1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2 // Window.cc for Blackbox - an X11 Window manager
3 // Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry <shaleh at debian.org>
4 // Copyright (c) 1997 - 2000, 2002 Brad Hughes <bhughes at trolltech.com>
6 // Permission is hereby granted, free of charge, to any person obtaining a
7 // copy of this software and associated documentation files (the "Software"),
8 // to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 // and/or sell copies of the Software, and to permit persons to whom the
11 // Software is furnished to do so, subject to the following conditions:
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 // DEALINGS IN THE SOFTWARE.
25 # include "../config.h"
26 #endif // HAVE_CONFIG_H
29 #include <X11/Xatom.h>
30 #include <X11/keysym.h>
34 #endif // HAVE_STRING_H
39 # endif // HAVE_STDIO_H
44 #endif // HAVE_STDLIB_H
48 #include "blackbox.hh"
49 #include "Clientmenu.hh"
52 #include "Iconmenu.hh"
58 #include "Windowmenu.hh"
59 #include "Workspace.hh"
66 * Initializes the class with default values/the window's set initial values.
68 BlackboxWindow::BlackboxWindow(Blackbox *b, Window w, BScreen *s) {
69 // fprintf(stderr, "BlackboxWindow size: %d bytes\n",
70 // sizeof(BlackboxWindow));
73 fprintf(stderr, "BlackboxWindow::BlackboxWindow(): creating 0x%lx\n", w);
77 set timer to zero... it is initialized properly later, so we check
78 if timer is zero in the destructor, and assume that the window is not
79 fully constructed if timer is zero...
85 xatom = blackbox->getXAtom();
87 if (! validateClient()) {
92 // fetch client size and placement
93 XWindowAttributes wattrib;
94 if (! XGetWindowAttributes(blackbox->getXDisplay(),
95 client.window, &wattrib) ||
96 ! wattrib.screen || wattrib.override_redirect) {
99 "BlackboxWindow::BlackboxWindow(): XGetWindowAttributes failed\n");
106 // set the eventmask early in the game so that we make sure we get
107 // all the events we are interested in
108 XSetWindowAttributes attrib_set;
109 attrib_set.event_mask = PropertyChangeMask | FocusChangeMask |
111 attrib_set.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask |
113 XChangeWindowAttributes(blackbox->getXDisplay(), client.window,
114 CWEventMask|CWDontPropagate, &attrib_set);
116 flags.moving = flags.resizing = flags.shaded = flags.visible =
117 flags.iconic = flags.focused = flags.stuck = flags.modal =
118 flags.send_focus_message = flags.shaped = flags.skip_taskbar =
119 flags.skip_pager = flags.fullscreen = False;
122 blackbox_attrib.workspace = window_number = BSENTINEL;
124 blackbox_attrib.flags = blackbox_attrib.attrib = blackbox_attrib.stack = 0l;
125 blackbox_attrib.decoration = DecorNormal;
126 // default premax taking up the middle 1/4 of the screen sounds fair to me
127 blackbox_attrib.premax_x = screen->getRect().x() +
128 screen->getRect().width() / 4;
129 blackbox_attrib.premax_y = screen->getRect().y() +
130 screen->getRect().height() / 4;
131 blackbox_attrib.premax_w = screen->getRect().width() / 2;
132 blackbox_attrib.premax_h = screen->getRect().height() / 2;
135 frame.window = frame.plate = frame.title = frame.handle = None;
136 frame.close_button = frame.iconify_button = frame.maximize_button =
137 frame.stick_button = None;
138 frame.right_grip = frame.left_grip = None;
140 frame.ulabel_pixel = frame.flabel_pixel = frame.utitle_pixel =
141 frame.ftitle_pixel = frame.uhandle_pixel = frame.fhandle_pixel =
142 frame.ubutton_pixel = frame.fbutton_pixel = frame.uborder_pixel =
143 frame.fborder_pixel = frame.ugrip_pixel = frame.fgrip_pixel = 0;
144 frame.utitle = frame.ftitle = frame.uhandle = frame.fhandle = None;
145 frame.ulabel = frame.flabel = frame.ubutton = frame.fbutton = None;
146 frame.ugrip = frame.fgrip = None;
148 functions = Func_Resize | Func_Move | Func_Iconify | Func_Maximize;
149 mwm_decorations = Decor_Titlebar | Decor_Handle | Decor_Border |
150 Decor_Iconify | Decor_Maximize;
152 client.normal_hint_flags = 0;
153 client.window_group = None;
154 client.transient_for = 0;
156 current_state = NormalState;
161 set the initial size and location of client window (relative to the
162 _root window_). This position is the reference point used with the
163 window's gravity to find the window's initial position.
165 client.rect.setRect(wattrib.x, wattrib.y, wattrib.width, wattrib.height);
166 client.old_bw = wattrib.border_width;
168 lastButtonPressTime = 0;
170 timer = new BTimer(blackbox, this);
171 timer->setTimeout(blackbox->getAutoRaiseDelay());
173 // get size, aspect, minimum/maximum size and other hints set by the
176 if (! getBlackboxHints())
183 frame.window = createToplevelWindow();
185 blackbox->saveWindowSearch(frame.window, this);
187 frame.plate = createChildWindow(frame.window, ExposureMask);
188 blackbox->saveWindowSearch(frame.plate, this);
190 // determine if this is a transient window
193 // determine the window's type, so we can decide its decorations and
194 // functionality, or if we should not manage it at all
195 if (getWindowType()) {
196 // adjust the window decorations/behavior based on the window type
197 switch (window_type) {
201 blackbox_attrib.workspace = 0; // we do need to belong to a workspace
202 flags.stuck = True; // we show up on all workspaces
204 // none of these windows are manipulated by the window manager
210 // these windows get less functionality
211 functions &= ~(Func_Maximize | Func_Resize | Func_Iconify);
215 // dialogs cannot be maximized
216 functions &= ~Func_Maximize;
220 // normal windows retain all of the possible decorations and
228 // further adjeust the window's decorations/behavior based on window sizes
229 if ((client.normal_hint_flags & PMinSize) &&
230 (client.normal_hint_flags & PMaxSize) &&
231 client.max_width <= client.min_width &&
232 client.max_height <= client.min_height) {
233 functions &= ~(Func_Resize | Func_Maximize);
240 if (decorations & Decor_Titlebar)
243 if (decorations & Decor_Handle)
246 // apply the size and gravity hint to the frame
250 bool place_window = True;
251 if (blackbox->isStartup() || isTransient() ||
252 client.normal_hint_flags & (PPosition|USPosition)) {
253 applyGravity(frame.rect);
255 if (blackbox->isStartup() || client.rect.intersects(screen->getRect()))
256 place_window = False;
259 // add the window's strut. note this is done *after* placing the window.
260 screen->addStrut(&client.strut);
264 the server needs to be grabbed here to prevent client's from sending
265 events while we are in the process of configuring their window.
266 We hold the grab until after we are done moving the window around.
269 XGrabServer(blackbox->getXDisplay());
271 associateClientWindow();
273 blackbox->saveWindowSearch(client.window, this);
275 if (blackbox_attrib.workspace >= screen->getWorkspaceCount())
276 screen->getCurrentWorkspace()->addWindow(this, place_window);
278 screen->getWorkspace(blackbox_attrib.workspace)->
279 addWindow(this, place_window);
281 if (! place_window) {
282 // don't need to call configure if we are letting the workspace
284 configure(frame.rect.x(), frame.rect.y(),
285 frame.rect.width(), frame.rect.height());
291 XUngrabServer(blackbox->getXDisplay());
294 if (blackbox->hasShapeExtensions() && flags.shaped)
298 // now that we know where to put the window and what it should look like
299 // we apply the decorations
304 XMapSubwindows(blackbox->getXDisplay(), frame.window);
306 // this ensures the title, buttons, and other decor are properly displayed
309 // preserve the window's initial state on first map, and its current state
311 unsigned long initial_state = current_state;
313 current_state = initial_state;
315 // get sticky state from our parent window if we've got one
316 if (isTransient() && client.transient_for != (BlackboxWindow *) ~0ul &&
317 client.transient_for->isStuck() != flags.stuck)
321 flags.shaded = False;
322 initial_state = current_state;
326 At this point in the life of a window, current_state should only be set
327 to IconicState if the window was an *icon*, not if it was shaded.
329 if (initial_state != IconicState)
330 current_state = NormalState;
338 if (flags.maximized && (functions & Func_Maximize))
341 // create this last so it only needs to be configured once
342 windowmenu = new Windowmenu(this);
346 BlackboxWindow::~BlackboxWindow(void) {
348 fprintf(stderr, "BlackboxWindow::~BlackboxWindow: destroying 0x%lx\n",
352 if (! timer) // window not managed...
358 screen->removeStrut(&client.strut);
359 screen->updateAvailableArea();
361 // We don't need to worry about resizing because resizing always grabs the X
362 // server. This should only ever happen if using opaque moving.
370 if (client.window_group) {
371 BWindowGroup *group = blackbox->searchGroup(client.window_group);
372 if (group) group->removeWindow(this);
375 // remove ourselves from our transient_for
377 if (client.transient_for != (BlackboxWindow *) ~0ul)
378 client.transient_for->client.transientList.remove(this);
379 client.transient_for = (BlackboxWindow*) 0;
382 if (client.transientList.size() > 0) {
383 // reset transient_for for all transients
384 BlackboxWindowList::iterator it, end = client.transientList.end();
385 for (it = client.transientList.begin(); it != end; ++it)
386 (*it)->client.transient_for = (BlackboxWindow*) 0;
396 blackbox->removeWindowSearch(frame.plate);
397 XDestroyWindow(blackbox->getXDisplay(), frame.plate);
401 blackbox->removeWindowSearch(frame.window);
402 XDestroyWindow(blackbox->getXDisplay(), frame.window);
405 blackbox->removeWindowSearch(client.window);
409 void BlackboxWindow::enableDecor(bool enable) {
410 blackbox_attrib.flags |= AttribDecoration;
411 blackbox_attrib.decoration = enable ? DecorNormal : DecorNone;
414 // we can not be shaded if we lack a titlebar
415 if (! (decorations & Decor_Titlebar) && flags.shaded)
418 if (flags.visible && frame.window) {
419 XMapSubwindows(blackbox->getXDisplay(), frame.window);
420 XMapWindow(blackbox->getXDisplay(), frame.window);
424 setState(current_state);
428 void BlackboxWindow::setupDecor() {
429 if (blackbox_attrib.decoration != DecorNone) {
430 // start with everything on
431 decorations = Decor_Close |
432 (mwm_decorations & Decor_Titlebar ? Decor_Titlebar : 0) |
433 (mwm_decorations & Decor_Border ? Decor_Border : 0) |
434 (mwm_decorations & Decor_Handle ? Decor_Handle : 0) |
435 (mwm_decorations & Decor_Iconify ? Decor_Iconify : 0) |
436 (mwm_decorations & Decor_Maximize ? Decor_Maximize : 0);
438 if (! (functions & Func_Close)) decorations &= ~Decor_Close;
439 if (! (functions & Func_Maximize)) decorations &= ~Decor_Maximize;
440 if (! (functions & Func_Iconify)) decorations &= ~Decor_Iconify;
441 if (! (functions & Func_Resize)) decorations &= ~Decor_Handle;
443 switch (window_type) {
448 // none of these windows are decorated by the window manager at all
454 decorations &= ~(Decor_Border);
458 decorations &= ~Decor_Handle;
470 * Creates a new top level window, with a given location, size, and border
472 * Returns: the newly created window
474 Window BlackboxWindow::createToplevelWindow(void) {
475 XSetWindowAttributes attrib_create;
476 unsigned long create_mask = CWBackPixmap | CWBorderPixel | CWColormap |
477 CWOverrideRedirect | CWEventMask;
479 attrib_create.background_pixmap = None;
480 attrib_create.colormap = screen->getColormap();
481 attrib_create.override_redirect = True;
482 attrib_create.event_mask = EnterWindowMask | LeaveWindowMask |
485 We catch button presses because other wise they get passed down to the
486 root window, which will then cause root menus to show when you click the
490 return XCreateWindow(blackbox->getXDisplay(), screen->getRootWindow(),
491 0, 0, 1, 1, frame.border_w, screen->getDepth(),
492 InputOutput, screen->getVisual(), create_mask,
498 * Creates a child window, and optionally associates a given cursor with
501 Window BlackboxWindow::createChildWindow(Window parent,
502 unsigned long event_mask,
504 XSetWindowAttributes attrib_create;
505 unsigned long create_mask = CWBackPixmap | CWBorderPixel |
508 attrib_create.background_pixmap = None;
509 attrib_create.event_mask = event_mask;
512 create_mask |= CWCursor;
513 attrib_create.cursor = cursor;
516 return XCreateWindow(blackbox->getXDisplay(), parent, 0, 0, 1, 1, 0,
517 screen->getDepth(), InputOutput, screen->getVisual(),
518 create_mask, &attrib_create);
522 void BlackboxWindow::associateClientWindow(void) {
523 XSetWindowBorderWidth(blackbox->getXDisplay(), client.window, 0);
527 XChangeSaveSet(blackbox->getXDisplay(), client.window, SetModeInsert);
529 XSelectInput(blackbox->getXDisplay(), frame.plate, SubstructureRedirectMask);
532 note we used to grab around this call to XReparentWindow however the
533 server is now grabbed before this method is called
535 unsigned long event_mask = PropertyChangeMask | FocusChangeMask |
537 XSelectInput(blackbox->getXDisplay(), client.window,
538 event_mask & ~StructureNotifyMask);
539 XReparentWindow(blackbox->getXDisplay(), client.window, frame.plate, 0, 0);
540 XSelectInput(blackbox->getXDisplay(), client.window, event_mask);
542 XRaiseWindow(blackbox->getXDisplay(), frame.plate);
543 XMapSubwindows(blackbox->getXDisplay(), frame.plate);
546 if (blackbox->hasShapeExtensions()) {
547 XShapeSelectInput(blackbox->getXDisplay(), client.window,
554 XShapeQueryExtents(blackbox->getXDisplay(), client.window, &shaped,
555 &foo, &foo, &ufoo, &ufoo, &foo, &foo, &foo,
557 flags.shaped = shaped;
563 void BlackboxWindow::decorate(void) {
566 texture = &(screen->getWindowStyle()->b_focus);
567 frame.fbutton = texture->render(frame.button_w, frame.button_w,
570 frame.fbutton_pixel = texture->color().pixel();
572 texture = &(screen->getWindowStyle()->b_unfocus);
573 frame.ubutton = texture->render(frame.button_w, frame.button_w,
576 frame.ubutton_pixel = texture->color().pixel();
578 unsigned char needsPressed = 0;
580 texture = &(screen->getWindowStyle()->b_pressed_focus);
582 if (texture->texture() != BTexture::NoTexture) {
583 frame.pfbutton = texture->render(frame.button_w, frame.button_w,
585 if (! frame.pfbutton)
586 frame.pfbutton_pixel = texture->color().pixel();
591 texture = &(screen->getWindowStyle()->b_pressed_unfocus);
593 if (texture->texture() != BTexture::NoTexture) {
594 frame.pubutton = texture->render(frame.button_w, frame.button_w,
596 if (! frame.pubutton)
597 frame.pubutton = texture->color().pixel();
602 // if we either pressed unfocused, or pressed focused were undefined,
603 // make them inherit from the old resource. It's a hack for sure, but
604 // it allows for some backwards and forwards compatibility.
606 texture = &(screen->getWindowStyle()->b_pressed);
608 if (needsPressed & 0x1) {
609 frame.pfbutton = texture->render(frame.button_w, frame.button_w,
611 if (! frame.pfbutton)
612 frame.pfbutton_pixel = texture->color().pixel();
614 if (needsPressed & 0x2) {
615 frame.pubutton = texture->render(frame.button_w, frame.button_w,
617 if (! frame.pubutton)
618 frame.pubutton = texture->color().pixel();
623 if (decorations & Decor_Titlebar) {
624 texture = &(screen->getWindowStyle()->t_focus);
625 frame.ftitle = texture->render(frame.inside_w, frame.title_h,
628 frame.ftitle_pixel = texture->color().pixel();
630 texture = &(screen->getWindowStyle()->t_unfocus);
631 frame.utitle = texture->render(frame.inside_w, frame.title_h,
634 frame.utitle_pixel = texture->color().pixel();
636 XSetWindowBorder(blackbox->getXDisplay(), frame.title,
637 screen->getBorderColor()->pixel());
642 if (decorations & Decor_Border) {
643 frame.fborder_pixel = screen->getWindowStyle()->f_focus.color().pixel();
644 frame.uborder_pixel = screen->getWindowStyle()->f_unfocus.color().pixel();
647 if (decorations & Decor_Handle) {
648 texture = &(screen->getWindowStyle()->h_focus);
649 frame.fhandle = texture->render(frame.inside_w, frame.handle_h,
652 frame.fhandle_pixel = texture->color().pixel();
654 texture = &(screen->getWindowStyle()->h_unfocus);
655 frame.uhandle = texture->render(frame.inside_w, frame.handle_h,
658 frame.uhandle_pixel = texture->color().pixel();
660 texture = &(screen->getWindowStyle()->g_focus);
661 frame.fgrip = texture->render(frame.grip_w, frame.handle_h, frame.fgrip);
663 frame.fgrip_pixel = texture->color().pixel();
665 texture = &(screen->getWindowStyle()->g_unfocus);
666 frame.ugrip = texture->render(frame.grip_w, frame.handle_h, frame.ugrip);
668 frame.ugrip_pixel = texture->color().pixel();
670 XSetWindowBorder(blackbox->getXDisplay(), frame.handle,
671 screen->getBorderColor()->pixel());
672 XSetWindowBorder(blackbox->getXDisplay(), frame.left_grip,
673 screen->getBorderColor()->pixel());
674 XSetWindowBorder(blackbox->getXDisplay(), frame.right_grip,
675 screen->getBorderColor()->pixel());
678 XSetWindowBorder(blackbox->getXDisplay(), frame.window,
679 screen->getBorderColor()->pixel());
683 void BlackboxWindow::decorateLabel(void) {
686 texture = &(screen->getWindowStyle()->l_focus);
687 frame.flabel = texture->render(frame.label_w, frame.label_h, frame.flabel);
689 frame.flabel_pixel = texture->color().pixel();
691 texture = &(screen->getWindowStyle()->l_unfocus);
692 frame.ulabel = texture->render(frame.label_w, frame.label_h, frame.ulabel);
694 frame.ulabel_pixel = texture->color().pixel();
698 void BlackboxWindow::createHandle(void) {
699 frame.handle = createChildWindow(frame.window,
700 ButtonPressMask | ButtonReleaseMask |
701 ButtonMotionMask | ExposureMask);
702 blackbox->saveWindowSearch(frame.handle, this);
705 createChildWindow(frame.handle,
706 ButtonPressMask | ButtonReleaseMask |
707 ButtonMotionMask | ExposureMask,
708 blackbox->getLowerLeftAngleCursor());
709 blackbox->saveWindowSearch(frame.left_grip, this);
712 createChildWindow(frame.handle,
713 ButtonPressMask | ButtonReleaseMask |
714 ButtonMotionMask | ExposureMask,
715 blackbox->getLowerRightAngleCursor());
716 blackbox->saveWindowSearch(frame.right_grip, this);
720 void BlackboxWindow::destroyHandle(void) {
722 screen->getImageControl()->removeImage(frame.fhandle);
725 screen->getImageControl()->removeImage(frame.uhandle);
728 screen->getImageControl()->removeImage(frame.fgrip);
731 screen->getImageControl()->removeImage(frame.ugrip);
733 blackbox->removeWindowSearch(frame.left_grip);
734 blackbox->removeWindowSearch(frame.right_grip);
736 XDestroyWindow(blackbox->getXDisplay(), frame.left_grip);
737 XDestroyWindow(blackbox->getXDisplay(), frame.right_grip);
738 frame.left_grip = frame.right_grip = None;
740 blackbox->removeWindowSearch(frame.handle);
741 XDestroyWindow(blackbox->getXDisplay(), frame.handle);
746 void BlackboxWindow::createTitlebar(void) {
747 frame.title = createChildWindow(frame.window,
748 ButtonPressMask | ButtonReleaseMask |
749 ButtonMotionMask | ExposureMask);
750 frame.label = createChildWindow(frame.title,
751 ButtonPressMask | ButtonReleaseMask |
752 ButtonMotionMask | ExposureMask);
753 blackbox->saveWindowSearch(frame.title, this);
754 blackbox->saveWindowSearch(frame.label, this);
756 if (decorations & Decor_Iconify) createIconifyButton();
757 if (decorations & Decor_Maximize) createMaximizeButton();
758 if (decorations & Decor_Close) createCloseButton();
762 void BlackboxWindow::destroyTitlebar(void) {
763 if (frame.close_button)
764 destroyCloseButton();
766 if (frame.iconify_button)
767 destroyIconifyButton();
769 if (frame.maximize_button)
770 destroyMaximizeButton();
772 if (frame.stick_button)
773 destroyStickyButton();
776 screen->getImageControl()->removeImage(frame.ftitle);
779 screen->getImageControl()->removeImage(frame.utitle);
782 screen->getImageControl()->removeImage(frame.flabel);
785 screen->getImageControl()->removeImage(frame.ulabel);
788 screen->getImageControl()->removeImage(frame.fbutton);
791 screen->getImageControl()->removeImage(frame.ubutton);
793 blackbox->removeWindowSearch(frame.title);
794 blackbox->removeWindowSearch(frame.label);
796 XDestroyWindow(blackbox->getXDisplay(), frame.label);
797 XDestroyWindow(blackbox->getXDisplay(), frame.title);
798 frame.title = frame.label = None;
802 void BlackboxWindow::createCloseButton(void) {
803 if (frame.title != None) {
804 frame.close_button = createChildWindow(frame.title,
807 ButtonMotionMask | ExposureMask);
808 blackbox->saveWindowSearch(frame.close_button, this);
813 void BlackboxWindow::destroyCloseButton(void) {
814 blackbox->removeWindowSearch(frame.close_button);
815 XDestroyWindow(blackbox->getXDisplay(), frame.close_button);
816 frame.close_button = None;
820 void BlackboxWindow::createIconifyButton(void) {
821 if (frame.title != None) {
822 frame.iconify_button = createChildWindow(frame.title,
825 ButtonMotionMask | ExposureMask);
826 blackbox->saveWindowSearch(frame.iconify_button, this);
831 void BlackboxWindow::destroyIconifyButton(void) {
832 blackbox->removeWindowSearch(frame.iconify_button);
833 XDestroyWindow(blackbox->getXDisplay(), frame.iconify_button);
834 frame.iconify_button = None;
838 void BlackboxWindow::createMaximizeButton(void) {
839 if (frame.title != None) {
840 frame.maximize_button = createChildWindow(frame.title,
843 ButtonMotionMask | ExposureMask);
844 blackbox->saveWindowSearch(frame.maximize_button, this);
849 void BlackboxWindow::destroyMaximizeButton(void) {
850 blackbox->removeWindowSearch(frame.maximize_button);
851 XDestroyWindow(blackbox->getXDisplay(), frame.maximize_button);
852 frame.maximize_button = None;
855 void BlackboxWindow::createStickyButton(void) {
856 if (frame.title != None) {
857 frame.stick_button = createChildWindow(frame.title,
860 ButtonMotionMask | ExposureMask);
861 blackbox->saveWindowSearch(frame.stick_button, this);
865 void BlackboxWindow::destroyStickyButton(void) {
866 blackbox->removeWindowSearch(frame.stick_button);
867 XDestroyWindow(blackbox->getXDisplay(), frame.stick_button);
868 frame.stick_button = None;
871 void BlackboxWindow::positionButtons(bool redecorate_label) {
872 string layout = blackbox->getTitlebarLayout();
875 bool hasclose, hasiconify, hasmaximize, haslabel, hasstick;
876 hasclose = hasiconify = hasmaximize = haslabel = hasstick = false;
878 string::const_iterator it, end;
879 for (it = layout.begin(), end = layout.end(); it != end; ++it) {
882 if (! hasclose && (decorations & Decor_Close)) {
888 if (! hasiconify && (decorations & Decor_Iconify)) {
900 if (! hasmaximize && (decorations & Decor_Maximize)) {
914 if (! hasclose && frame.close_button)
915 destroyCloseButton();
916 if (! hasiconify && frame.iconify_button)
917 destroyIconifyButton();
918 if (! hasmaximize && frame.maximize_button)
919 destroyMaximizeButton();
920 if (! hasstick && frame.stick_button)
921 destroyStickyButton();
923 parsed += 'L'; // require that the label be in the layout
925 const unsigned int bsep = frame.bevel_w + 1; // separation between elements
926 const unsigned int by = frame.bevel_w + 1;
927 const unsigned int ty = frame.bevel_w;
929 frame.label_w = frame.inside_w - bsep * 2 -
930 (frame.button_w + bsep) * (parsed.size() - 1);
932 unsigned int x = bsep;
933 for (it = parsed.begin(), end = parsed.end(); it != end; ++it) {
936 if (! frame.close_button) createCloseButton();
937 XMoveResizeWindow(blackbox->getXDisplay(), frame.close_button, x, by,
938 frame.button_w, frame.button_w);
939 x += frame.button_w + bsep;
942 if (! frame.iconify_button) createIconifyButton();
943 XMoveResizeWindow(blackbox->getXDisplay(), frame.iconify_button, x, by,
944 frame.button_w, frame.button_w);
945 x += frame.button_w + bsep;
948 if (! frame.stick_button) createStickyButton();
949 XMoveResizeWindow(blackbox->getXDisplay(), frame.stick_button, x, by,
950 frame.button_w, frame.button_w);
951 x += frame.button_w + bsep;
954 if (! frame.maximize_button) createMaximizeButton();
955 XMoveResizeWindow(blackbox->getXDisplay(), frame.maximize_button, x, by,
956 frame.button_w, frame.button_w);
957 x += frame.button_w + bsep;
960 XMoveResizeWindow(blackbox->getXDisplay(), frame.label, x, ty,
961 frame.label_w, frame.label_h);
962 x += frame.label_w + bsep;
967 if (redecorate_label) decorateLabel();
973 void BlackboxWindow::reconfigure(void) {
974 restoreGravity(client.rect);
976 applyGravity(frame.rect);
985 windowmenu->move(windowmenu->getX(), frame.rect.y() + frame.title_h);
986 windowmenu->reconfigure();
991 void BlackboxWindow::grabButtons(void) {
992 mod_mask = blackbox->getMouseModMask();
994 if (! screen->isSloppyFocus() || screen->doClickRaise())
995 // grab button 1 for changing focus/raising
996 blackbox->grabButton(Button1, 0, frame.plate, True, ButtonPressMask,
997 GrabModeSync, GrabModeSync, frame.plate, None,
998 screen->allowScrollLock());
1000 if (functions & Func_Move)
1001 blackbox->grabButton(Button1, mod_mask, frame.window, True,
1002 ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
1003 GrabModeAsync, frame.window, None,
1004 screen->allowScrollLock());
1005 if (functions & Func_Resize)
1006 blackbox->grabButton(Button3, mod_mask, frame.window, True,
1007 ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
1008 GrabModeAsync, frame.window, None,
1009 screen->allowScrollLock());
1010 // alt+middle lowers the window
1011 blackbox->grabButton(Button2, mod_mask, frame.window, True,
1012 ButtonReleaseMask, GrabModeAsync, GrabModeAsync,
1013 frame.window, None, screen->allowScrollLock());
1017 void BlackboxWindow::ungrabButtons(void) {
1018 blackbox->ungrabButton(Button1, 0, frame.plate);
1019 blackbox->ungrabButton(Button1, mod_mask, frame.window);
1020 blackbox->ungrabButton(Button2, mod_mask, frame.window);
1021 blackbox->ungrabButton(Button3, mod_mask, frame.window);
1025 void BlackboxWindow::positionWindows(void) {
1026 XMoveResizeWindow(blackbox->getXDisplay(), frame.window,
1027 frame.rect.x(), frame.rect.y(), frame.inside_w,
1028 (flags.shaded) ? frame.title_h : frame.inside_h);
1029 XSetWindowBorderWidth(blackbox->getXDisplay(), frame.window,
1031 XSetWindowBorderWidth(blackbox->getXDisplay(), frame.plate,
1032 frame.mwm_border_w);
1033 XMoveResizeWindow(blackbox->getXDisplay(), frame.plate,
1034 frame.margin.left - frame.mwm_border_w - frame.border_w,
1035 frame.margin.top - frame.mwm_border_w - frame.border_w,
1036 client.rect.width(), client.rect.height());
1037 XMoveResizeWindow(blackbox->getXDisplay(), client.window,
1038 0, 0, client.rect.width(), client.rect.height());
1039 // ensure client.rect contains the real location
1040 client.rect.setPos(frame.rect.left() + frame.margin.left,
1041 frame.rect.top() + frame.margin.top);
1043 if (decorations & Decor_Titlebar) {
1044 if (frame.title == None) createTitlebar();
1046 XSetWindowBorderWidth(blackbox->getXDisplay(), frame.title,
1048 XMoveResizeWindow(blackbox->getXDisplay(), frame.title, -frame.border_w,
1049 -frame.border_w, frame.inside_w, frame.title_h);
1052 XMapSubwindows(blackbox->getXDisplay(), frame.title);
1053 XMapWindow(blackbox->getXDisplay(), frame.title);
1054 } else if (frame.title) {
1057 if (decorations & Decor_Handle) {
1058 if (frame.handle == None) createHandle();
1059 XSetWindowBorderWidth(blackbox->getXDisplay(), frame.handle,
1061 XSetWindowBorderWidth(blackbox->getXDisplay(), frame.left_grip,
1063 XSetWindowBorderWidth(blackbox->getXDisplay(), frame.right_grip,
1066 // use client.rect here so the value is correct even if shaded
1067 XMoveResizeWindow(blackbox->getXDisplay(), frame.handle,
1069 client.rect.height() + frame.margin.top +
1070 frame.mwm_border_w - frame.border_w,
1071 frame.inside_w, frame.handle_h);
1072 XMoveResizeWindow(blackbox->getXDisplay(), frame.left_grip,
1073 -frame.border_w, -frame.border_w,
1074 frame.grip_w, frame.handle_h);
1075 XMoveResizeWindow(blackbox->getXDisplay(), frame.right_grip,
1076 frame.inside_w - frame.grip_w - frame.border_w,
1077 -frame.border_w, frame.grip_w, frame.handle_h);
1079 XMapSubwindows(blackbox->getXDisplay(), frame.handle);
1080 XMapWindow(blackbox->getXDisplay(), frame.handle);
1081 } else if (frame.handle) {
1084 XSync(blackbox->getXDisplay(), False);
1088 void BlackboxWindow::updateStrut(void) {
1089 unsigned long num = 4;
1090 unsigned long *data;
1091 if (! xatom->getValue(client.window, XAtom::net_wm_strut, XAtom::cardinal,
1096 client.strut.left = data[0];
1097 client.strut.right = data[1];
1098 client.strut.top = data[2];
1099 client.strut.bottom = data[3];
1101 screen->updateAvailableArea();
1108 bool BlackboxWindow::getWindowType(void) {
1109 window_type = (WindowType) -1;
1112 unsigned long num = (unsigned) -1;
1113 if (xatom->getValue(client.window, XAtom::net_wm_window_type, XAtom::atom,
1115 for (unsigned long i = 0; i < num; ++i) {
1116 if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_desktop))
1117 window_type = Type_Desktop;
1118 else if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_dock))
1119 window_type = Type_Dock;
1120 else if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_toolbar))
1121 window_type = Type_Toolbar;
1122 else if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_menu))
1123 window_type = Type_Menu;
1124 else if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_utility))
1125 window_type = Type_Utility;
1126 else if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_splash))
1127 window_type = Type_Splash;
1128 else if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_dialog))
1129 window_type = Type_Dialog;
1130 else if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_normal))
1131 window_type = Type_Normal;
1133 xatom->getAtom(XAtom::kde_net_wm_window_type_override))
1134 mwm_decorations = 0; // prevent this window from getting any decor
1139 if (window_type == (WindowType) -1) {
1141 * the window type hint was not set, which means we either classify ourself
1142 * as a normal window or a dialog, depending on if we are a transient.
1145 window_type = Type_Dialog;
1147 window_type = Type_Normal;
1156 void BlackboxWindow::getWMName(void) {
1157 if (xatom->getValue(client.window, XAtom::net_wm_name,
1158 XAtom::utf8, client.title) &&
1159 !client.title.empty()) {
1160 xatom->eraseValue(client.window, XAtom::net_wm_visible_name);
1163 //fall through to using WM_NAME
1164 if (xatom->getValue(client.window, XAtom::wm_name, XAtom::ansi, client.title)
1165 && !client.title.empty()) {
1166 xatom->eraseValue(client.window, XAtom::net_wm_visible_name);
1169 // fall back to an internal default
1170 client.title = i18n(WindowSet, WindowUnnamed, "Unnamed");
1171 xatom->setValue(client.window, XAtom::net_wm_visible_name, XAtom::utf8,
1174 #ifdef DEBUG_WITH_ID
1175 // the 16 is the 8 chars of the debug text plus the number
1176 char *tmp = new char[client.title.length() + 16];
1177 sprintf(tmp, "%s; id: 0x%lx", client.title.c_str(), client.window);
1184 void BlackboxWindow::getWMIconName(void) {
1185 if (xatom->getValue(client.window, XAtom::net_wm_icon_name,
1186 XAtom::utf8, client.icon_title) &&
1187 !client.icon_title.empty()) {
1188 xatom->eraseValue(client.window, XAtom::net_wm_visible_icon_name);
1191 //fall through to using WM_ICON_NAME
1192 if (xatom->getValue(client.window, XAtom::wm_icon_name, XAtom::ansi,
1193 client.icon_title) &&
1194 !client.icon_title.empty()) {
1195 xatom->eraseValue(client.window, XAtom::net_wm_visible_icon_name);
1198 // fall back to using the main name
1199 client.icon_title = client.title;
1200 xatom->setValue(client.window, XAtom::net_wm_visible_icon_name, XAtom::utf8,
1206 * Retrieve which WM Protocols are supported by the client window.
1207 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
1208 * window's decorations and allow the close behavior.
1209 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
1212 void BlackboxWindow::getWMProtocols(void) {
1216 if (XGetWMProtocols(blackbox->getXDisplay(), client.window,
1217 &proto, &num_return)) {
1218 for (int i = 0; i < num_return; ++i) {
1219 if (proto[i] == xatom->getAtom(XAtom::wm_delete_window)) {
1220 decorations |= Decor_Close;
1221 functions |= Func_Close;
1222 } else if (proto[i] == xatom->getAtom(XAtom::wm_take_focus))
1223 flags.send_focus_message = True;
1224 else if (proto[i] == xatom->getAtom(XAtom::blackbox_structure_messages))
1225 screen->addNetizen(new Netizen(screen, client.window));
1234 * Gets the value of the WM_HINTS property.
1235 * If the property is not set, then use a set of default values.
1237 void BlackboxWindow::getWMHints(void) {
1238 focus_mode = F_Passive;
1240 // remove from current window group
1241 if (client.window_group) {
1242 BWindowGroup *group = blackbox->searchGroup(client.window_group);
1243 if (group) group->removeWindow(this);
1245 client.window_group = None;
1247 XWMHints *wmhint = XGetWMHints(blackbox->getXDisplay(), client.window);
1252 if (wmhint->flags & InputHint) {
1253 if (wmhint->input == True) {
1254 if (flags.send_focus_message)
1255 focus_mode = F_LocallyActive;
1257 if (flags.send_focus_message)
1258 focus_mode = F_GloballyActive;
1260 focus_mode = F_NoInput;
1264 if (wmhint->flags & StateHint)
1265 current_state = wmhint->initial_state;
1267 if (wmhint->flags & WindowGroupHint) {
1268 client.window_group = wmhint->window_group;
1270 // add window to the appropriate group
1271 BWindowGroup *group = blackbox->searchGroup(client.window_group);
1272 if (! group) { // no group found, create it!
1273 new BWindowGroup(blackbox, client.window_group);
1274 group = blackbox->searchGroup(client.window_group);
1277 group->addWindow(this);
1285 * Gets the value of the WM_NORMAL_HINTS property.
1286 * If the property is not set, then use a set of default values.
1288 void BlackboxWindow::getWMNormalHints(void) {
1290 XSizeHints sizehint;
1292 client.min_width = client.min_height =
1293 client.width_inc = client.height_inc = 1;
1294 client.base_width = client.base_height = 0;
1295 client.win_gravity = NorthWestGravity;
1297 client.min_aspect_x = client.min_aspect_y =
1298 client.max_aspect_x = client.max_aspect_y = 1;
1301 // don't limit the size of a window, the default max width is the biggest
1303 client.max_width = (unsigned) -1;
1304 client.max_height = (unsigned) -1;
1307 if (! XGetWMNormalHints(blackbox->getXDisplay(), client.window,
1308 &sizehint, &icccm_mask))
1311 client.normal_hint_flags = sizehint.flags;
1313 if (sizehint.flags & PMinSize) {
1314 if (sizehint.min_width >= 0)
1315 client.min_width = sizehint.min_width;
1316 if (sizehint.min_height >= 0)
1317 client.min_height = sizehint.min_height;
1320 if (sizehint.flags & PMaxSize) {
1321 if (sizehint.max_width > static_cast<signed>(client.min_width))
1322 client.max_width = sizehint.max_width;
1324 client.max_width = client.min_width;
1326 if (sizehint.max_height > static_cast<signed>(client.min_height))
1327 client.max_height = sizehint.max_height;
1329 client.max_height = client.min_height;
1332 if (sizehint.flags & PResizeInc) {
1333 client.width_inc = sizehint.width_inc;
1334 client.height_inc = sizehint.height_inc;
1337 #if 0 // we do not support this at the moment
1338 if (sizehint.flags & PAspect) {
1339 client.min_aspect_x = sizehint.min_aspect.x;
1340 client.min_aspect_y = sizehint.min_aspect.y;
1341 client.max_aspect_x = sizehint.max_aspect.x;
1342 client.max_aspect_y = sizehint.max_aspect.y;
1346 if (sizehint.flags & PBaseSize) {
1347 client.base_width = sizehint.base_width;
1348 client.base_height = sizehint.base_height;
1351 if (sizehint.flags & PWinGravity)
1352 client.win_gravity = sizehint.win_gravity;
1357 * Gets the NETWM hints for the class' contained window.
1359 void BlackboxWindow::getNetWMHints(void) {
1360 unsigned long workspace;
1362 if (xatom->getValue(client.window, XAtom::net_wm_desktop, XAtom::cardinal,
1364 if (workspace == 0xffffffff)
1367 blackbox_attrib.workspace = workspace;
1370 unsigned long *state;
1371 unsigned long num = (unsigned) -1;
1372 if (xatom->getValue(client.window, XAtom::net_wm_state, XAtom::atom,
1376 for (unsigned long i = 0; i < num; ++i) {
1377 if (state[i] == xatom->getAtom(XAtom::net_wm_state_modal))
1379 else if (state[i] == xatom->getAtom(XAtom::net_wm_state_shaded))
1380 flags.shaded = True;
1381 else if (state[i] == xatom->getAtom(XAtom::net_wm_state_skip_taskbar))
1382 flags.skip_taskbar = True;
1383 else if (state[i] == xatom->getAtom(XAtom::net_wm_state_skip_pager))
1384 flags.skip_pager = True;
1385 else if (state[i] == xatom->getAtom(XAtom::net_wm_state_fullscreen))
1386 flags.fullscreen = True;
1387 else if (state[i] == xatom->getAtom(XAtom::net_wm_state_hidden))
1388 setState(IconicState);
1389 else if (state[i] == xatom->getAtom(XAtom::net_wm_state_maximized_vert))
1391 else if (state[i] == xatom->getAtom(XAtom::net_wm_state_maximized_horz))
1395 flags.maximized = 1;
1397 flags.maximized = 2;
1399 flags.maximized = 3;
1407 * Gets the MWM hints for the class' contained window.
1408 * This is used while initializing the window to its first state, and not
1410 * Returns: true if the MWM hints are successfully retreived and applied;
1411 * false if they are not.
1413 void BlackboxWindow::getMWMHints(void) {
1417 num = PropMwmHintsElements;
1418 if (! xatom->getValue(client.window, XAtom::motif_wm_hints,
1419 XAtom::motif_wm_hints, num,
1420 (unsigned long **)&mwm_hint))
1422 if (num < PropMwmHintsElements) {
1427 if (mwm_hint->flags & MwmHintsDecorations) {
1428 if (mwm_hint->decorations & MwmDecorAll) {
1429 mwm_decorations = Decor_Titlebar | Decor_Handle | Decor_Border |
1430 Decor_Iconify | Decor_Maximize;
1432 mwm_decorations = 0;
1434 if (mwm_hint->decorations & MwmDecorBorder)
1435 mwm_decorations |= Decor_Border;
1436 if (mwm_hint->decorations & MwmDecorHandle)
1437 mwm_decorations |= Decor_Handle;
1438 if (mwm_hint->decorations & MwmDecorTitle)
1439 mwm_decorations |= Decor_Titlebar;
1440 if (mwm_hint->decorations & MwmDecorIconify)
1441 mwm_decorations |= Decor_Iconify;
1442 if (mwm_hint->decorations & MwmDecorMaximize)
1443 mwm_decorations |= Decor_Maximize;
1447 if (mwm_hint->flags & MwmHintsFunctions) {
1448 if (mwm_hint->functions & MwmFuncAll) {
1449 functions = Func_Resize | Func_Move | Func_Iconify | Func_Maximize |
1454 if (mwm_hint->functions & MwmFuncResize)
1455 functions |= Func_Resize;
1456 if (mwm_hint->functions & MwmFuncMove)
1457 functions |= Func_Move;
1458 if (mwm_hint->functions & MwmFuncIconify)
1459 functions |= Func_Iconify;
1460 if (mwm_hint->functions & MwmFuncMaximize)
1461 functions |= Func_Maximize;
1462 if (mwm_hint->functions & MwmFuncClose)
1463 functions |= Func_Close;
1471 * Gets the blackbox hints from the class' contained window.
1472 * This is used while initializing the window to its first state, and not
1474 * Returns: true if the hints are successfully retreived and applied; false if
1477 bool BlackboxWindow::getBlackboxHints(void) {
1479 BlackboxHints *blackbox_hint;
1481 num = PropBlackboxHintsElements;
1482 if (! xatom->getValue(client.window, XAtom::blackbox_hints,
1483 XAtom::blackbox_hints, num,
1484 (unsigned long **)&blackbox_hint))
1486 if (num < PropBlackboxHintsElements) {
1487 delete [] blackbox_hint;
1491 if (blackbox_hint->flags & AttribShaded)
1492 flags.shaded = (blackbox_hint->attrib & AttribShaded);
1494 if ((blackbox_hint->flags & AttribMaxHoriz) &&
1495 (blackbox_hint->flags & AttribMaxVert))
1496 flags.maximized = (blackbox_hint->attrib &
1497 (AttribMaxHoriz | AttribMaxVert)) ? 1 : 0;
1498 else if (blackbox_hint->flags & AttribMaxVert)
1499 flags.maximized = (blackbox_hint->attrib & AttribMaxVert) ? 2 : 0;
1500 else if (blackbox_hint->flags & AttribMaxHoriz)
1501 flags.maximized = (blackbox_hint->attrib & AttribMaxHoriz) ? 3 : 0;
1503 if (blackbox_hint->flags & AttribOmnipresent)
1504 flags.stuck = (blackbox_hint->attrib & AttribOmnipresent);
1506 if (blackbox_hint->flags & AttribWorkspace)
1507 blackbox_attrib.workspace = blackbox_hint->workspace;
1509 // if (blackbox_hint->flags & AttribStack)
1510 // don't yet have always on top/bottom for blackbox yet... working
1513 if (blackbox_hint->flags & AttribDecoration) {
1514 switch (blackbox_hint->decoration) {
1516 blackbox_attrib.decoration = DecorNone;
1523 // blackbox_attrib.decoration defaults to DecorNormal
1528 delete [] blackbox_hint;
1534 void BlackboxWindow::getTransientInfo(void) {
1535 if (client.transient_for &&
1536 client.transient_for != (BlackboxWindow *) ~0ul) {
1537 // reset transient_for in preparation of looking for a new owner
1538 client.transient_for->client.transientList.remove(this);
1541 // we have no transient_for until we find a new one
1542 client.transient_for = (BlackboxWindow *) 0;
1545 if (! XGetTransientForHint(blackbox->getXDisplay(), client.window,
1547 // transient_for hint not set
1551 if (trans_for == client.window) {
1552 // wierd client... treat this window as a normal window
1556 if (trans_for == None || trans_for == screen->getRootWindow()) {
1557 // this is an undocumented interpretation of the ICCCM. a transient
1558 // associated with None/Root/itself is assumed to be a modal root
1559 // transient. we don't support the concept of a global transient,
1560 // so we just associate this transient with nothing, and perhaps
1561 // we will add support later for global modality.
1562 client.transient_for = (BlackboxWindow *) ~0ul;
1567 client.transient_for = blackbox->searchWindow(trans_for);
1568 if (! client.transient_for &&
1569 client.window_group && trans_for == client.window_group) {
1570 // no direct transient_for, perhaps this is a group transient?
1571 BWindowGroup *group = blackbox->searchGroup(client.window_group);
1572 if (group) client.transient_for = group->find(screen);
1575 if (! client.transient_for || client.transient_for == this) {
1576 // no transient_for found, or we have a wierd client that wants to be
1577 // a transient for itself, so we treat this window as a normal window
1578 client.transient_for = (BlackboxWindow*) 0;
1582 // Check for a circular transient state: this can lock up Blackbox
1583 // when it tries to find the non-transient window for a transient.
1584 BlackboxWindow *w = this;
1585 while(w->client.transient_for &&
1586 w->client.transient_for != (BlackboxWindow *) ~0ul) {
1587 if(w->client.transient_for == this) {
1588 client.transient_for = (BlackboxWindow*) 0;
1591 w = w->client.transient_for;
1594 if (client.transient_for &&
1595 client.transient_for != (BlackboxWindow *) ~0ul) {
1596 // register ourselves with our new transient_for
1597 client.transient_for->client.transientList.push_back(this);
1598 flags.stuck = client.transient_for->flags.stuck;
1603 BlackboxWindow *BlackboxWindow::getTransientFor(void) const {
1604 if (client.transient_for &&
1605 client.transient_for != (BlackboxWindow*) ~0ul)
1606 return client.transient_for;
1612 * This function is responsible for updating both the client and the frame
1614 * According to the ICCCM a client message is not sent for a resize, only a
1617 void BlackboxWindow::configure(int dx, int dy,
1618 unsigned int dw, unsigned int dh) {
1619 bool send_event = ((frame.rect.x() != dx || frame.rect.y() != dy) &&
1622 if (dw != frame.rect.width() || dh != frame.rect.height()) {
1623 frame.rect.setRect(dx, dy, dw, dh);
1624 frame.inside_w = frame.rect.width() - (frame.border_w * 2);
1625 frame.inside_h = frame.rect.height() - (frame.border_w * 2);
1627 if (frame.rect.right() <= 0 || frame.rect.bottom() <= 0)
1628 frame.rect.setPos(0, 0);
1630 client.rect.setCoords(frame.rect.left() + frame.margin.left,
1631 frame.rect.top() + frame.margin.top,
1632 frame.rect.right() - frame.margin.right,
1633 frame.rect.bottom() - frame.margin.bottom);
1636 if (blackbox->hasShapeExtensions() && flags.shaped) {
1643 redrawWindowFrame();
1645 frame.rect.setPos(dx, dy);
1647 XMoveWindow(blackbox->getXDisplay(), frame.window,
1648 frame.rect.x(), frame.rect.y());
1650 we may have been called just after an opaque window move, so even though
1651 the old coords match the new ones no ConfigureNotify has been sent yet.
1652 There are likely other times when this will be relevant as well.
1654 if (! flags.moving) send_event = True;
1658 // if moving, the update and event will occur when the move finishes
1659 client.rect.setPos(frame.rect.left() + frame.margin.left,
1660 frame.rect.top() + frame.margin.top);
1663 event.type = ConfigureNotify;
1665 event.xconfigure.display = blackbox->getXDisplay();
1666 event.xconfigure.event = client.window;
1667 event.xconfigure.window = client.window;
1668 event.xconfigure.x = client.rect.x();
1669 event.xconfigure.y = client.rect.y();
1670 event.xconfigure.width = client.rect.width();
1671 event.xconfigure.height = client.rect.height();
1672 event.xconfigure.border_width = client.old_bw;
1673 event.xconfigure.above = frame.window;
1674 event.xconfigure.override_redirect = False;
1676 XSendEvent(blackbox->getXDisplay(), client.window, False,
1677 StructureNotifyMask, &event);
1678 screen->updateNetizenConfigNotify(&event);
1679 XFlush(blackbox->getXDisplay());
1685 void BlackboxWindow::configureShape(void) {
1686 XShapeCombineShape(blackbox->getXDisplay(), frame.window, ShapeBounding,
1687 frame.margin.left - frame.border_w,
1688 frame.margin.top - frame.border_w,
1689 client.window, ShapeBounding, ShapeSet);
1692 XRectangle xrect[2];
1694 if (decorations & Decor_Titlebar) {
1695 xrect[0].x = xrect[0].y = -frame.border_w;
1696 xrect[0].width = frame.rect.width();
1697 xrect[0].height = frame.title_h + (frame.border_w * 2);
1701 if (decorations & Decor_Handle) {
1702 xrect[1].x = -frame.border_w;
1703 xrect[1].y = frame.rect.height() - frame.margin.bottom +
1704 frame.mwm_border_w - frame.border_w;
1705 xrect[1].width = frame.rect.width();
1706 xrect[1].height = frame.handle_h + (frame.border_w * 2);
1710 XShapeCombineRectangles(blackbox->getXDisplay(), frame.window,
1711 ShapeBounding, 0, 0, xrect, num,
1712 ShapeUnion, Unsorted);
1716 void BlackboxWindow::clearShape(void) {
1717 XShapeCombineMask(blackbox->getXDisplay(), frame.window, ShapeBounding,
1718 frame.margin.left - frame.border_w,
1719 frame.margin.top - frame.border_w,
1725 bool BlackboxWindow::setInputFocus(void) {
1726 if (flags.focused) return True;
1728 assert(flags.stuck || // window must be on the current workspace or sticky
1729 blackbox_attrib.workspace == screen->getCurrentWorkspaceID());
1732 We only do this check for normal windows and dialogs because other windows
1733 do this on purpose, such as kde's kicker, and we don't want to go moving
1736 if (window_type == Type_Normal || window_type == Type_Dialog)
1737 if (! frame.rect.intersects(screen->getRect())) {
1738 // client is outside the screen, move it to the center
1739 configure((screen->getWidth() - frame.rect.width()) / 2,
1740 (screen->getHeight() - frame.rect.height()) / 2,
1741 frame.rect.width(), frame.rect.height());
1744 if (client.transientList.size() > 0) {
1745 // transfer focus to any modal transients
1746 BlackboxWindowList::iterator it, end = client.transientList.end();
1747 for (it = client.transientList.begin(); it != end; ++it)
1748 if ((*it)->flags.modal) return (*it)->setInputFocus();
1752 if (focus_mode == F_LocallyActive || focus_mode == F_Passive) {
1753 XSetInputFocus(blackbox->getXDisplay(), client.window,
1754 RevertToPointerRoot, CurrentTime);
1756 /* we could set the focus to none, since the window doesn't accept focus,
1757 * but we shouldn't set focus to nothing since this would surely make
1763 if (flags.send_focus_message) {
1765 ce.xclient.type = ClientMessage;
1766 ce.xclient.message_type = xatom->getAtom(XAtom::wm_protocols);
1767 ce.xclient.display = blackbox->getXDisplay();
1768 ce.xclient.window = client.window;
1769 ce.xclient.format = 32;
1770 ce.xclient.data.l[0] = xatom->getAtom(XAtom::wm_take_focus);
1771 ce.xclient.data.l[1] = blackbox->getLastTime();
1772 ce.xclient.data.l[2] = 0l;
1773 ce.xclient.data.l[3] = 0l;
1774 ce.xclient.data.l[4] = 0l;
1775 XSendEvent(blackbox->getXDisplay(), client.window, False,
1777 XFlush(blackbox->getXDisplay());
1784 void BlackboxWindow::iconify(void) {
1785 if (flags.iconic || ! (functions & Func_Iconify)) return;
1787 // We don't need to worry about resizing because resizing always grabs the X
1788 // server. This should only ever happen if using opaque moving.
1792 if (windowmenu) windowmenu->hide();
1795 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1796 * we need to clear the event mask on client.window for a split second.
1797 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1798 * split second, leaving us with a ghost window... so, we need to do this
1799 * while the X server is grabbed
1801 unsigned long event_mask = PropertyChangeMask | FocusChangeMask |
1802 StructureNotifyMask;
1803 XGrabServer(blackbox->getXDisplay());
1804 XSelectInput(blackbox->getXDisplay(), client.window,
1805 event_mask & ~StructureNotifyMask);
1806 XUnmapWindow(blackbox->getXDisplay(), client.window);
1807 XSelectInput(blackbox->getXDisplay(), client.window, event_mask);
1808 XUngrabServer(blackbox->getXDisplay());
1810 XUnmapWindow(blackbox->getXDisplay(), frame.window);
1811 flags.visible = False;
1812 flags.iconic = True;
1814 setState(IconicState);
1816 screen->getWorkspace(blackbox_attrib.workspace)->removeWindow(this);
1818 for (unsigned int i = 0; i < screen->getNumberOfWorkspaces(); ++i)
1819 if (i != blackbox_attrib.workspace)
1820 screen->getWorkspace(i)->removeWindow(this, True);
1823 if (isTransient()) {
1824 if (client.transient_for != (BlackboxWindow *) ~0ul &&
1825 ! client.transient_for->flags.iconic) {
1826 // iconify our transient_for
1827 client.transient_for->iconify();
1831 screen->addIcon(this);
1833 if (client.transientList.size() > 0) {
1834 // iconify all transients
1835 BlackboxWindowList::iterator it, end = client.transientList.end();
1836 for (it = client.transientList.begin(); it != end; ++it) {
1837 if (! (*it)->flags.iconic) (*it)->iconify();
1840 screen->updateStackingList();
1844 void BlackboxWindow::show(void) {
1845 flags.visible = True;
1846 flags.iconic = False;
1848 current_state = (flags.shaded) ? IconicState : NormalState;
1849 setState(current_state);
1851 XMapWindow(blackbox->getXDisplay(), client.window);
1852 XMapSubwindows(blackbox->getXDisplay(), frame.window);
1853 XMapWindow(blackbox->getXDisplay(), frame.window);
1858 XTranslateCoordinates(blackbox->getXDisplay(), client.window,
1859 screen->getRootWindow(),
1860 0, 0, &real_x, &real_y, &child);
1861 fprintf(stderr, "%s -- assumed: (%d, %d), real: (%d, %d)\n", getTitle(),
1862 client.rect.left(), client.rect.top(), real_x, real_y);
1863 assert(client.rect.left() == real_x && client.rect.top() == real_y);
1868 void BlackboxWindow::deiconify(bool reassoc, bool raise) {
1869 if (flags.iconic || reassoc)
1870 screen->reassociateWindow(this, BSENTINEL, False);
1871 else if (blackbox_attrib.workspace != screen->getCurrentWorkspaceID())
1876 // reassociate and deiconify all transients
1877 if (reassoc && client.transientList.size() > 0) {
1878 BlackboxWindowList::iterator it, end = client.transientList.end();
1879 for (it = client.transientList.begin(); it != end; ++it)
1880 (*it)->deiconify(True, False);
1884 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
1888 void BlackboxWindow::close(void) {
1889 if (! (functions & Func_Close)) return;
1892 ce.xclient.type = ClientMessage;
1893 ce.xclient.message_type = xatom->getAtom(XAtom::wm_protocols);
1894 ce.xclient.display = blackbox->getXDisplay();
1895 ce.xclient.window = client.window;
1896 ce.xclient.format = 32;
1897 ce.xclient.data.l[0] = xatom->getAtom(XAtom::wm_delete_window);
1898 ce.xclient.data.l[1] = CurrentTime;
1899 ce.xclient.data.l[2] = 0l;
1900 ce.xclient.data.l[3] = 0l;
1901 ce.xclient.data.l[4] = 0l;
1902 XSendEvent(blackbox->getXDisplay(), client.window, False, NoEventMask, &ce);
1903 XFlush(blackbox->getXDisplay());
1907 void BlackboxWindow::withdraw(void) {
1908 // We don't need to worry about resizing because resizing always grabs the X
1909 // server. This should only ever happen if using opaque moving.
1913 flags.visible = False;
1914 flags.iconic = False;
1916 setState(current_state);
1918 XUnmapWindow(blackbox->getXDisplay(), frame.window);
1920 XGrabServer(blackbox->getXDisplay());
1922 unsigned long event_mask = PropertyChangeMask | FocusChangeMask |
1923 StructureNotifyMask;
1924 XSelectInput(blackbox->getXDisplay(), client.window,
1925 event_mask & ~StructureNotifyMask);
1926 XUnmapWindow(blackbox->getXDisplay(), client.window);
1927 XSelectInput(blackbox->getXDisplay(), client.window, event_mask);
1929 XUngrabServer(blackbox->getXDisplay());
1931 if (windowmenu) windowmenu->hide();
1935 void BlackboxWindow::maximize(unsigned int button) {
1936 if (! (functions & Func_Maximize)) return;
1938 // We don't need to worry about resizing because resizing always grabs the X
1939 // server. This should only ever happen if using opaque moving.
1943 // handle case where menu is open then the max button is used instead
1944 if (windowmenu && windowmenu->isVisible()) windowmenu->hide();
1946 if (flags.maximized) {
1947 flags.maximized = 0;
1949 blackbox_attrib.flags &= ! (AttribMaxHoriz | AttribMaxVert);
1950 blackbox_attrib.attrib &= ! (AttribMaxHoriz | AttribMaxVert);
1953 when a resize finishes, maximize(0) is called to clear any maximization
1954 flags currently set. Otherwise it still thinks it is maximized.
1955 so we do not need to call configure() because resizing will handle it
1957 if (! flags.resizing)
1958 configure(blackbox_attrib.premax_x, blackbox_attrib.premax_y,
1959 blackbox_attrib.premax_w, blackbox_attrib.premax_h);
1961 blackbox_attrib.premax_x = blackbox_attrib.premax_y = 0;
1962 blackbox_attrib.premax_w = blackbox_attrib.premax_h = 0;
1964 redrawAllButtons(); // in case it is not called in configure()
1965 setState(current_state);
1969 blackbox_attrib.premax_x = frame.rect.x();
1970 blackbox_attrib.premax_y = frame.rect.y();
1971 blackbox_attrib.premax_w = frame.rect.width();
1972 // use client.rect so that clients can be restored even if shaded
1973 blackbox_attrib.premax_h =
1974 client.rect.height() + frame.margin.top + frame.margin.bottom;
1977 if (screen->isXineramaActive() && blackbox->doXineramaMaximizing()) {
1978 // find the area to use
1979 RectList availableAreas = screen->allAvailableAreas();
1980 RectList::iterator it, end = availableAreas.end();
1982 for (it = availableAreas.begin(); it != end; ++it)
1983 if (it->intersects(frame.rect)) break;
1984 if (it == end) // the window isn't inside an area
1985 it = availableAreas.begin(); // so just default to the first one
1987 frame.changing = *it;
1990 frame.changing = screen->availableArea();
1994 blackbox_attrib.flags |= AttribMaxHoriz | AttribMaxVert;
1995 blackbox_attrib.attrib |= AttribMaxHoriz | AttribMaxVert;
1999 blackbox_attrib.flags |= AttribMaxVert;
2000 blackbox_attrib.attrib |= AttribMaxVert;
2002 frame.changing.setX(frame.rect.x());
2003 frame.changing.setWidth(frame.rect.width());
2007 blackbox_attrib.flags |= AttribMaxHoriz;
2008 blackbox_attrib.attrib |= AttribMaxHoriz;
2010 frame.changing.setY(frame.rect.y());
2011 frame.changing.setHeight(frame.rect.height());
2018 blackbox_attrib.flags ^= AttribShaded;
2019 blackbox_attrib.attrib ^= AttribShaded;
2020 flags.shaded = False;
2023 flags.maximized = button;
2025 configure(frame.changing.x(), frame.changing.y(),
2026 frame.changing.width(), frame.changing.height());
2028 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
2029 redrawAllButtons(); // in case it is not called in configure()
2030 setState(current_state);
2034 // re-maximizes the window to take into account availableArea changes
2035 void BlackboxWindow::remaximize(void) {
2037 // we only update the window's attributes otherwise we lose the shade bit
2038 switch(flags.maximized) {
2040 blackbox_attrib.flags |= AttribMaxHoriz | AttribMaxVert;
2041 blackbox_attrib.attrib |= AttribMaxHoriz | AttribMaxVert;
2045 blackbox_attrib.flags |= AttribMaxVert;
2046 blackbox_attrib.attrib |= AttribMaxVert;
2050 blackbox_attrib.flags |= AttribMaxHoriz;
2051 blackbox_attrib.attrib |= AttribMaxHoriz;
2057 // save the original dimensions because maximize will wipe them out
2058 int premax_x = blackbox_attrib.premax_x,
2059 premax_y = blackbox_attrib.premax_y,
2060 premax_w = blackbox_attrib.premax_w,
2061 premax_h = blackbox_attrib.premax_h;
2063 unsigned int button = flags.maximized;
2064 flags.maximized = 0; // trick maximize() into working
2067 // restore saved values
2068 blackbox_attrib.premax_x = premax_x;
2069 blackbox_attrib.premax_y = premax_y;
2070 blackbox_attrib.premax_w = premax_w;
2071 blackbox_attrib.premax_h = premax_h;
2075 void BlackboxWindow::setWorkspace(unsigned int n) {
2076 blackbox_attrib.flags |= AttribWorkspace;
2077 blackbox_attrib.workspace = n;
2078 if (n == BSENTINEL) { // iconified window
2080 we set the workspace to 'all workspaces' so that taskbars will show the
2081 window. otherwise, it made uniconifying a window imposible without the
2082 blackbox workspace menu
2086 xatom->setValue(client.window, XAtom::net_wm_desktop, XAtom::cardinal, n);
2090 void BlackboxWindow::shade(void) {
2092 XResizeWindow(blackbox->getXDisplay(), frame.window,
2093 frame.inside_w, frame.inside_h);
2094 flags.shaded = False;
2095 blackbox_attrib.flags ^= AttribShaded;
2096 blackbox_attrib.attrib ^= AttribShaded;
2098 setState(NormalState);
2100 // set the frame rect to the normal size
2101 frame.rect.setHeight(client.rect.height() + frame.margin.top +
2102 frame.margin.bottom);
2104 if (! (decorations & Decor_Titlebar))
2105 return; // can't shade it without a titlebar!
2107 XResizeWindow(blackbox->getXDisplay(), frame.window,
2108 frame.inside_w, frame.title_h);
2109 flags.shaded = True;
2110 blackbox_attrib.flags |= AttribShaded;
2111 blackbox_attrib.attrib |= AttribShaded;
2113 setState(IconicState);
2115 // set the frame rect to the shaded size
2116 frame.rect.setHeight(frame.title_h + (frame.border_w * 2));
2122 * (Un)Sticks a window and its relatives.
2124 void BlackboxWindow::stick(void) {
2126 blackbox_attrib.flags ^= AttribOmnipresent;
2127 blackbox_attrib.attrib ^= AttribOmnipresent;
2129 flags.stuck = False;
2131 for (unsigned int i = 0; i < screen->getNumberOfWorkspaces(); ++i)
2132 if (i != blackbox_attrib.workspace)
2133 screen->getWorkspace(i)->removeWindow(this, True);
2136 screen->reassociateWindow(this, BSENTINEL, True);
2137 // temporary fix since sticky windows suck. set the hint to what we
2138 // actually hold in our data.
2139 xatom->setValue(client.window, XAtom::net_wm_desktop, XAtom::cardinal,
2140 blackbox_attrib.workspace);
2142 setState(current_state);
2146 blackbox_attrib.flags |= AttribOmnipresent;
2147 blackbox_attrib.attrib |= AttribOmnipresent;
2149 // temporary fix since sticky windows suck. set the hint to a different
2150 // value than that contained in the class' data.
2151 xatom->setValue(client.window, XAtom::net_wm_desktop, XAtom::cardinal,
2154 for (unsigned int i = 0; i < screen->getNumberOfWorkspaces(); ++i)
2155 if (i != blackbox_attrib.workspace)
2156 screen->getWorkspace(i)->addWindow(this, False, True);
2158 setState(current_state);
2164 if (isTransient() && client.transient_for != (BlackboxWindow *) ~0ul &&
2165 client.transient_for->isStuck() != flags.stuck)
2166 client.transient_for->stick();
2167 // go down the chain
2168 BlackboxWindowList::iterator it;
2169 const BlackboxWindowList::iterator end = client.transientList.end();
2170 for (it = client.transientList.begin(); it != end; ++it)
2171 if ((*it)->isStuck() != flags.stuck)
2176 void BlackboxWindow::redrawWindowFrame(void) const {
2177 if (decorations & Decor_Titlebar) {
2178 if (flags.focused) {
2180 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2181 frame.title, frame.ftitle);
2183 XSetWindowBackground(blackbox->getXDisplay(),
2184 frame.title, frame.ftitle_pixel);
2187 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2188 frame.title, frame.utitle);
2190 XSetWindowBackground(blackbox->getXDisplay(),
2191 frame.title, frame.utitle_pixel);
2193 XClearWindow(blackbox->getXDisplay(), frame.title);
2199 if (decorations & Decor_Handle) {
2200 if (flags.focused) {
2202 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2203 frame.handle, frame.fhandle);
2205 XSetWindowBackground(blackbox->getXDisplay(),
2206 frame.handle, frame.fhandle_pixel);
2209 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2210 frame.left_grip, frame.fgrip);
2211 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2212 frame.right_grip, frame.fgrip);
2214 XSetWindowBackground(blackbox->getXDisplay(),
2215 frame.left_grip, frame.fgrip_pixel);
2216 XSetWindowBackground(blackbox->getXDisplay(),
2217 frame.right_grip, frame.fgrip_pixel);
2221 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2222 frame.handle, frame.uhandle);
2224 XSetWindowBackground(blackbox->getXDisplay(),
2225 frame.handle, frame.uhandle_pixel);
2228 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2229 frame.left_grip, frame.ugrip);
2230 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2231 frame.right_grip, frame.ugrip);
2233 XSetWindowBackground(blackbox->getXDisplay(),
2234 frame.left_grip, frame.ugrip_pixel);
2235 XSetWindowBackground(blackbox->getXDisplay(),
2236 frame.right_grip, frame.ugrip_pixel);
2239 XClearWindow(blackbox->getXDisplay(), frame.handle);
2240 XClearWindow(blackbox->getXDisplay(), frame.left_grip);
2241 XClearWindow(blackbox->getXDisplay(), frame.right_grip);
2244 if (decorations & Decor_Border) {
2246 XSetWindowBorder(blackbox->getXDisplay(),
2247 frame.plate, frame.fborder_pixel);
2249 XSetWindowBorder(blackbox->getXDisplay(),
2250 frame.plate, frame.uborder_pixel);
2255 void BlackboxWindow::setFocusFlag(bool focus) {
2256 // only focus a window if it is visible
2257 if (focus && ! flags.visible)
2260 flags.focused = focus;
2262 redrawWindowFrame();
2265 blackbox->setFocusedWindow(this);
2267 if (! flags.iconic) {
2268 // iconic windows arent in a workspace menu!
2270 screen->getCurrentWorkspace()->setFocused(this, isFocused());
2272 screen->getWorkspace(blackbox_attrib.workspace)->
2273 setFocused(this, flags.focused);
2278 void BlackboxWindow::installColormap(bool install) {
2279 int i = 0, ncmap = 0;
2280 Colormap *cmaps = XListInstalledColormaps(blackbox->getXDisplay(),
2281 client.window, &ncmap);
2283 XWindowAttributes wattrib;
2284 if (XGetWindowAttributes(blackbox->getXDisplay(),
2285 client.window, &wattrib)) {
2287 // install the window's colormap
2288 for (i = 0; i < ncmap; i++) {
2289 if (*(cmaps + i) == wattrib.colormap)
2290 // this window is using an installed color map... do not install
2293 // otherwise, install the window's colormap
2295 XInstallColormap(blackbox->getXDisplay(), wattrib.colormap);
2297 // uninstall the window's colormap
2298 for (i = 0; i < ncmap; i++) {
2299 if (*(cmaps + i) == wattrib.colormap)
2300 // we found the colormap to uninstall
2301 XUninstallColormap(blackbox->getXDisplay(), wattrib.colormap);
2311 void BlackboxWindow::setAllowedActions(void) {
2315 actions[num++] = xatom->getAtom(XAtom::net_wm_action_shade);
2316 actions[num++] = xatom->getAtom(XAtom::net_wm_action_change_desktop);
2317 actions[num++] = xatom->getAtom(XAtom::net_wm_action_close);
2319 if (functions & Func_Move)
2320 actions[num++] = xatom->getAtom(XAtom::net_wm_action_move);
2321 if (functions & Func_Resize)
2322 actions[num++] = xatom->getAtom(XAtom::net_wm_action_resize);
2323 if (functions & Func_Maximize) {
2324 actions[num++] = xatom->getAtom(XAtom::net_wm_action_maximize_horz);
2325 actions[num++] = xatom->getAtom(XAtom::net_wm_action_maximize_vert);
2328 xatom->setValue(client.window, XAtom::net_wm_allowed_actions, XAtom::atom,
2333 void BlackboxWindow::setState(unsigned long new_state) {
2334 current_state = new_state;
2336 unsigned long state[2];
2337 state[0] = current_state;
2339 xatom->setValue(client.window, XAtom::wm_state, XAtom::wm_state, state, 2);
2341 xatom->setValue(client.window, XAtom::blackbox_attributes,
2342 XAtom::blackbox_attributes, (unsigned long *)&blackbox_attrib,
2343 PropBlackboxAttributesElements);
2348 netstate[num++] = xatom->getAtom(XAtom::net_wm_state_modal);
2350 netstate[num++] = xatom->getAtom(XAtom::net_wm_state_shaded);
2352 netstate[num++] = xatom->getAtom(XAtom::net_wm_state_hidden);
2353 if (flags.skip_taskbar)
2354 netstate[num++] = xatom->getAtom(XAtom::net_wm_state_skip_taskbar);
2355 if (flags.skip_pager)
2356 netstate[num++] = xatom->getAtom(XAtom::net_wm_state_skip_pager);
2357 if (flags.fullscreen)
2358 netstate[num++] = xatom->getAtom(XAtom::net_wm_state_fullscreen);
2359 if (flags.maximized == 1 || flags.maximized == 2)
2360 netstate[num++] = xatom->getAtom(XAtom::net_wm_state_maximized_vert);
2361 if (flags.maximized == 1 || flags.maximized == 3)
2362 netstate[num++] = xatom->getAtom(XAtom::net_wm_state_maximized_horz);
2363 xatom->setValue(client.window, XAtom::net_wm_state, XAtom::atom,
2368 bool BlackboxWindow::getState(void) {
2369 bool ret = xatom->getValue(client.window, XAtom::wm_state, XAtom::wm_state,
2371 if (! ret) current_state = 0;
2376 void BlackboxWindow::restoreAttributes(void) {
2377 unsigned long num = PropBlackboxAttributesElements;
2378 BlackboxAttributes *net;
2379 if (! xatom->getValue(client.window, XAtom::blackbox_attributes,
2380 XAtom::blackbox_attributes, num,
2381 (unsigned long **)&net))
2383 if (num < PropBlackboxAttributesElements) {
2388 if (net->flags & AttribShaded && net->attrib & AttribShaded) {
2389 flags.shaded = False;
2390 unsigned long orig_state = current_state;
2394 At this point in the life of a window, current_state should only be set
2395 to IconicState if the window was an *icon*, not if it was shaded.
2397 if (orig_state != IconicState)
2398 current_state = WithdrawnState;
2401 if (net->workspace != screen->getCurrentWorkspaceID() &&
2402 net->workspace < screen->getWorkspaceCount())
2403 screen->reassociateWindow(this, net->workspace, True);
2405 if ((blackbox_attrib.workspace != screen->getCurrentWorkspaceID()) &&
2406 (blackbox_attrib.workspace < screen->getWorkspaceCount())) {
2407 // set to WithdrawnState so it will be mapped on the new workspace
2408 if (current_state == NormalState) current_state = WithdrawnState;
2409 } else if (current_state == WithdrawnState) {
2410 // the window is on this workspace and is Withdrawn, so it is waiting to
2412 current_state = NormalState;
2415 if (net->flags & AttribOmnipresent && net->attrib & AttribOmnipresent &&
2419 // if the window was on another workspace, it was going to be hidden. this
2420 // specifies that the window should be mapped since it is sticky.
2421 if (current_state == WithdrawnState) current_state = NormalState;
2424 if (net->flags & AttribMaxHoriz || net->flags & AttribMaxVert) {
2425 int x = net->premax_x, y = net->premax_y;
2426 unsigned int w = net->premax_w, h = net->premax_h;
2427 flags.maximized = 0;
2430 if ((net->flags & AttribMaxHoriz) &&
2431 (net->flags & AttribMaxVert))
2432 m = (net->attrib & (AttribMaxHoriz | AttribMaxVert)) ? 1 : 0;
2433 else if (net->flags & AttribMaxVert)
2434 m = (net->attrib & AttribMaxVert) ? 2 : 0;
2435 else if (net->flags & AttribMaxHoriz)
2436 m = (net->attrib & AttribMaxHoriz) ? 3 : 0;
2440 blackbox_attrib.premax_x = x;
2441 blackbox_attrib.premax_y = y;
2442 blackbox_attrib.premax_w = w;
2443 blackbox_attrib.premax_h = h;
2446 if (net->flags & AttribDecoration) {
2447 switch (net->decoration) {
2452 /* since tools only let you toggle this anyways, we'll just make that all
2453 it supports for now.
2464 // with the state set it will then be the map event's job to read the
2465 // window's state and behave accordingly
2472 * Positions the Rect r according the the client window position and
2475 void BlackboxWindow::applyGravity(Rect &r) {
2476 // apply horizontal window gravity
2477 switch (client.win_gravity) {
2479 case NorthWestGravity:
2480 case SouthWestGravity:
2482 r.setX(client.rect.x());
2488 r.setX(client.rect.x() - (frame.margin.left + frame.margin.right) / 2);
2491 case NorthEastGravity:
2492 case SouthEastGravity:
2494 r.setX(client.rect.x() - frame.margin.left - frame.margin.right + 2);
2499 r.setX(client.rect.x() - frame.margin.left);
2503 // apply vertical window gravity
2504 switch (client.win_gravity) {
2506 case NorthWestGravity:
2507 case NorthEastGravity:
2509 r.setY(client.rect.y());
2515 r.setY(client.rect.y() - (frame.margin.top + frame.margin.bottom) / 2);
2518 case SouthWestGravity:
2519 case SouthEastGravity:
2521 r.setY(client.rect.y() - frame.margin.top - frame.margin.bottom + 2);
2526 r.setY(client.rect.y() - frame.margin.top);
2533 * The reverse of the applyGravity function.
2535 * Positions the Rect r according to the frame window position and
2538 void BlackboxWindow::restoreGravity(Rect &r) {
2539 // restore horizontal window gravity
2540 switch (client.win_gravity) {
2542 case NorthWestGravity:
2543 case SouthWestGravity:
2545 r.setX(frame.rect.x());
2551 r.setX(frame.rect.x() + (frame.margin.left + frame.margin.right) / 2);
2554 case NorthEastGravity:
2555 case SouthEastGravity:
2557 r.setX(frame.rect.x() + frame.margin.left + frame.margin.right - 2);
2562 r.setX(frame.rect.x() + frame.margin.left);
2566 // restore vertical window gravity
2567 switch (client.win_gravity) {
2569 case NorthWestGravity:
2570 case NorthEastGravity:
2572 r.setY(frame.rect.y());
2578 r.setY(frame.rect.y() + (frame.margin.top + frame.margin.bottom) / 2);
2581 case SouthWestGravity:
2582 case SouthEastGravity:
2584 r.setY(frame.rect.y() + frame.margin.top + frame.margin.bottom - 2);
2589 r.setY(frame.rect.y() + frame.margin.top);
2595 void BlackboxWindow::redrawLabel(void) const {
2596 if (flags.focused) {
2598 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2599 frame.label, frame.flabel);
2601 XSetWindowBackground(blackbox->getXDisplay(),
2602 frame.label, frame.flabel_pixel);
2605 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2606 frame.label, frame.ulabel);
2608 XSetWindowBackground(blackbox->getXDisplay(),
2609 frame.label, frame.ulabel_pixel);
2611 XClearWindow(blackbox->getXDisplay(), frame.label);
2613 WindowStyle *style = screen->getWindowStyle();
2615 int pos = frame.bevel_w * 2;
2616 style->doJustify(client.title.c_str(), pos, frame.label_w, frame.bevel_w * 4);
2617 style->font->drawString(frame.label, pos, 1,
2618 (flags.focused ? style->l_text_focus :
2619 style->l_text_unfocus),
2624 void BlackboxWindow::redrawAllButtons(void) const {
2625 if (frame.iconify_button) redrawIconifyButton(False);
2626 if (frame.maximize_button) redrawMaximizeButton(flags.maximized);
2627 if (frame.close_button) redrawCloseButton(False);
2628 if (frame.stick_button) redrawStickyButton(flags.stuck);
2632 void BlackboxWindow::redrawButton(bool pressed, Window win,
2633 Pixmap fppix, unsigned long fppixel,
2634 Pixmap uppix, unsigned long uppixel,
2635 Pixmap fpix, unsigned long fpixel,
2636 Pixmap upix, unsigned long upixel) const {
2641 if (flags.focused) {
2649 if (flags.focused) {
2659 XSetWindowBackgroundPixmap(blackbox->getXDisplay(), win, p);
2661 XSetWindowBackground(blackbox->getXDisplay(), win, pix);
2665 void BlackboxWindow::redrawIconifyButton(bool pressed) const {
2666 redrawButton(pressed, frame.iconify_button,
2667 frame.pfbutton, frame.pfbutton_pixel,
2668 frame.pubutton, frame.pubutton_pixel,
2669 frame.fbutton, frame.fbutton_pixel,
2670 frame.ubutton, frame.ubutton_pixel);
2672 XClearWindow(blackbox->getXDisplay(), frame.iconify_button);
2673 BPen pen((flags.focused) ? screen->getWindowStyle()->b_pic_focus :
2674 screen->getWindowStyle()->b_pic_unfocus);
2676 #ifdef BITMAPBUTTONS
2677 PixmapMask pm = screen->getWindowStyle()->icon_button;
2679 if (screen->getWindowStyle()->icon_button.mask != None) {
2680 XSetClipMask(blackbox->getXDisplay(), pen.gc(), pm.mask);
2681 XSetClipOrigin(blackbox->getXDisplay(), pen.gc(),
2682 (frame.button_w - pm.w)/2, (frame.button_w - pm.h)/2);
2684 XFillRectangle(blackbox->getXDisplay(), frame.iconify_button, pen.gc(),
2685 (frame.button_w - pm.w)/2, (frame.button_w - pm.h)/2,
2686 (frame.button_w + pm.w)/2, (frame.button_w + pm.h)/2);
2688 XSetClipMask(blackbox->getXDisplay(), pen.gc(), None);
2689 XSetClipOrigin(blackbox->getXDisplay(), pen.gc(), 0, 0);
2691 #endif // BITMAPBUTTONS
2692 XDrawRectangle(blackbox->getXDisplay(), frame.iconify_button, pen.gc(),
2693 2, (frame.button_w - 5), (frame.button_w - 5), 2);
2694 #ifdef BITMAPBUTTONS
2696 #endif // BITMAPBUTTONS
2700 void BlackboxWindow::redrawMaximizeButton(bool pressed) const {
2701 redrawButton(pressed, frame.maximize_button,
2702 frame.pfbutton, frame.pfbutton_pixel,
2703 frame.pubutton, frame.pubutton_pixel,
2704 frame.fbutton, frame.fbutton_pixel,
2705 frame.ubutton, frame.ubutton_pixel);
2707 XClearWindow(blackbox->getXDisplay(), frame.maximize_button);
2709 BPen pen((flags.focused) ? screen->getWindowStyle()->b_pic_focus :
2710 screen->getWindowStyle()->b_pic_unfocus);
2712 #ifdef BITMAPBUTTONS
2713 PixmapMask pm = screen->getWindowStyle()->max_button;
2715 if (pm.mask != None) {
2716 XSetClipMask(blackbox->getXDisplay(), pen.gc(), pm.mask);
2717 XSetClipOrigin(blackbox->getXDisplay(), pen.gc(),
2718 (frame.button_w - pm.w)/2, (frame.button_w - pm.h)/2);
2720 XFillRectangle(blackbox->getXDisplay(), frame.maximize_button, pen.gc(),
2721 (frame.button_w - pm.w)/2, (frame.button_w - pm.h)/2,
2722 (frame.button_w + pm.w)/2, (frame.button_w + pm.h)/2);
2724 XSetClipOrigin(blackbox->getXDisplay(), pen.gc(), 0, 0 );
2725 XSetClipMask( blackbox->getXDisplay(), pen.gc(), None );
2727 #endif // BITMAPBUTTONS
2728 XDrawRectangle(blackbox->getXDisplay(), frame.maximize_button, pen.gc(),
2729 2, 2, (frame.button_w - 5), (frame.button_w - 5));
2730 XDrawLine(blackbox->getXDisplay(), frame.maximize_button, pen.gc(),
2731 2, 3, (frame.button_w - 3), 3);
2732 #ifdef BITMAPBUTTONS
2734 #endif // BITMAPBUTTONS
2738 void BlackboxWindow::redrawCloseButton(bool pressed) const {
2739 redrawButton(pressed, frame.close_button,
2740 frame.pfbutton, frame.pfbutton_pixel,
2741 frame.pubutton, frame.pubutton_pixel,
2742 frame.fbutton, frame.fbutton_pixel,
2743 frame.ubutton, frame.ubutton_pixel);
2745 XClearWindow(blackbox->getXDisplay(), frame.close_button);
2747 BPen pen((flags.focused) ? screen->getWindowStyle()->b_pic_focus :
2748 screen->getWindowStyle()->b_pic_unfocus);
2750 #ifdef BITMAPBUTTONS
2751 PixmapMask pm = screen->getWindowStyle()->close_button;
2753 if (pm.mask != None) {
2754 XSetClipMask(blackbox->getXDisplay(), pen.gc(), pm.mask);
2755 XSetClipOrigin(blackbox->getXDisplay(), pen.gc(),
2756 (frame.button_w - pm.w)/2, (frame.button_w - pm.h)/2);
2758 XFillRectangle(blackbox->getXDisplay(), frame.close_button, pen.gc(),
2759 (frame.button_w - pm.w)/2, (frame.button_w - pm.h)/2,
2760 (frame.button_w + pm.w)/2, (frame.button_w + pm.h)/2);
2763 XSetClipOrigin(blackbox->getXDisplay(), pen.gc(), 0, 0 );
2764 XSetClipMask( blackbox->getXDisplay(), pen.gc(), None );
2766 #endif // BITMAPBUTTONS
2767 XDrawLine(blackbox->getXDisplay(), frame.close_button, pen.gc(),
2768 2, 2, (frame.button_w - 3), (frame.button_w - 3));
2769 XDrawLine(blackbox->getXDisplay(), frame.close_button, pen.gc(),
2770 2, (frame.button_w - 3), (frame.button_w - 3), 2);
2771 #ifdef BITMAPBUTTONS
2773 #endif // BITMAPBUTTONS
2776 void BlackboxWindow::redrawStickyButton(bool pressed) const {
2777 redrawButton(pressed, frame.stick_button,
2778 frame.pfbutton, frame.pfbutton_pixel,
2779 frame.pubutton, frame.pubutton_pixel,
2780 frame.fbutton, frame.fbutton_pixel,
2781 frame.ubutton, frame.ubutton_pixel);
2783 XClearWindow(blackbox->getXDisplay(), frame.stick_button);
2785 BPen pen((flags.focused) ? screen->getWindowStyle()->b_pic_focus :
2786 screen->getWindowStyle()->b_pic_unfocus);
2788 #ifdef BITMAPBUTTONS
2789 PixmapMask pm = screen->getWindowStyle()->stick_button;
2791 if (pm.mask != None) {
2792 XSetClipMask(blackbox->getXDisplay(), pen.gc(), pm.mask);
2793 XSetClipOrigin(blackbox->getXDisplay(), pen.gc(),
2794 (frame.button_w - pm.w)/2, (frame.button_w - pm.h)/2);
2796 XFillRectangle(blackbox->getXDisplay(), frame.stick_button, pen.gc(),
2797 (frame.button_w - pm.w)/2, (frame.button_w - pm.h)/2,
2798 (frame.button_w + pm.w)/2, (frame.button_w + pm.h)/2);
2801 XSetClipOrigin(blackbox->getXDisplay(), pen.gc(), 0, 0 );
2802 XSetClipMask( blackbox->getXDisplay(), pen.gc(), None );
2804 #endif // BITMAPBUTTONS
2805 XFillRectangle(blackbox->getXDisplay(), frame.stick_button, pen.gc(),
2806 frame.button_w/2 - 1, frame.button_w/2 -1, 2, 2 );
2807 #ifdef BITMAPBUTTONS
2812 void BlackboxWindow::mapRequestEvent(const XMapRequestEvent *re) {
2813 if (re->window != client.window)
2817 fprintf(stderr, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2822 Even though the window wants to be shown, if it is not on the current
2823 workspace, then it isn't going to be shown right now.
2825 if (! flags.stuck &&
2826 blackbox_attrib.workspace != screen->getCurrentWorkspaceID() &&
2827 blackbox_attrib.workspace < screen->getWorkspaceCount())
2828 if (current_state == NormalState) current_state = WithdrawnState;
2830 switch (current_state) {
2835 case WithdrawnState:
2844 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
2846 if (! blackbox->isStartup()) {
2847 XSync(blackbox->getXDisplay(), False); // make sure the frame is mapped
2848 if (screen->doFocusNew() || (isTransient() && getTransientFor() &&
2849 getTransientFor()->isFocused())) {
2852 if (screen->getPlacementPolicy() == BScreen::ClickMousePlacement) {
2856 XQueryPointer(blackbox->getXDisplay(), screen->getRootWindow(),
2857 &r, &c, &rx, &ry, &x, &y, &m);
2867 void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent *ue) {
2868 if (ue->window != client.window)
2872 fprintf(stderr, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2876 screen->unmanageWindow(this, False);
2880 void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent *de) {
2881 if (de->window != client.window)
2885 fprintf(stderr, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2889 screen->unmanageWindow(this, False);
2893 void BlackboxWindow::reparentNotifyEvent(const XReparentEvent *re) {
2894 if (re->window != client.window || re->parent == frame.plate)
2898 fprintf(stderr, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2899 "0x%lx.\n", client.window, re->parent);
2904 XPutBackEvent(blackbox->getXDisplay(), &ev);
2905 screen->unmanageWindow(this, True);
2909 void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent *pe) {
2910 if (pe->state == PropertyDelete || ! validateClient())
2914 fprintf(stderr, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n",
2920 case XA_WM_CLIENT_MACHINE:
2924 case XA_WM_TRANSIENT_FOR: {
2925 bool s = flags.stuck;
2927 // determine if this is a transient window
2930 if (flags.stuck != s) stick();
2932 // adjust the window decorations based on transience
2933 if (isTransient()) {
2934 functions &= ~Func_Maximize;
2935 setAllowedActions();
2947 case XA_WM_ICON_NAME:
2949 if (flags.iconic) screen->propagateWindowName(this);
2952 case XAtom::net_wm_name:
2956 if (decorations & Decor_Titlebar)
2959 screen->propagateWindowName(this);
2962 case XA_WM_NORMAL_HINTS: {
2965 // the window now can/can't resize itself, so the buttons need to be
2968 if (((client.normal_hint_flags & PMinSize) &&
2969 (client.normal_hint_flags & PMaxSize)) &&
2970 (client.max_width <= client.min_width &&
2971 client.max_height <= client.min_height)) {
2972 functions &= ~(Func_Resize | Func_Maximize);
2974 if (! isTransient())
2975 functions |= Func_Maximize;
2976 functions |= Func_Resize;
2979 setAllowedActions();
2982 Rect old_rect = frame.rect;
2986 if (old_rect != frame.rect)
2993 if (pe->atom == xatom->getAtom(XAtom::wm_protocols)) {
2996 if ((decorations & Decor_Close) && (! frame.close_button)) {
2997 createCloseButton();
2998 if (decorations & Decor_Titlebar) {
2999 positionButtons(True);
3000 XMapSubwindows(blackbox->getXDisplay(), frame.title);
3002 if (windowmenu) windowmenu->reconfigure();
3004 } else if (pe->atom == xatom->getAtom(XAtom::net_wm_strut)) {
3013 void BlackboxWindow::exposeEvent(const XExposeEvent *ee) {
3015 fprintf(stderr, "BlackboxWindow::exposeEvent() for 0x%lx\n", client.window);
3018 if (frame.label == ee->window && (decorations & Decor_Titlebar))
3020 else if (frame.close_button == ee->window)
3021 redrawCloseButton(False);
3022 else if (frame.maximize_button == ee->window)
3023 redrawMaximizeButton(flags.maximized);
3024 else if (frame.iconify_button == ee->window)
3025 redrawIconifyButton(False);
3026 else if (frame.stick_button == ee->window)
3027 redrawStickyButton(flags.stuck);
3031 void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent *cr) {
3032 if (cr->window != client.window || flags.iconic)
3035 if (cr->value_mask & CWBorderWidth)
3036 client.old_bw = cr->border_width;
3038 if (cr->value_mask & (CWX | CWY | CWWidth | CWHeight)) {
3039 frame.changing = frame.rect;
3041 if (cr->value_mask & (CWX | CWY)) {
3042 if (cr->value_mask & CWX)
3043 client.rect.setX(cr->x);
3044 if (cr->value_mask & CWY)
3045 client.rect.setY(cr->y);
3047 applyGravity(frame.changing);
3050 if (cr->value_mask & (CWWidth | CWHeight)) {
3051 if (cr->value_mask & CWWidth)
3052 frame.changing.setWidth(cr->width +
3053 frame.margin.left + frame.margin.right);
3055 if (cr->value_mask & CWHeight)
3056 frame.changing.setHeight(cr->height +
3057 frame.margin.top + frame.margin.bottom);
3060 if a position change has been specified, then that position will be
3061 used instead of determining a position based on the window's gravity.
3063 if (! (cr->value_mask & (CWX | CWY))) {
3065 switch (client.win_gravity) {
3066 case NorthEastGravity:
3070 case SouthWestGravity:
3072 corner = BottomLeft;
3074 case SouthEastGravity:
3075 corner = BottomRight;
3077 default: // NorthWest, Static, etc
3084 configure(frame.changing.x(), frame.changing.y(),
3085 frame.changing.width(), frame.changing.height());
3088 if (cr->value_mask & CWStackMode && !isDesktop()) {
3089 switch (cr->detail) {
3092 screen->getWorkspace(blackbox_attrib.workspace)->lowerWindow(this);
3098 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
3105 void BlackboxWindow::buttonPressEvent(const XButtonEvent *be) {
3107 fprintf(stderr, "BlackboxWindow::buttonPressEvent() for 0x%lx\n",
3111 if (frame.maximize_button == be->window && be->button <= 3) {
3112 redrawMaximizeButton(True);
3113 } else if (be->button == 1 || (be->button == 3 && be->state == mod_mask)) {
3114 if (! flags.focused)
3117 if (frame.iconify_button == be->window) {
3118 redrawIconifyButton(True);
3119 } else if (frame.close_button == be->window) {
3120 redrawCloseButton(True);
3121 } else if (frame.stick_button == be->window) {
3122 redrawStickyButton(True);
3123 } else if (frame.plate == be->window) {
3124 if (windowmenu && windowmenu->isVisible()) windowmenu->hide();
3126 if (be->state != mod_mask || getScreen()->doRaiseOnMoveResize())
3127 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
3129 XAllowEvents(blackbox->getXDisplay(), ReplayPointer, be->time);
3131 if (frame.title == be->window || frame.label == be->window) {
3132 if (((be->time - lastButtonPressTime) <=
3133 blackbox->getDoubleClickInterval()) ||
3134 (be->state == ControlMask)) {
3135 lastButtonPressTime = 0;
3138 lastButtonPressTime = be->time;
3142 if (windowmenu && windowmenu->isVisible()) windowmenu->hide();
3144 if (be->state != mod_mask || getScreen()->doRaiseOnMoveResize())
3145 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
3147 } else if (be->button == 2 && (be->window != frame.iconify_button) &&
3148 (be->window != frame.close_button) &&
3149 (be->window != frame.stick_button)) {
3150 screen->getWorkspace(blackbox_attrib.workspace)->lowerWindow(this);
3151 } else if (windowmenu && be->button == 3 &&
3152 (frame.title == be->window || frame.label == be->window ||
3153 frame.handle == be->window || frame.window == be->window)) {
3154 if (windowmenu->isVisible()) {
3157 int mx = be->x_root - windowmenu->getWidth() / 2,
3158 my = be->y_root - windowmenu->getHeight() / 2;
3160 // snap the window menu into a corner/side if necessary
3161 int left_edge, right_edge, top_edge, bottom_edge;
3164 the " + (frame.border_w * 2) - 1" bits are to get the proper width
3165 and height of the menu, as the sizes returned by it do not include
3168 left_edge = frame.rect.x();
3169 right_edge = frame.rect.right() -
3170 (windowmenu->getWidth() + (frame.border_w * 2) - 1);
3171 top_edge = client.rect.top() - (frame.border_w + frame.mwm_border_w);
3172 bottom_edge = client.rect.bottom() -
3173 (windowmenu->getHeight() + (frame.border_w * 2) - 1) +
3174 (frame.border_w + frame.mwm_border_w);
3178 else if (mx > right_edge)
3182 else if (my > bottom_edge)
3185 if (my + windowmenu->getHeight() > screen->getHeight())
3186 my = screen->getHeight() - windowmenu->getHeight() -
3187 (screen->getBorderWidth() * 2);
3189 windowmenu->move(mx, my);
3191 XRaiseWindow(blackbox->getXDisplay(), windowmenu->getWindowID());
3192 XRaiseWindow(blackbox->getXDisplay(),
3193 windowmenu->getSendToMenu()->getWindowID());
3196 } else if (be->button == 4) {
3197 if ((be->window == frame.label ||
3198 be->window == frame.title ||
3199 be->window == frame.maximize_button ||
3200 be->window == frame.iconify_button ||
3201 be->window == frame.close_button ||
3202 be->window == frame.stick_button) &&
3206 } else if (be->button == 5) {
3207 if ((be->window == frame.label ||
3208 be->window == frame.title ||
3209 be->window == frame.maximize_button ||
3210 be->window == frame.iconify_button ||
3211 be->window == frame.close_button ||
3212 be->window == frame.stick_button) &&
3219 void BlackboxWindow::buttonReleaseEvent(const XButtonEvent *re) {
3221 fprintf(stderr, "BlackboxWindow::buttonReleaseEvent() for 0x%lx\n",
3225 if (re->window == frame.maximize_button &&
3226 re->button >= 1 && re->button <= 3) {
3227 if ((re->x >= 0 && re->x <= static_cast<signed>(frame.button_w)) &&
3228 (re->y >= 0 && re->y <= static_cast<signed>(frame.button_w))) {
3229 maximize(re->button);
3231 redrawMaximizeButton(flags.maximized);
3233 } else if (re->window == frame.iconify_button && re->button == 1) {
3234 if ((re->x >= 0 && re->x <= static_cast<signed>(frame.button_w)) &&
3235 (re->y >= 0 && re->y <= static_cast<signed>(frame.button_w))) {
3238 redrawIconifyButton(False);
3240 } else if (re->window == frame.stick_button && re->button == 1) {
3241 if ((re->x >= 0 && re->x <= static_cast<signed>(frame.button_w)) &&
3242 (re->y >= 0 && re->y <= static_cast<signed>(frame.button_w))) {
3245 redrawStickyButton(False);
3247 } else if (re->window == frame.close_button & re->button == 1) {
3248 if ((re->x >= 0 && re->x <= static_cast<signed>(frame.button_w)) &&
3249 (re->y >= 0 && re->y <= static_cast<signed>(frame.button_w)))
3251 redrawCloseButton(False);
3252 } else if (flags.moving) {
3254 } else if (flags.resizing) {
3256 } else if (re->window == frame.window) {
3257 if (re->button == 2 && re->state == mod_mask)
3258 XUngrabPointer(blackbox->getXDisplay(), CurrentTime);
3264 void BlackboxWindow::beginMove(int x_root, int y_root) {
3265 if (! (functions & Func_Move)) return;
3267 assert(! (flags.resizing || flags.moving));
3270 Only one window can be moved/resized at a time. If another window is already
3271 being moved or resized, then stop it before whating to work with this one.
3273 BlackboxWindow *changing = blackbox->getChangingWindow();
3274 if (changing && changing != this) {
3275 if (changing->flags.moving)
3276 changing->endMove();
3277 else // if (changing->flags.resizing)
3278 changing->endResize();
3281 XGrabPointer(blackbox->getXDisplay(), frame.window, False,
3282 PointerMotionMask | ButtonReleaseMask,
3283 GrabModeAsync, GrabModeAsync,
3284 None, blackbox->getMoveCursor(), CurrentTime);
3286 if (windowmenu && windowmenu->isVisible())
3289 flags.moving = True;
3290 blackbox->setChangingWindow(this);
3292 if (! screen->doOpaqueMove()) {
3293 XGrabServer(blackbox->getXDisplay());
3295 frame.changing = frame.rect;
3296 screen->showPosition(frame.changing.x(), frame.changing.y());
3298 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
3302 frame.changing.width() - 1,
3303 frame.changing.height() - 1);
3306 frame.grab_x = x_root - frame.rect.x() - frame.border_w;
3307 frame.grab_y = y_root - frame.rect.y() - frame.border_w;
3311 void BlackboxWindow::doMove(int x_root, int y_root) {
3312 assert(flags.moving);
3313 assert(blackbox->getChangingWindow() == this);
3315 int dx = x_root - frame.grab_x, dy = y_root - frame.grab_y;
3316 dx -= frame.border_w;
3317 dy -= frame.border_w;
3319 doWindowSnapping(dx, dy);
3321 if (screen->doOpaqueMove()) {
3322 if (screen->doWorkspaceWarping())
3323 doWorkspaceWarping(x_root, y_root, dx);
3325 configure(dx, dy, frame.rect.width(), frame.rect.height());
3327 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
3331 frame.changing.width() - 1,
3332 frame.changing.height() - 1);
3334 if (screen->doWorkspaceWarping())
3335 doWorkspaceWarping(x_root, y_root, dx);
3337 frame.changing.setPos(dx, dy);
3339 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
3343 frame.changing.width() - 1,
3344 frame.changing.height() - 1);
3347 screen->showPosition(dx, dy);
3351 void BlackboxWindow::doWorkspaceWarping(int x_root, int y_root, int &dx) {
3352 // workspace warping
3354 unsigned int dest = screen->getCurrentWorkspaceID();
3358 if (dest > 0) dest--;
3359 else dest = screen->getNumberOfWorkspaces() - 1;
3361 } else if (x_root >= screen->getRect().right()) {
3364 if (dest < screen->getNumberOfWorkspaces() - 1) dest++;
3370 bool focus = flags.focused; // had focus while moving?
3372 int dest_x = x_root;
3374 dest_x += screen->getRect().width() - 1;
3375 dx += screen->getRect().width() - 1;
3377 dest_x -= screen->getRect().width() - 1;
3378 dx -= screen->getRect().width() - 1;
3382 screen->reassociateWindow(this, dest, False);
3383 screen->changeWorkspaceID(dest);
3385 if (screen->doOpaqueMove())
3386 XGrabServer(blackbox->getXDisplay());
3388 XUngrabPointer(blackbox->getXDisplay(), CurrentTime);
3389 XWarpPointer(blackbox->getXDisplay(), None,
3390 screen->getRootWindow(), 0, 0, 0, 0,
3392 XGrabPointer(blackbox->getXDisplay(), frame.window, False,
3393 PointerMotionMask | ButtonReleaseMask,
3394 GrabModeAsync, GrabModeAsync,
3395 None, blackbox->getMoveCursor(), CurrentTime);
3397 if (screen->doOpaqueMove())
3398 XUngrabServer(blackbox->getXDisplay());
3406 void BlackboxWindow::doWindowSnapping(int &dx, int &dy) {
3407 // how much resistance to edges to provide
3408 const int resistance_size = screen->getResistanceSize();
3410 // how far away to snap
3411 const int snap_distance = screen->getSnapThreshold();
3413 // how to snap windows
3414 const int snap_to_windows = screen->getWindowToWindowSnap();
3415 const int snap_to_edges = screen->getWindowToEdgeSnap();
3416 // the amount of space away from the edge to provide resistance/snap
3417 const int snap_offset = screen->getSnapOffset();
3419 // find the geomeetery where the moving window currently is
3420 const Rect &moving = screen->doOpaqueMove() ? frame.rect : frame.changing;
3423 const int wleft = dx,
3424 wright = dx + frame.rect.width() - 1,
3426 wbottom = dy + frame.rect.height() - 1;
3428 if (snap_to_windows) {
3431 Workspace *w = screen->getWorkspace(getWorkspaceNumber());
3434 // add windows on the workspace to the rect list
3435 const BlackboxWindowList& stack_list = w->getStackingList();
3436 BlackboxWindowList::const_iterator st_it, st_end = stack_list.end();
3437 for (st_it = stack_list.begin(); st_it != st_end; ++st_it)
3438 if (*st_it != this) // don't snap to ourself
3439 rectlist.push_back( (*st_it)->frameRect() );
3441 // add the toolbar and the slit to the rect list.
3442 // (only if they are not hidden)
3443 Toolbar *tbar = screen->getToolbar();
3444 Slit *slit = screen->getSlit();
3445 Rect tbar_rect, slit_rect;
3446 unsigned int bwidth = screen->getBorderWidth() * 2;
3448 if (! (screen->doHideToolbar() || tbar->isHidden())) {
3449 tbar_rect.setRect(tbar->getX(), tbar->getY(), tbar->getWidth() + bwidth,
3450 tbar->getHeight() + bwidth);
3451 rectlist.push_back(tbar_rect);
3454 if (! slit->isHidden()) {
3455 slit_rect.setRect(slit->getX(), slit->getY(), slit->getWidth() + bwidth,
3456 slit->getHeight() + bwidth);
3457 rectlist.push_back(slit_rect);
3460 RectList::const_iterator it, end = rectlist.end();
3461 for (it = rectlist.begin(); it != end; ++it) {
3462 bool snapped = False;
3463 const Rect &winrect = *it;
3465 offsetrect.setCoords(winrect.left() - snap_offset,
3466 winrect.top() - snap_offset,
3467 winrect.right() + snap_offset,
3468 winrect.bottom() + snap_offset);
3470 if (snap_to_windows == BScreen::WindowResistance)
3471 // if the window is already over top of this snap target, then
3472 // resistance is futile, so just ignore it
3473 if (winrect.intersects(moving))
3476 int dleft, dright, dtop, dbottom;
3478 // if the windows are in the same plane vertically
3479 if (wtop >= (signed)(winrect.y() - frame.rect.height() + 1) &&
3480 wtop < (signed)(winrect.y() + winrect.height() - 1)) {
3482 if (snap_to_windows == BScreen::WindowResistance) {
3483 dleft = wright - offsetrect.left();
3484 dright = offsetrect.right() - wleft;
3486 // snap left of other window?
3487 if (dleft >= 0 && dleft < resistance_size &&
3488 dleft < (wright - wleft)) {
3489 dx = offsetrect.left() - frame.rect.width();
3492 // snap right of other window?
3493 else if (dright >= 0 && dright < resistance_size &&
3494 dright < (wright - wleft)) {
3495 dx = offsetrect.right() + 1;
3498 } else { // BScreen::WindowSnap
3499 dleft = abs(wright - offsetrect.left());
3500 dright = abs(wleft - offsetrect.right());
3502 // snap left of other window?
3503 if (dleft < snap_distance && dleft <= dright) {
3504 dx = offsetrect.left() - frame.rect.width();
3507 // snap right of other window?
3508 else if (dright < snap_distance) {
3509 dx = offsetrect.right() + 1;
3515 if (screen->getWindowCornerSnap()) {
3516 // try corner-snap to its other sides
3517 if (snap_to_windows == BScreen::WindowResistance) {
3518 dtop = winrect.top() - wtop;
3519 dbottom = wbottom - winrect.bottom();
3520 if (dtop > 0 && dtop < resistance_size) {
3521 // if we're already past the top edge, then don't provide
3523 if (moving.top() >= winrect.top())
3525 } else if (dbottom > 0 && dbottom < resistance_size) {
3526 // if we're already past the bottom edge, then don't provide
3528 if (moving.bottom() <= winrect.bottom())
3529 dy = winrect.bottom() - frame.rect.height() + 1;
3531 } else { // BScreen::WindowSnap
3532 dtop = abs(wtop - winrect.top());
3533 dbottom = abs(wbottom - winrect.bottom());
3534 if (dtop < snap_distance && dtop <= dbottom)
3536 else if (dbottom < snap_distance)
3537 dy = winrect.bottom() - frame.rect.height() + 1;
3545 // if the windows are on the same plane horizontally
3546 if (wleft >= (signed)(winrect.x() - frame.rect.width() + 1) &&
3547 wleft < (signed)(winrect.x() + winrect.width() - 1)) {
3549 if (snap_to_windows == BScreen::WindowResistance) {
3550 dtop = wbottom - offsetrect.top();
3551 dbottom = offsetrect.bottom() - wtop;
3553 // snap top of other window?
3554 if (dtop >= 0 && dtop < resistance_size && dtop < (wbottom - wtop)) {
3555 dy = offsetrect.top() - frame.rect.height();
3558 // snap bottom of other window?
3559 else if (dbottom >= 0 && dbottom < resistance_size &&
3560 dbottom < (wbottom - wtop)) {
3561 dy = offsetrect.bottom() + 1;
3564 } else { // BScreen::WindowSnap
3565 dtop = abs(wbottom - offsetrect.top());
3566 dbottom = abs(wtop - offsetrect.bottom());
3568 // snap top of other window?
3569 if (dtop < snap_distance && dtop <= dbottom) {
3570 dy = offsetrect.top() - frame.rect.height();
3573 // snap bottom of other window?
3574 else if (dbottom < snap_distance) {
3575 dy = offsetrect.bottom() + 1;
3582 if (screen->getWindowCornerSnap()) {
3583 // try corner-snap to its other sides
3584 if (snap_to_windows == BScreen::WindowResistance) {
3585 dleft = winrect.left() - wleft;
3586 dright = wright - winrect.right();
3587 if (dleft > 0 && dleft < resistance_size) {
3588 // if we're already past the left edge, then don't provide
3590 if (moving.left() >= winrect.left())
3591 dx = winrect.left();
3592 } else if (dright > 0 && dright < resistance_size) {
3593 // if we're already past the right edge, then don't provide
3595 if (moving.right() <= winrect.right())
3596 dx = winrect.right() - frame.rect.width() + 1;
3598 } else { // BScreen::WindowSnap
3599 dleft = abs(wleft - winrect.left());
3600 dright = abs(wright - winrect.right());
3601 if (dleft < snap_distance && dleft <= dright)
3602 dx = winrect.left();
3603 else if (dright < snap_distance)
3604 dx = winrect.right() - frame.rect.width() + 1;
3614 if (snap_to_edges) {
3617 // snap to the screen edges (and screen boundaries for xinerama)
3619 if (screen->isXineramaActive() && blackbox->doXineramaSnapping()) {
3620 rectlist.insert(rectlist.begin(),
3621 screen->getXineramaAreas().begin(),
3622 screen->getXineramaAreas().end());
3625 rectlist.push_back(screen->getRect());
3627 RectList::const_iterator it, end = rectlist.end();
3628 for (it = rectlist.begin(); it != end; ++it) {
3629 const Rect &srect = *it;
3631 offsetrect.setCoords(srect.left() + snap_offset,
3632 srect.top() + snap_offset,
3633 srect.right() - snap_offset,
3634 srect.bottom() - snap_offset);
3636 if (snap_to_edges == BScreen::WindowResistance) {
3637 // if we're not in the rectangle then don't snap to it.
3638 if (! srect.contains(moving))
3640 } else { // BScreen::WindowSnap
3641 // if we're not in the rectangle then don't snap to it.
3642 if (! srect.intersects(Rect(wleft, wtop, frame.rect.width(),
3643 frame.rect.height())))
3647 if (snap_to_edges == BScreen::WindowResistance) {
3648 int dleft = offsetrect.left() - wleft,
3649 dright = wright - offsetrect.right(),
3650 dtop = offsetrect.top() - wtop,
3651 dbottom = wbottom - offsetrect.bottom();
3654 if (dleft > 0 && dleft < resistance_size)
3655 dx = offsetrect.left();
3657 else if (dright > 0 && dright < resistance_size)
3658 dx = offsetrect.right() - frame.rect.width() + 1;
3661 if (dtop > 0 && dtop < resistance_size)
3662 dy = offsetrect.top();
3664 else if (dbottom > 0 && dbottom < resistance_size)
3665 dy = offsetrect.bottom() - frame.rect.height() + 1;
3666 } else { // BScreen::WindowSnap
3667 int dleft = abs(wleft - offsetrect.left()),
3668 dright = abs(wright - offsetrect.right()),
3669 dtop = abs(wtop - offsetrect.top()),
3670 dbottom = abs(wbottom - offsetrect.bottom());
3673 if (dleft < snap_distance && dleft <= dright)
3674 dx = offsetrect.left();
3676 else if (dright < snap_distance)
3677 dx = offsetrect.right() - frame.rect.width() + 1;
3680 if (dtop < snap_distance && dtop <= dbottom)
3681 dy = offsetrect.top();
3683 else if (dbottom < snap_distance)
3684 dy = offsetrect.bottom() - frame.rect.height() + 1;
3691 void BlackboxWindow::endMove(void) {
3692 assert(flags.moving);
3693 assert(blackbox->getChangingWindow() == this);
3695 flags.moving = False;
3696 blackbox->setChangingWindow(0);
3698 if (! screen->doOpaqueMove()) {
3699 /* when drawing the rubber band, we need to make sure we only draw inside
3700 * the frame... frame.changing_* contain the new coords for the window,
3701 * so we need to subtract 1 from changing_w/changing_h every where we
3702 * draw the rubber band (for both moving and resizing)
3704 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
3705 screen->getOpGC(), frame.changing.x(), frame.changing.y(),
3706 frame.changing.width() - 1, frame.changing.height() - 1);
3707 XUngrabServer(blackbox->getXDisplay());
3709 configure(frame.changing.x(), frame.changing.y(),
3710 frame.changing.width(), frame.changing.height());
3712 configure(frame.rect.x(), frame.rect.y(),
3713 frame.rect.width(), frame.rect.height());
3715 screen->hideGeometry();
3717 XUngrabPointer(blackbox->getXDisplay(), CurrentTime);
3719 // if there are any left over motions from the move, drop them now
3720 XSync(blackbox->getXDisplay(), false); // make sure we don't miss any
3722 while (XCheckTypedWindowEvent(blackbox->getXDisplay(), frame.window,
3727 void BlackboxWindow::beginResize(int x_root, int y_root, Corner dir) {
3728 if (! (functions & Func_Resize)) return;
3730 assert(! (flags.resizing || flags.moving));
3733 Only one window can be moved/resized at a time. If another window is
3734 already being moved or resized, then stop it before whating to work with
3737 BlackboxWindow *changing = blackbox->getChangingWindow();
3738 if (changing && changing != this) {
3739 if (changing->flags.moving)
3740 changing->endMove();
3741 else // if (changing->flags.resizing)
3742 changing->endResize();
3750 switch (resize_dir) {
3753 cursor = blackbox->getLowerLeftAngleCursor();
3758 cursor = blackbox->getLowerRightAngleCursor();
3762 anchor = BottomRight;
3763 cursor = blackbox->getUpperLeftAngleCursor();
3767 anchor = BottomLeft;
3768 cursor = blackbox->getUpperRightAngleCursor();
3772 assert(false); // unhandled Corner
3773 return; // unreachable, for the compiler
3776 XGrabServer(blackbox->getXDisplay());
3777 XGrabPointer(blackbox->getXDisplay(), frame.window, False,
3778 PointerMotionMask | ButtonReleaseMask,
3779 GrabModeAsync, GrabModeAsync, None, cursor, CurrentTime);
3781 flags.resizing = True;
3782 blackbox->setChangingWindow(this);
3784 unsigned int gw, gh;
3785 frame.changing = frame.rect;
3787 constrain(anchor, &gw, &gh);
3789 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
3790 screen->getOpGC(), frame.changing.x(), frame.changing.y(),
3791 frame.changing.width() - 1, frame.changing.height() - 1);
3793 screen->showGeometry(gw, gh);
3795 frame.grab_x = x_root;
3796 frame.grab_y = y_root;
3800 void BlackboxWindow::doResize(int x_root, int y_root) {
3801 assert(flags.resizing);
3802 assert(blackbox->getChangingWindow() == this);
3804 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
3805 screen->getOpGC(), frame.changing.x(), frame.changing.y(),
3806 frame.changing.width() - 1, frame.changing.height() - 1);
3808 unsigned int gw, gh;
3810 int dx, dy; // the amount of change in the size of the window
3812 switch (resize_dir) {
3815 dx = - (x_root - frame.grab_x);
3816 dy = + (y_root - frame.grab_y);
3820 dx = + (x_root - frame.grab_x);
3821 dy = + (y_root - frame.grab_y);
3824 anchor = BottomRight;
3825 dx = - (x_root - frame.grab_x);
3826 dy = - (y_root - frame.grab_y);
3829 anchor = BottomLeft;
3830 dx = + (x_root - frame.grab_x);
3831 dy = - (y_root - frame.grab_y);
3835 assert(false); // unhandled Corner
3836 return; // unreachable, for the compiler
3839 // make sure the user cant resize the window smaller than 0, which makes it
3840 // wrap around and become huge
3841 if (dx < -(signed)client.rect.width()) dx = -(signed)client.rect.width();
3842 if (dy < -(signed)client.rect.height()) dy = -(signed)client.rect.height();
3844 frame.changing.setSize(frame.rect.width() + dx, frame.rect.height() + dy);
3846 constrain(anchor, &gw, &gh);
3848 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
3849 screen->getOpGC(), frame.changing.x(), frame.changing.y(),
3850 frame.changing.width() - 1, frame.changing.height() - 1);
3852 screen->showGeometry(gw, gh);
3856 void BlackboxWindow::endResize(void) {
3857 assert(flags.resizing);
3858 assert(blackbox->getChangingWindow() == this);
3860 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
3861 screen->getOpGC(), frame.changing.x(), frame.changing.y(),
3862 frame.changing.width() - 1, frame.changing.height() - 1);
3863 XUngrabServer(blackbox->getXDisplay());
3865 // unset maximized state after resized when fully maximized
3866 if (flags.maximized == 1)
3869 flags.resizing = False;
3870 blackbox->setChangingWindow(0);
3872 configure(frame.changing.x(), frame.changing.y(),
3873 frame.changing.width(), frame.changing.height());
3874 screen->hideGeometry();
3876 XUngrabPointer(blackbox->getXDisplay(), CurrentTime);
3878 // if there are any left over motions from the resize, drop them now
3879 XSync(blackbox->getXDisplay(), false); // make sure we don't miss any
3881 while (XCheckTypedWindowEvent(blackbox->getXDisplay(), frame.window,
3886 void BlackboxWindow::motionNotifyEvent(const XMotionEvent *me) {
3888 fprintf(stderr, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n",
3893 doMove(me->x_root, me->y_root);
3894 } else if (flags.resizing) {
3895 doResize(me->x_root, me->y_root);
3897 if ((functions & Func_Move) &&
3898 (me->state & Button1Mask) &&
3899 (frame.title == me->window || frame.label == me->window ||
3900 frame.handle == me->window || frame.window == me->window)) {
3901 beginMove(me->x_root, me->y_root);
3902 } else if ((functions & Func_Resize) &&
3903 ((me->state & Button1Mask) &&
3904 (me->window == frame.right_grip ||
3905 me->window == frame.left_grip)) ||
3906 ((me->state & Button3Mask) && (me->state & mod_mask) &&
3907 (frame.title == me->window || frame.label == me->window ||
3908 frame.handle == me->window || frame.window == me->window ||
3909 frame.right_grip == me->window ||
3910 frame.left_grip == me->window))) {
3911 unsigned int zones = screen->getResizeZones();
3914 if (me->window == frame.left_grip) {
3915 corner = BottomLeft;
3916 } else if (me->window == frame.right_grip || zones == 1) {
3917 corner = BottomRight;
3920 bool left = (me->x_root - frame.rect.x() <=
3921 static_cast<signed>(frame.rect.width() / 2));
3924 else // (zones == 4)
3925 top = (me->y_root - frame.rect.y() <=
3926 static_cast<signed>(frame.rect.height() / 2));
3927 corner = (top ? (left ? TopLeft : TopRight) :
3928 (left ? BottomLeft : BottomRight));
3931 beginResize(me->x_root, me->y_root, corner);
3937 void BlackboxWindow::enterNotifyEvent(const XCrossingEvent* ce) {
3938 if (! (screen->isSloppyFocus() && isVisible() && isNormal()))
3942 bool leave = False, inferior = False;
3944 while (XCheckTypedWindowEvent(blackbox->getXDisplay(), ce->window,
3946 if (e.type == LeaveNotify && e.xcrossing.mode == NotifyNormal) {
3948 inferior = (e.xcrossing.detail == NotifyInferior);
3952 if (! leave || inferior) {
3953 if (! isFocused()) {
3954 bool success = setInputFocus();
3955 if (success) // if focus succeeded install the colormap
3956 installColormap(True); // XXX: shouldnt we honour no install?
3959 We only auto-raise when the window wasn't focused because otherwise
3960 we run into problems with gtk+ drop-down lists. The window ends up
3961 raising over the list.
3963 if (screen->doAutoRaise())
3970 void BlackboxWindow::leaveNotifyEvent(const XCrossingEvent*) {
3971 if (! (screen->isSloppyFocus() && screen->doAutoRaise() && isNormal()))
3974 installColormap(False);
3976 if (timer->isTiming())
3982 void BlackboxWindow::shapeEvent(XShapeEvent *e) {
3983 if (blackbox->hasShapeExtensions()) {
3984 if (! e->shaped && flags.shaped) {
3986 flags.shaped = False;
3987 } else if (e->shaped) {
3989 flags.shaped = True;
3996 bool BlackboxWindow::validateClient(void) const {
3997 XSync(blackbox->getXDisplay(), False);
4000 if (XCheckTypedWindowEvent(blackbox->getXDisplay(), client.window,
4001 DestroyNotify, &e) ||
4002 XCheckTypedWindowEvent(blackbox->getXDisplay(), client.window,
4004 XPutBackEvent(blackbox->getXDisplay(), &e);
4013 void BlackboxWindow::restore(bool remap) {
4014 XChangeSaveSet(blackbox->getXDisplay(), client.window, SetModeDelete);
4015 XSelectInput(blackbox->getXDisplay(), client.window, NoEventMask);
4016 XSelectInput(blackbox->getXDisplay(), frame.plate, NoEventMask);
4018 // do not leave a shaded window as an icon unless it was an icon
4019 if (flags.shaded && ! flags.iconic)
4020 setState(NormalState);
4022 // erase the netwm stuff that we read when a window maps, so that it
4023 // doesn't persist between mappings.
4024 // (these are the ones read in getNetWMFlags().)
4025 xatom->eraseValue(client.window, XAtom::net_wm_desktop);
4026 xatom->eraseValue(client.window, XAtom::net_wm_state);
4028 restoreGravity(client.rect);
4030 XUnmapWindow(blackbox->getXDisplay(), frame.window);
4031 XUnmapWindow(blackbox->getXDisplay(), client.window);
4033 XSetWindowBorderWidth(blackbox->getXDisplay(), client.window, client.old_bw);
4036 if (XCheckTypedWindowEvent(blackbox->getXDisplay(), client.window,
4037 ReparentNotify, &ev)) {
4040 // according to the ICCCM - if the client doesn't reparent to
4041 // root, then we have to do it for them
4042 XReparentWindow(blackbox->getXDisplay(), client.window,
4043 screen->getRootWindow(),
4044 client.rect.x(), client.rect.y());
4047 if (remap) XMapWindow(blackbox->getXDisplay(), client.window);
4051 // timer for autoraise
4052 void BlackboxWindow::timeout(void) {
4053 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
4057 void BlackboxWindow::changeBlackboxHints(const BlackboxHints *net) {
4058 if ((net->flags & AttribShaded) &&
4059 ((blackbox_attrib.attrib & AttribShaded) !=
4060 (net->attrib & AttribShaded)))
4063 if (flags.visible && // watch out for requests when we can not be seen
4064 (net->flags & (AttribMaxVert | AttribMaxHoriz)) &&
4065 ((blackbox_attrib.attrib & (AttribMaxVert | AttribMaxHoriz)) !=
4066 (net->attrib & (AttribMaxVert | AttribMaxHoriz)))) {
4067 if (flags.maximized) {
4072 if ((net->flags & AttribMaxHoriz) && (net->flags & AttribMaxVert))
4073 button = ((net->attrib & (AttribMaxHoriz | AttribMaxVert)) ? 1 : 0);
4074 else if (net->flags & AttribMaxVert)
4075 button = ((net->attrib & AttribMaxVert) ? 2 : 0);
4076 else if (net->flags & AttribMaxHoriz)
4077 button = ((net->attrib & AttribMaxHoriz) ? 3 : 0);
4083 if ((net->flags & AttribOmnipresent) &&
4084 ((blackbox_attrib.attrib & AttribOmnipresent) !=
4085 (net->attrib & AttribOmnipresent)))
4088 if ((net->flags & AttribWorkspace) &&
4089 (blackbox_attrib.workspace != net->workspace)) {
4090 screen->reassociateWindow(this, net->workspace, True);
4092 if (screen->getCurrentWorkspaceID() != net->workspace) {
4096 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
4100 if (net->flags & AttribDecoration) {
4101 switch (net->decoration) {
4118 * Set the sizes of all components of the window frame
4119 * (the window decorations).
4120 * These values are based upon the current style settings and the client
4121 * window's dimensions.
4123 void BlackboxWindow::upsize(void) {
4124 frame.bevel_w = screen->getBevelWidth();
4126 if (decorations & Decor_Border) {
4127 frame.border_w = screen->getBorderWidth();
4128 if (! isTransient())
4129 frame.mwm_border_w = screen->getFrameWidth();
4131 frame.mwm_border_w = 0;
4133 frame.mwm_border_w = frame.border_w = 0;
4136 if (decorations & Decor_Titlebar) {
4137 // the height of the titlebar is based upon the height of the font being
4138 // used to display the window's title
4139 WindowStyle *style = screen->getWindowStyle();
4140 frame.title_h = style->font->height() + (frame.bevel_w * 2) + 2;
4142 frame.label_h = frame.title_h - (frame.bevel_w * 2);
4143 frame.button_w = (frame.label_h - 2);
4145 // set the top frame margin
4146 frame.margin.top = frame.border_w + frame.title_h +
4147 frame.border_w + frame.mwm_border_w;
4153 // set the top frame margin
4154 frame.margin.top = frame.border_w + frame.mwm_border_w;
4157 // set the left/right frame margin
4158 frame.margin.left = frame.margin.right = frame.border_w + frame.mwm_border_w;
4160 if (decorations & Decor_Handle) {
4161 frame.grip_w = frame.button_w * 2;
4162 frame.handle_h = screen->getHandleWidth();
4164 // set the bottom frame margin
4165 frame.margin.bottom = frame.border_w + frame.handle_h +
4166 frame.border_w + frame.mwm_border_w;
4171 // set the bottom frame margin
4172 frame.margin.bottom = frame.border_w + frame.mwm_border_w;
4176 We first get the normal dimensions and use this to define the inside_w/h
4177 then we modify the height if shading is in effect.
4178 If the shade state is not considered then frame.rect gets reset to the
4179 normal window size on a reconfigure() call resulting in improper
4180 dimensions appearing in move/resize and other events.
4183 height = client.rect.height() + frame.margin.top + frame.margin.bottom,
4184 width = client.rect.width() + frame.margin.left + frame.margin.right;
4186 frame.inside_w = width - (frame.border_w * 2);
4187 frame.inside_h = height - (frame.border_w * 2);
4190 height = frame.title_h + (frame.border_w * 2);
4191 frame.rect.setSize(width, height);
4196 * Calculate the size of the client window and constrain it to the
4197 * size specified by the size hints of the client window.
4199 * The logical width and height are placed into pw and ph, if they
4200 * are non-zero. Logical size refers to the users perception of
4201 * the window size (for example an xterm resizes in cells, not in pixels).
4202 * pw and ph are then used to display the geometry during window moves, resize,
4205 * The physical geometry is placed into frame.changing_{x,y,width,height}.
4206 * Physical geometry refers to the geometry of the window in pixels.
4208 void BlackboxWindow::constrain(Corner anchor,
4209 unsigned int *pw, unsigned int *ph) {
4210 // frame.changing represents the requested frame size, we need to
4211 // strip the frame margin off and constrain the client size
4212 frame.changing.setCoords(frame.changing.left() + frame.margin.left,
4213 frame.changing.top() + frame.margin.top,
4214 frame.changing.right() - frame.margin.right,
4215 frame.changing.bottom() - frame.margin.bottom);
4217 unsigned int dw = frame.changing.width(), dh = frame.changing.height(),
4218 base_width = (client.base_width) ? client.base_width : client.min_width,
4219 base_height = (client.base_height) ? client.base_height :
4222 // constrain, but only if the min/max are being used. if they aren't, then
4223 // this resize is going to be from a ConfigureRequest because the window
4224 // isn't allowed to be resized by the user. And in that case, we don't want
4225 // to limit what the app can do
4226 if (client.max_width > client.min_width ||
4227 client.max_height > client.min_height) {
4228 if (dw < client.min_width) dw = client.min_width;
4229 if (dh < client.min_height) dh = client.min_height;
4230 if (dw > client.max_width) dw = client.max_width;
4231 if (dh > client.max_height) dh = client.max_height;
4234 if (client.width_inc > 1) {
4236 dw /= client.width_inc;
4238 if (client.height_inc > 1) {
4240 dh /= client.height_inc;
4249 if (client.width_inc > 1) {
4250 dw *= client.width_inc;
4253 if (client.height_inc > 1) {
4254 dh *= client.height_inc;
4258 frame.changing.setSize(dw, dh);
4260 // add the frame margin back onto frame.changing
4261 frame.changing.setCoords(frame.changing.left() - frame.margin.left,
4262 frame.changing.top() - frame.margin.top,
4263 frame.changing.right() + frame.margin.right,
4264 frame.changing.bottom() + frame.margin.bottom);
4266 // move frame.changing to the specified anchor
4274 dx = frame.rect.right() - frame.changing.right();
4278 dy = frame.rect.bottom() - frame.changing.bottom();
4282 dx = frame.rect.right() - frame.changing.right();
4283 dy = frame.rect.bottom() - frame.changing.bottom();
4287 assert(false); // unhandled corner
4289 frame.changing.setPos(frame.changing.x() + dx, frame.changing.y() + dy);
4293 void WindowStyle::doJustify(const std::string &text, int &start_pos,
4294 unsigned int max_length,
4295 unsigned int modifier) const {
4296 size_t text_len = text.size();
4297 unsigned int length;
4300 length = font->measureString(string(text, 0, text_len)) + modifier;
4301 } while (length > max_length && text_len-- > 0);
4305 start_pos += max_length - length;
4309 start_pos += (max_length - length) / 2;
4319 BWindowGroup::BWindowGroup(Blackbox *b, Window _group)
4320 : blackbox(b), group(_group) {
4321 XWindowAttributes wattrib;
4322 if (! XGetWindowAttributes(blackbox->getXDisplay(), group, &wattrib)) {
4323 // group window doesn't seem to exist anymore
4328 XSelectInput(blackbox->getXDisplay(), group,
4329 PropertyChangeMask | FocusChangeMask | StructureNotifyMask);
4331 blackbox->saveGroupSearch(group, this);
4335 BWindowGroup::~BWindowGroup(void) {
4336 blackbox->removeGroupSearch(group);
4341 BWindowGroup::find(BScreen *screen, bool allow_transients) const {
4342 BlackboxWindow *ret = blackbox->getFocusedWindow();
4344 // does the focus window match (or any transient_fors)?
4345 for (; ret; ret = ret->getTransientFor()) {
4346 if (ret->getScreen() == screen && ret->getGroupWindow() == group &&
4347 (! ret->isTransient() || allow_transients))
4351 if (ret) return ret;
4353 // the focus window didn't match, look in the group's window list
4354 BlackboxWindowList::const_iterator it, end = windowList.end();
4355 for (it = windowList.begin(); it != end; ++it) {
4357 if (ret->getScreen() == screen && ret->getGroupWindow() == group &&
4358 (! ret->isTransient() || allow_transients))