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"
65 // change this to change what modifier keys openbox uses for mouse bindings
66 // for example: Mod1Mask | ControlMask
67 // or: ControlMask| ShiftMask
68 const unsigned int ModMask = Mod1Mask;
71 * Initializes the class with default values/the window's set initial values.
73 BlackboxWindow::BlackboxWindow(Blackbox *b, Window w, BScreen *s) {
74 // fprintf(stderr, "BlackboxWindow size: %d bytes\n",
75 // sizeof(BlackboxWindow));
78 fprintf(stderr, "BlackboxWindow::BlackboxWindow(): creating 0x%lx\n", w);
82 set timer to zero... it is initialized properly later, so we check
83 if timer is zero in the destructor, and assume that the window is not
84 fully constructed if timer is zero...
90 xatom = blackbox->getXAtom();
92 if (! validateClient()) {
97 // fetch client size and placement
98 XWindowAttributes wattrib;
99 if (! XGetWindowAttributes(blackbox->getXDisplay(),
100 client.window, &wattrib) ||
101 ! wattrib.screen || wattrib.override_redirect) {
104 "BlackboxWindow::BlackboxWindow(): XGetWindowAttributes failed\n");
111 // set the eventmask early in the game so that we make sure we get
112 // all the events we are interested in
113 XSetWindowAttributes attrib_set;
114 attrib_set.event_mask = PropertyChangeMask | FocusChangeMask |
116 attrib_set.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask |
118 XChangeWindowAttributes(blackbox->getXDisplay(), client.window,
119 CWEventMask|CWDontPropagate, &attrib_set);
121 flags.moving = flags.resizing = flags.shaded = flags.visible =
122 flags.iconic = flags.focused = flags.stuck = flags.modal =
123 flags.send_focus_message = flags.shaped = flags.skip_taskbar =
124 flags.skip_pager = flags.fullscreen = False;
127 blackbox_attrib.workspace = window_number = BSENTINEL;
129 blackbox_attrib.flags = blackbox_attrib.attrib = blackbox_attrib.stack
130 = blackbox_attrib.decoration = 0l;
131 blackbox_attrib.premax_x = blackbox_attrib.premax_y = 0;
132 blackbox_attrib.premax_w = blackbox_attrib.premax_h = 0;
135 frame.window = frame.plate = frame.title = frame.handle = None;
136 frame.close_button = frame.iconify_button = frame.maximize_button = None;
137 frame.right_grip = frame.left_grip = None;
139 frame.ulabel_pixel = frame.flabel_pixel = frame.utitle_pixel =
140 frame.ftitle_pixel = frame.uhandle_pixel = frame.fhandle_pixel =
141 frame.ubutton_pixel = frame.fbutton_pixel = frame.pbutton_pixel =
142 frame.uborder_pixel = frame.fborder_pixel = frame.ugrip_pixel =
143 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.pbutton = frame.ugrip = frame.fgrip = None;
148 decorations = Decor_Titlebar | Decor_Border | Decor_Handle |
149 Decor_Iconify | Decor_Maximize;
150 functions = Func_Resize | Func_Move | Func_Iconify | Func_Maximize;
152 client.normal_hint_flags = 0;
153 client.window_group = None;
154 client.transient_for = 0;
156 current_state = NormalState;
161 get 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()) {
185 frame.window = createToplevelWindow();
187 blackbox->saveWindowSearch(frame.window, this);
189 frame.plate = createChildWindow(frame.window);
190 blackbox->saveWindowSearch(frame.plate, this);
192 // determine if this is a transient window
195 // determine the window's type, so we can decide its decorations and
196 // functionality, or if we should not manage it at all
199 // adjust the window decorations/behavior based on the window type
201 switch (window_type) {
208 // none of these windows are decorated or manipulated by the window manager
211 blackbox_attrib.workspace = 0; // we do need to belong to a workspace
212 flags.stuck = True; // we show up on all workspaces
216 // dialogs cannot be maximized, and don't display a handle
217 decorations &= ~(Decor_Maximize | Decor_Handle);
218 functions &= ~Func_Maximize;
222 // normal windows retain all of the possible decorations and functionality
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 decorations &= ~(Decor_Maximize | Decor_Handle);
234 functions &= ~(Func_Resize | Func_Maximize);
237 if (decorations & Decor_Titlebar)
240 if (decorations & Decor_Handle)
243 // apply the size and gravity hint to the frame
247 bool place_window = True;
248 if (blackbox->isStartup() || isTransient() ||
249 client.normal_hint_flags & (PPosition|USPosition)) {
250 applyGravity(frame.rect);
252 if (blackbox->isStartup() || client.rect.intersects(screen->getRect()))
253 place_window = False;
256 // add the window's strut. note this is done *after* placing the window.
257 screen->addStrut(&client.strut);
261 the server needs to be grabbed here to prevent client's from sending
262 events while we are in the process of configuring their window.
263 We hold the grab until after we are done moving the window around.
266 XGrabServer(blackbox->getXDisplay());
268 associateClientWindow();
270 blackbox->saveWindowSearch(client.window, this);
272 if (blackbox_attrib.workspace >= screen->getWorkspaceCount())
273 screen->getCurrentWorkspace()->addWindow(this, place_window);
275 screen->getWorkspace(blackbox_attrib.workspace)->
276 addWindow(this, place_window);
278 if (! place_window) {
279 // don't need to call configure if we are letting the workspace
281 configure(frame.rect.x(), frame.rect.y(),
282 frame.rect.width(), frame.rect.height());
288 XUngrabServer(blackbox->getXDisplay());
291 if (blackbox->hasShapeExtensions() && flags.shaped)
295 // now that we know where to put the window and what it should look like
296 // we apply the decorations
301 XMapSubwindows(blackbox->getXDisplay(), frame.window);
303 // this ensures the title, buttons, and other decor are properly displayed
306 // preserve the window's initial state on first map, and its current state
308 unsigned long initial_state = current_state;
310 current_state = initial_state;
312 // get sticky state from our parent window if we've got one
313 if (isTransient() && client.transient_for != (BlackboxWindow *) ~0ul &&
314 client.transient_for->isStuck() != flags.stuck)
318 flags.shaded = False;
319 initial_state = current_state;
323 At this point in the life of a window, current_state should only be set
324 to IconicState if the window was an *icon*, not if it was shaded.
326 if (initial_state != IconicState)
327 current_state = NormalState;
335 if (flags.maximized && (functions & Func_Maximize))
338 // create this last so it only needs to be configured once
339 windowmenu = new Windowmenu(this);
343 BlackboxWindow::~BlackboxWindow(void) {
345 fprintf(stderr, "BlackboxWindow::~BlackboxWindow: destroying 0x%lx\n",
349 if (! timer) // window not managed...
352 screen->removeStrut(&client.strut);
353 screen->updateAvailableArea();
355 // We don't need to worry about resizing because resizing always grabs the X
356 // server. This should only ever happen if using opaque moving.
364 if (client.window_group) {
365 BWindowGroup *group = blackbox->searchGroup(client.window_group);
366 if (group) group->removeWindow(this);
369 // remove ourselves from our transient_for
371 if (client.transient_for != (BlackboxWindow *) ~0ul)
372 client.transient_for->client.transientList.remove(this);
373 client.transient_for = (BlackboxWindow*) 0;
376 if (client.transientList.size() > 0) {
377 // reset transient_for for all transients
378 BlackboxWindowList::iterator it, end = client.transientList.end();
379 for (it = client.transientList.begin(); it != end; ++it)
380 (*it)->client.transient_for = (BlackboxWindow*) 0;
390 blackbox->removeWindowSearch(frame.plate);
391 XDestroyWindow(blackbox->getXDisplay(), frame.plate);
395 blackbox->removeWindowSearch(frame.window);
396 XDestroyWindow(blackbox->getXDisplay(), frame.window);
399 blackbox->removeWindowSearch(client.window);
404 * Creates a new top level window, with a given location, size, and border
406 * Returns: the newly created window
408 Window BlackboxWindow::createToplevelWindow(void) {
409 XSetWindowAttributes attrib_create;
410 unsigned long create_mask = CWBackPixmap | CWBorderPixel | CWColormap |
411 CWOverrideRedirect | CWEventMask;
413 attrib_create.background_pixmap = None;
414 attrib_create.colormap = screen->getColormap();
415 attrib_create.override_redirect = True;
416 attrib_create.event_mask = ButtonPressMask | ButtonReleaseMask |
418 EnterWindowMask | LeaveWindowMask;
420 return XCreateWindow(blackbox->getXDisplay(), screen->getRootWindow(),
421 0, 0, 1, 1, frame.border_w, screen->getDepth(),
422 InputOutput, screen->getVisual(), create_mask,
428 * Creates a child window, and optionally associates a given cursor with
431 Window BlackboxWindow::createChildWindow(Window parent, Cursor cursor) {
432 XSetWindowAttributes attrib_create;
433 unsigned long create_mask = CWBackPixmap | CWBorderPixel |
436 attrib_create.background_pixmap = None;
437 attrib_create.event_mask = ButtonPressMask | ButtonReleaseMask |
438 ButtonMotionMask | ExposureMask;
441 create_mask |= CWCursor;
442 attrib_create.cursor = cursor;
445 return XCreateWindow(blackbox->getXDisplay(), parent, 0, 0, 1, 1, 0,
446 screen->getDepth(), InputOutput, screen->getVisual(),
447 create_mask, &attrib_create);
451 void BlackboxWindow::associateClientWindow(void) {
452 XSetWindowBorderWidth(blackbox->getXDisplay(), client.window, 0);
456 XChangeSaveSet(blackbox->getXDisplay(), client.window, SetModeInsert);
458 XSelectInput(blackbox->getXDisplay(), frame.plate, SubstructureRedirectMask);
461 note we used to grab around this call to XReparentWindow however the
462 server is now grabbed before this method is called
464 unsigned long event_mask = PropertyChangeMask | FocusChangeMask |
466 XSelectInput(blackbox->getXDisplay(), client.window,
467 event_mask & ~StructureNotifyMask);
468 XReparentWindow(blackbox->getXDisplay(), client.window, frame.plate, 0, 0);
469 XSelectInput(blackbox->getXDisplay(), client.window, event_mask);
471 XRaiseWindow(blackbox->getXDisplay(), frame.plate);
472 XMapSubwindows(blackbox->getXDisplay(), frame.plate);
475 if (blackbox->hasShapeExtensions()) {
476 XShapeSelectInput(blackbox->getXDisplay(), client.window,
483 XShapeQueryExtents(blackbox->getXDisplay(), client.window, &shaped,
484 &foo, &foo, &ufoo, &ufoo, &foo, &foo, &foo,
486 flags.shaped = shaped;
492 void BlackboxWindow::decorate(void) {
495 texture = &(screen->getWindowStyle()->b_focus);
496 frame.fbutton = texture->render(frame.button_w, frame.button_w,
499 frame.fbutton_pixel = texture->color().pixel();
501 texture = &(screen->getWindowStyle()->b_unfocus);
502 frame.ubutton = texture->render(frame.button_w, frame.button_w,
505 frame.ubutton_pixel = texture->color().pixel();
507 texture = &(screen->getWindowStyle()->b_pressed);
508 frame.pbutton = texture->render(frame.button_w, frame.button_w,
511 frame.pbutton_pixel = texture->color().pixel();
513 if (decorations & Decor_Titlebar) {
514 texture = &(screen->getWindowStyle()->t_focus);
515 frame.ftitle = texture->render(frame.inside_w, frame.title_h,
518 frame.ftitle_pixel = texture->color().pixel();
520 texture = &(screen->getWindowStyle()->t_unfocus);
521 frame.utitle = texture->render(frame.inside_w, frame.title_h,
524 frame.utitle_pixel = texture->color().pixel();
526 XSetWindowBorder(blackbox->getXDisplay(), frame.title,
527 screen->getBorderColor()->pixel());
532 if (decorations & Decor_Border) {
533 frame.fborder_pixel = screen->getWindowStyle()->f_focus.pixel();
534 frame.uborder_pixel = screen->getWindowStyle()->f_unfocus.pixel();
535 blackbox_attrib.flags |= AttribDecoration;
536 blackbox_attrib.decoration = DecorNormal;
538 blackbox_attrib.flags |= AttribDecoration;
539 blackbox_attrib.decoration = DecorNone;
542 if (decorations & Decor_Handle) {
543 texture = &(screen->getWindowStyle()->h_focus);
544 frame.fhandle = texture->render(frame.inside_w, frame.handle_h,
547 frame.fhandle_pixel = texture->color().pixel();
549 texture = &(screen->getWindowStyle()->h_unfocus);
550 frame.uhandle = texture->render(frame.inside_w, frame.handle_h,
553 frame.uhandle_pixel = texture->color().pixel();
555 texture = &(screen->getWindowStyle()->g_focus);
556 frame.fgrip = texture->render(frame.grip_w, frame.handle_h, frame.fgrip);
558 frame.fgrip_pixel = texture->color().pixel();
560 texture = &(screen->getWindowStyle()->g_unfocus);
561 frame.ugrip = texture->render(frame.grip_w, frame.handle_h, frame.ugrip);
563 frame.ugrip_pixel = texture->color().pixel();
565 XSetWindowBorder(blackbox->getXDisplay(), frame.handle,
566 screen->getBorderColor()->pixel());
567 XSetWindowBorder(blackbox->getXDisplay(), frame.left_grip,
568 screen->getBorderColor()->pixel());
569 XSetWindowBorder(blackbox->getXDisplay(), frame.right_grip,
570 screen->getBorderColor()->pixel());
573 XSetWindowBorder(blackbox->getXDisplay(), frame.window,
574 screen->getBorderColor()->pixel());
578 void BlackboxWindow::decorateLabel(void) {
581 texture = &(screen->getWindowStyle()->l_focus);
582 frame.flabel = texture->render(frame.label_w, frame.label_h, frame.flabel);
584 frame.flabel_pixel = texture->color().pixel();
586 texture = &(screen->getWindowStyle()->l_unfocus);
587 frame.ulabel = texture->render(frame.label_w, frame.label_h, frame.ulabel);
589 frame.ulabel_pixel = texture->color().pixel();
593 void BlackboxWindow::createHandle(void) {
594 frame.handle = createChildWindow(frame.window);
595 blackbox->saveWindowSearch(frame.handle, this);
598 createChildWindow(frame.handle, blackbox->getLowerLeftAngleCursor());
599 blackbox->saveWindowSearch(frame.left_grip, this);
602 createChildWindow(frame.handle, blackbox->getLowerRightAngleCursor());
603 blackbox->saveWindowSearch(frame.right_grip, this);
607 void BlackboxWindow::destroyHandle(void) {
609 screen->getImageControl()->removeImage(frame.fhandle);
612 screen->getImageControl()->removeImage(frame.uhandle);
615 screen->getImageControl()->removeImage(frame.fgrip);
618 screen->getImageControl()->removeImage(frame.ugrip);
620 blackbox->removeWindowSearch(frame.left_grip);
621 blackbox->removeWindowSearch(frame.right_grip);
623 XDestroyWindow(blackbox->getXDisplay(), frame.left_grip);
624 XDestroyWindow(blackbox->getXDisplay(), frame.right_grip);
625 frame.left_grip = frame.right_grip = None;
627 blackbox->removeWindowSearch(frame.handle);
628 XDestroyWindow(blackbox->getXDisplay(), frame.handle);
633 void BlackboxWindow::createTitlebar(void) {
634 frame.title = createChildWindow(frame.window);
635 frame.label = createChildWindow(frame.title);
636 blackbox->saveWindowSearch(frame.title, this);
637 blackbox->saveWindowSearch(frame.label, this);
639 if (decorations & Decor_Iconify) createIconifyButton();
640 if (decorations & Decor_Maximize) createMaximizeButton();
641 if (decorations & Decor_Close) createCloseButton();
645 void BlackboxWindow::destroyTitlebar(void) {
646 if (frame.close_button)
647 destroyCloseButton();
649 if (frame.iconify_button)
650 destroyIconifyButton();
652 if (frame.maximize_button)
653 destroyMaximizeButton();
656 screen->getImageControl()->removeImage(frame.ftitle);
659 screen->getImageControl()->removeImage(frame.utitle);
662 screen->getImageControl()->removeImage(frame.flabel);
665 screen->getImageControl()->removeImage(frame.ulabel);
668 screen->getImageControl()->removeImage(frame.fbutton);
671 screen->getImageControl()->removeImage(frame.ubutton);
674 screen->getImageControl()->removeImage(frame.pbutton);
676 blackbox->removeWindowSearch(frame.title);
677 blackbox->removeWindowSearch(frame.label);
679 XDestroyWindow(blackbox->getXDisplay(), frame.label);
680 XDestroyWindow(blackbox->getXDisplay(), frame.title);
681 frame.title = frame.label = None;
685 void BlackboxWindow::createCloseButton(void) {
686 if (frame.title != None) {
687 frame.close_button = createChildWindow(frame.title);
688 blackbox->saveWindowSearch(frame.close_button, this);
693 void BlackboxWindow::destroyCloseButton(void) {
694 blackbox->removeWindowSearch(frame.close_button);
695 XDestroyWindow(blackbox->getXDisplay(), frame.close_button);
696 frame.close_button = None;
700 void BlackboxWindow::createIconifyButton(void) {
701 if (frame.title != None) {
702 frame.iconify_button = createChildWindow(frame.title);
703 blackbox->saveWindowSearch(frame.iconify_button, this);
708 void BlackboxWindow::destroyIconifyButton(void) {
709 blackbox->removeWindowSearch(frame.iconify_button);
710 XDestroyWindow(blackbox->getXDisplay(), frame.iconify_button);
711 frame.iconify_button = None;
715 void BlackboxWindow::createMaximizeButton(void) {
716 if (frame.title != None) {
717 frame.maximize_button = createChildWindow(frame.title);
718 blackbox->saveWindowSearch(frame.maximize_button, this);
723 void BlackboxWindow::destroyMaximizeButton(void) {
724 blackbox->removeWindowSearch(frame.maximize_button);
725 XDestroyWindow(blackbox->getXDisplay(), frame.maximize_button);
726 frame.maximize_button = None;
730 void BlackboxWindow::positionButtons(bool redecorate_label) {
731 string layout = blackbox->getTitlebarLayout();
734 bool hasclose, hasiconify, hasmaximize, haslabel;
735 hasclose = hasiconify = hasmaximize = haslabel = false;
737 string::const_iterator it, end;
738 for (it = layout.begin(), end = layout.end(); it != end; ++it) {
741 if (! hasclose && (decorations & Decor_Close)) {
747 if (! hasiconify && (decorations & Decor_Iconify)) {
753 if (! hasmaximize && (decorations & Decor_Maximize)) {
765 if (! hasclose && frame.close_button)
766 destroyCloseButton();
767 if (! hasiconify && frame.iconify_button)
768 destroyIconifyButton();
769 if (! hasmaximize && frame.maximize_button)
770 destroyMaximizeButton();
772 parsed += 'L'; // require that the label be in the layout
774 const unsigned int bsep = frame.bevel_w + 1; // separation between elements
775 const unsigned int by = frame.bevel_w + 1;
776 const unsigned int ty = frame.bevel_w;
778 frame.label_w = frame.inside_w - bsep * 2 -
779 (frame.button_w + bsep) * (parsed.size() - 1);
781 unsigned int x = bsep;
782 for (it = parsed.begin(), end = parsed.end(); it != end; ++it) {
785 if (! frame.close_button) createCloseButton();
786 XMoveResizeWindow(blackbox->getXDisplay(), frame.close_button, x, by,
787 frame.button_w, frame.button_w);
788 x += frame.button_w + bsep;
791 if (! frame.iconify_button) createIconifyButton();
792 XMoveResizeWindow(blackbox->getXDisplay(), frame.iconify_button, x, by,
793 frame.button_w, frame.button_w);
794 x += frame.button_w + bsep;
797 if (! frame.maximize_button) createMaximizeButton();
798 XMoveResizeWindow(blackbox->getXDisplay(), frame.maximize_button, x, by,
799 frame.button_w, frame.button_w);
800 x += frame.button_w + bsep;
803 XMoveResizeWindow(blackbox->getXDisplay(), frame.label, x, ty,
804 frame.label_w, frame.label_h);
805 x += frame.label_w + bsep;
810 if (redecorate_label) decorateLabel();
816 void BlackboxWindow::reconfigure(void) {
817 restoreGravity(client.rect);
819 applyGravity(frame.rect);
828 windowmenu->move(windowmenu->getX(), frame.rect.y() + frame.title_h);
829 windowmenu->reconfigure();
834 void BlackboxWindow::grabButtons(void) {
835 if (! screen->isSloppyFocus() || screen->doClickRaise())
836 // grab button 1 for changing focus/raising
837 blackbox->grabButton(Button1, 0, frame.plate, True, ButtonPressMask,
838 GrabModeSync, GrabModeSync, frame.plate, None,
839 screen->allowScrollLock());
841 if (functions & Func_Move)
842 blackbox->grabButton(Button1, ModMask, frame.window, True,
843 ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
844 GrabModeAsync, frame.window, None,
845 screen->allowScrollLock());
846 if (functions & Func_Resize)
847 blackbox->grabButton(Button3, ModMask, frame.window, True,
848 ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
849 GrabModeAsync, frame.window, None,
850 screen->allowScrollLock());
851 // alt+middle lowers the window
852 blackbox->grabButton(Button2, ModMask, frame.window, True,
853 ButtonReleaseMask, GrabModeAsync, GrabModeAsync,
855 screen->allowScrollLock());
859 void BlackboxWindow::ungrabButtons(void) {
860 blackbox->ungrabButton(Button1, 0, frame.plate);
861 blackbox->ungrabButton(Button1, ModMask, frame.window);
862 blackbox->ungrabButton(Button2, ModMask, frame.window);
863 blackbox->ungrabButton(Button3, ModMask, frame.window);
867 void BlackboxWindow::positionWindows(void) {
868 XMoveResizeWindow(blackbox->getXDisplay(), frame.window,
869 frame.rect.x(), frame.rect.y(), frame.inside_w,
870 (flags.shaded) ? frame.title_h : frame.inside_h);
871 XSetWindowBorderWidth(blackbox->getXDisplay(), frame.window,
873 XSetWindowBorderWidth(blackbox->getXDisplay(), frame.plate,
875 XMoveResizeWindow(blackbox->getXDisplay(), frame.plate,
876 frame.margin.left - frame.mwm_border_w - frame.border_w,
877 frame.margin.top - frame.mwm_border_w - frame.border_w,
878 client.rect.width(), client.rect.height());
879 XMoveResizeWindow(blackbox->getXDisplay(), client.window,
880 0, 0, client.rect.width(), client.rect.height());
881 // ensure client.rect contains the real location
882 client.rect.setPos(frame.rect.left() + frame.margin.left,
883 frame.rect.top() + frame.margin.top);
885 if (decorations & Decor_Titlebar) {
886 if (frame.title == None) createTitlebar();
888 XSetWindowBorderWidth(blackbox->getXDisplay(), frame.title,
890 XMoveResizeWindow(blackbox->getXDisplay(), frame.title, -frame.border_w,
891 -frame.border_w, frame.inside_w, frame.title_h);
894 XMapSubwindows(blackbox->getXDisplay(), frame.title);
895 XMapWindow(blackbox->getXDisplay(), frame.title);
896 } else if (frame.title) {
899 if (decorations & Decor_Handle) {
900 if (frame.handle == None) createHandle();
901 XSetWindowBorderWidth(blackbox->getXDisplay(), frame.handle,
903 XSetWindowBorderWidth(blackbox->getXDisplay(), frame.left_grip,
905 XSetWindowBorderWidth(blackbox->getXDisplay(), frame.right_grip,
908 // use client.rect here so the value is correct even if shaded
909 XMoveResizeWindow(blackbox->getXDisplay(), frame.handle,
911 client.rect.height() + frame.margin.top +
912 frame.mwm_border_w - frame.border_w,
913 frame.inside_w, frame.handle_h);
914 XMoveResizeWindow(blackbox->getXDisplay(), frame.left_grip,
915 -frame.border_w, -frame.border_w,
916 frame.grip_w, frame.handle_h);
917 XMoveResizeWindow(blackbox->getXDisplay(), frame.right_grip,
918 frame.inside_w - frame.grip_w - frame.border_w,
919 -frame.border_w, frame.grip_w, frame.handle_h);
921 XMapSubwindows(blackbox->getXDisplay(), frame.handle);
922 XMapWindow(blackbox->getXDisplay(), frame.handle);
923 } else if (frame.handle) {
926 XSync(blackbox->getXDisplay(), False);
930 void BlackboxWindow::updateStrut(void) {
931 unsigned long num = 4;
933 if (! xatom->getValue(client.window, XAtom::net_wm_strut, XAtom::cardinal,
938 client.strut.left = data[0];
939 client.strut.right = data[1];
940 client.strut.top = data[2];
941 client.strut.bottom = data[3];
943 screen->updateAvailableArea();
950 void BlackboxWindow::getWindowType(void) {
952 if (xatom->getValue(client.window, XAtom::net_wm_window_type, XAtom::atom,
954 if (val == xatom->getAtom(XAtom::net_wm_window_type_desktop))
955 window_type = Type_Desktop;
956 else if (val == xatom->getAtom(XAtom::net_wm_window_type_dock))
957 window_type = Type_Dock;
958 else if (val == xatom->getAtom(XAtom::net_wm_window_type_toolbar))
959 window_type = Type_Toolbar;
960 else if (val == xatom->getAtom(XAtom::net_wm_window_type_menu))
961 window_type = Type_Menu;
962 else if (val == xatom->getAtom(XAtom::net_wm_window_type_utility))
963 window_type = Type_Utility;
964 else if (val == xatom->getAtom(XAtom::net_wm_window_type_splash))
965 window_type = Type_Splash;
966 else if (val == xatom->getAtom(XAtom::net_wm_window_type_dialog))
967 window_type = Type_Dialog;
968 else //if (val[0] == xatom->getAtom(XAtom::net_wm_window_type_normal))
969 window_type = Type_Normal;
974 * the window type hint was not set, which means we either classify ourself
975 * as a normal window or a dialog, depending on if we are a transient.
978 window_type = Type_Dialog;
980 window_type = Type_Normal;
984 void BlackboxWindow::getWMName(void) {
985 if (xatom->getValue(client.window, XAtom::net_wm_name,
986 XAtom::utf8, client.title) &&
987 !client.title.empty()) {
988 xatom->eraseValue(client.window, XAtom::net_wm_visible_name);
991 //fall through to using WM_NAME
992 if (xatom->getValue(client.window, XAtom::wm_name, XAtom::ansi, client.title)
993 && !client.title.empty()) {
994 xatom->eraseValue(client.window, XAtom::net_wm_visible_name);
997 // fall back to an internal default
998 client.title = i18n(WindowSet, WindowUnnamed, "Unnamed");
999 xatom->setValue(client.window, XAtom::net_wm_visible_name, XAtom::utf8,
1004 void BlackboxWindow::getWMIconName(void) {
1005 if (xatom->getValue(client.window, XAtom::net_wm_icon_name,
1006 XAtom::utf8, client.icon_title) &&
1007 !client.icon_title.empty()) {
1008 xatom->eraseValue(client.window, XAtom::net_wm_visible_icon_name);
1011 //fall through to using WM_ICON_NAME
1012 if (xatom->getValue(client.window, XAtom::wm_icon_name, XAtom::ansi,
1013 client.icon_title) &&
1014 !client.icon_title.empty()) {
1015 xatom->eraseValue(client.window, XAtom::net_wm_visible_icon_name);
1018 // fall back to using the main name
1019 client.icon_title = client.title;
1020 xatom->setValue(client.window, XAtom::net_wm_visible_icon_name, XAtom::utf8,
1026 * Retrieve which WM Protocols are supported by the client window.
1027 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
1028 * window's decorations and allow the close behavior.
1029 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
1032 void BlackboxWindow::getWMProtocols(void) {
1036 if (XGetWMProtocols(blackbox->getXDisplay(), client.window,
1037 &proto, &num_return)) {
1038 for (int i = 0; i < num_return; ++i) {
1039 if (proto[i] == xatom->getAtom(XAtom::wm_delete_window)) {
1040 decorations |= Decor_Close;
1041 functions |= Func_Close;
1042 } else if (proto[i] == xatom->getAtom(XAtom::wm_take_focus))
1043 flags.send_focus_message = True;
1044 else if (proto[i] == xatom->getAtom(XAtom::blackbox_structure_messages))
1045 screen->addNetizen(new Netizen(screen, client.window));
1054 * Gets the value of the WM_HINTS property.
1055 * If the property is not set, then use a set of default values.
1057 void BlackboxWindow::getWMHints(void) {
1058 focus_mode = F_Passive;
1060 // remove from current window group
1061 if (client.window_group) {
1062 BWindowGroup *group = blackbox->searchGroup(client.window_group);
1063 if (group) group->removeWindow(this);
1065 client.window_group = None;
1067 XWMHints *wmhint = XGetWMHints(blackbox->getXDisplay(), client.window);
1072 if (wmhint->flags & InputHint) {
1073 if (wmhint->input == True) {
1074 if (flags.send_focus_message)
1075 focus_mode = F_LocallyActive;
1077 if (flags.send_focus_message)
1078 focus_mode = F_GloballyActive;
1080 focus_mode = F_NoInput;
1084 if (wmhint->flags & StateHint)
1085 current_state = wmhint->initial_state;
1087 if (wmhint->flags & WindowGroupHint) {
1088 client.window_group = wmhint->window_group;
1090 // add window to the appropriate group
1091 BWindowGroup *group = blackbox->searchGroup(client.window_group);
1092 if (! group) { // no group found, create it!
1093 new BWindowGroup(blackbox, client.window_group);
1094 group = blackbox->searchGroup(client.window_group);
1097 group->addWindow(this);
1105 * Gets the value of the WM_NORMAL_HINTS property.
1106 * If the property is not set, then use a set of default values.
1108 void BlackboxWindow::getWMNormalHints(void) {
1110 XSizeHints sizehint;
1112 client.min_width = client.min_height =
1113 client.width_inc = client.height_inc = 1;
1114 client.base_width = client.base_height = 0;
1115 client.win_gravity = NorthWestGravity;
1117 client.min_aspect_x = client.min_aspect_y =
1118 client.max_aspect_x = client.max_aspect_y = 1;
1122 use the full screen, not the strut modified size. otherwise when the
1123 availableArea changes max_width/height will be incorrect and lead to odd
1126 const Rect& screen_area = screen->getRect();
1127 client.max_width = screen_area.width();
1128 client.max_height = screen_area.height();
1130 if (! XGetWMNormalHints(blackbox->getXDisplay(), client.window,
1131 &sizehint, &icccm_mask))
1134 client.normal_hint_flags = sizehint.flags;
1136 if (sizehint.flags & PMinSize) {
1137 if (sizehint.min_width >= 0)
1138 client.min_width = sizehint.min_width;
1139 if (sizehint.min_height >= 0)
1140 client.min_height = sizehint.min_height;
1143 if (sizehint.flags & PMaxSize) {
1144 if (sizehint.max_width > static_cast<signed>(client.min_width))
1145 client.max_width = sizehint.max_width;
1147 client.max_width = client.min_width;
1149 if (sizehint.max_height > static_cast<signed>(client.min_height))
1150 client.max_height = sizehint.max_height;
1152 client.max_height = client.min_height;
1155 if (sizehint.flags & PResizeInc) {
1156 client.width_inc = sizehint.width_inc;
1157 client.height_inc = sizehint.height_inc;
1160 #if 0 // we do not support this at the moment
1161 if (sizehint.flags & PAspect) {
1162 client.min_aspect_x = sizehint.min_aspect.x;
1163 client.min_aspect_y = sizehint.min_aspect.y;
1164 client.max_aspect_x = sizehint.max_aspect.x;
1165 client.max_aspect_y = sizehint.max_aspect.y;
1169 if (sizehint.flags & PBaseSize) {
1170 client.base_width = sizehint.base_width;
1171 client.base_height = sizehint.base_height;
1174 if (sizehint.flags & PWinGravity)
1175 client.win_gravity = sizehint.win_gravity;
1180 * Gets the NETWM hints for the class' contained window.
1182 void BlackboxWindow::getNetWMHints(void) {
1183 unsigned long workspace;
1185 if (xatom->getValue(client.window, XAtom::net_wm_desktop, XAtom::cardinal,
1187 if (workspace == 0xffffffff)
1190 blackbox_attrib.workspace = workspace;
1193 unsigned long *state;
1194 unsigned long num = (unsigned) -1;
1195 if (xatom->getValue(client.window, XAtom::net_wm_state, XAtom::atom,
1199 for (unsigned long i = 0; i < num; ++i) {
1200 if (state[i] == xatom->getAtom(XAtom::net_wm_state_modal))
1202 else if (state[i] == xatom->getAtom(XAtom::net_wm_state_shaded))
1203 flags.shaded = True;
1204 else if (state[i] == xatom->getAtom(XAtom::net_wm_state_skip_taskbar))
1205 flags.skip_taskbar = True;
1206 else if (state[i] == xatom->getAtom(XAtom::net_wm_state_skip_pager))
1207 flags.skip_pager = True;
1208 else if (state[i] == xatom->getAtom(XAtom::net_wm_state_fullscreen))
1209 flags.fullscreen = True;
1210 else if (state[i] == xatom->getAtom(XAtom::net_wm_state_hidden))
1211 setState(IconicState);
1212 else if (state[i] == xatom->getAtom(XAtom::net_wm_state_maximized_vert))
1214 else if (state[i] == xatom->getAtom(XAtom::net_wm_state_maximized_horz))
1218 flags.maximized = 1;
1220 flags.maximized = 2;
1222 flags.maximized = 3;
1230 * Gets the MWM hints for the class' contained window.
1231 * This is used while initializing the window to its first state, and not
1233 * Returns: true if the MWM hints are successfully retreived and applied;
1234 * false if they are not.
1236 void BlackboxWindow::getMWMHints(void) {
1240 num = PropMwmHintsElements;
1241 if (! xatom->getValue(client.window, XAtom::motif_wm_hints,
1242 XAtom::motif_wm_hints, num,
1243 (unsigned long **)&mwm_hint))
1245 if (num < PropMwmHintsElements) {
1250 if (mwm_hint->flags & MwmHintsDecorations) {
1251 if (mwm_hint->decorations & MwmDecorAll) {
1252 decorations = Decor_Titlebar | Decor_Handle | Decor_Border |
1253 Decor_Iconify | Decor_Maximize | Decor_Close;
1257 if (mwm_hint->decorations & MwmDecorBorder)
1258 decorations |= Decor_Border;
1259 if (mwm_hint->decorations & MwmDecorHandle)
1260 decorations |= Decor_Handle;
1261 if (mwm_hint->decorations & MwmDecorTitle)
1262 decorations |= Decor_Titlebar;
1263 if (mwm_hint->decorations & MwmDecorIconify)
1264 decorations |= Decor_Iconify;
1265 if (mwm_hint->decorations & MwmDecorMaximize)
1266 decorations |= Decor_Maximize;
1270 if (mwm_hint->flags & MwmHintsFunctions) {
1271 if (mwm_hint->functions & MwmFuncAll) {
1272 functions = Func_Resize | Func_Move | Func_Iconify | Func_Maximize |
1277 if (mwm_hint->functions & MwmFuncResize)
1278 functions |= Func_Resize;
1279 if (mwm_hint->functions & MwmFuncMove)
1280 functions |= Func_Move;
1281 if (mwm_hint->functions & MwmFuncIconify)
1282 functions |= Func_Iconify;
1283 if (mwm_hint->functions & MwmFuncMaximize)
1284 functions |= Func_Maximize;
1285 if (mwm_hint->functions & MwmFuncClose)
1286 functions |= Func_Close;
1294 * Gets the blackbox hints from the class' contained window.
1295 * This is used while initializing the window to its first state, and not
1297 * Returns: true if the hints are successfully retreived and applied; false if
1300 bool BlackboxWindow::getBlackboxHints(void) {
1302 BlackboxHints *blackbox_hint;
1304 num = PropBlackboxHintsElements;
1305 if (! xatom->getValue(client.window, XAtom::blackbox_hints,
1306 XAtom::blackbox_hints, num,
1307 (unsigned long **)&blackbox_hint))
1309 if (num < PropBlackboxHintsElements) {
1310 delete [] blackbox_hint;
1314 if (blackbox_hint->flags & AttribShaded)
1315 flags.shaded = (blackbox_hint->attrib & AttribShaded);
1317 if ((blackbox_hint->flags & AttribMaxHoriz) &&
1318 (blackbox_hint->flags & AttribMaxVert))
1319 flags.maximized = (blackbox_hint->attrib &
1320 (AttribMaxHoriz | AttribMaxVert)) ? 1 : 0;
1321 else if (blackbox_hint->flags & AttribMaxVert)
1322 flags.maximized = (blackbox_hint->attrib & AttribMaxVert) ? 2 : 0;
1323 else if (blackbox_hint->flags & AttribMaxHoriz)
1324 flags.maximized = (blackbox_hint->attrib & AttribMaxHoriz) ? 3 : 0;
1326 if (blackbox_hint->flags & AttribOmnipresent)
1327 flags.stuck = (blackbox_hint->attrib & AttribOmnipresent);
1329 if (blackbox_hint->flags & AttribWorkspace)
1330 blackbox_attrib.workspace = blackbox_hint->workspace;
1332 // if (blackbox_hint->flags & AttribStack)
1333 // don't yet have always on top/bottom for blackbox yet... working
1336 if (blackbox_hint->flags & AttribDecoration) {
1337 switch (blackbox_hint->decoration) {
1343 decorations |= Decor_Titlebar | Decor_Iconify;
1344 decorations &= ~(Decor_Border | Decor_Handle | Decor_Maximize);
1345 functions &= ~(Func_Resize | Func_Maximize);
1350 decorations |= Decor_Titlebar;
1351 decorations &= ~(Decor_Iconify | Decor_Border | Decor_Handle);
1352 functions &= ~(Func_Resize | Func_Maximize | Func_Iconify);
1358 decorations |= Decor_Titlebar | Decor_Border | Decor_Handle |
1359 Decor_Iconify | Decor_Maximize;
1366 delete [] blackbox_hint;
1372 void BlackboxWindow::getTransientInfo(void) {
1373 if (client.transient_for &&
1374 client.transient_for != (BlackboxWindow *) ~0ul) {
1375 // reset transient_for in preparation of looking for a new owner
1376 client.transient_for->client.transientList.remove(this);
1379 // we have no transient_for until we find a new one
1380 client.transient_for = 0;
1383 if (! XGetTransientForHint(blackbox->getXDisplay(), client.window,
1385 // transient_for hint not set
1389 if (trans_for == client.window) {
1390 // wierd client... treat this window as a normal window
1394 if (trans_for == None || trans_for == screen->getRootWindow()) {
1395 // this is an undocumented interpretation of the ICCCM. a transient
1396 // associated with None/Root/itself is assumed to be a modal root
1397 // transient. we don't support the concept of a global transient,
1398 // so we just associate this transient with nothing, and perhaps
1399 // we will add support later for global modality.
1400 client.transient_for = (BlackboxWindow *) ~0ul;
1405 client.transient_for = blackbox->searchWindow(trans_for);
1406 if (! client.transient_for &&
1407 client.window_group && trans_for == client.window_group) {
1408 // no direct transient_for, perhaps this is a group transient?
1409 BWindowGroup *group = blackbox->searchGroup(client.window_group);
1410 if (group) client.transient_for = group->find(screen);
1413 if (! client.transient_for || client.transient_for == this) {
1414 // no transient_for found, or we have a wierd client that wants to be
1415 // a transient for itself, so we treat this window as a normal window
1416 client.transient_for = (BlackboxWindow*) 0;
1420 // Check for a circular transient state: this can lock up Blackbox
1421 // when it tries to find the non-transient window for a transient.
1422 BlackboxWindow *w = this;
1423 while(w->client.transient_for &&
1424 w->client.transient_for != (BlackboxWindow *) ~0ul) {
1425 if(w->client.transient_for == this) {
1426 client.transient_for = (BlackboxWindow*) 0;
1429 w = w->client.transient_for;
1432 if (client.transient_for &&
1433 client.transient_for != (BlackboxWindow *) ~0ul) {
1434 // register ourselves with our new transient_for
1435 client.transient_for->client.transientList.push_back(this);
1436 flags.stuck = client.transient_for->flags.stuck;
1441 BlackboxWindow *BlackboxWindow::getTransientFor(void) const {
1442 if (client.transient_for &&
1443 client.transient_for != (BlackboxWindow*) ~0ul)
1444 return client.transient_for;
1450 * This function is responsible for updating both the client and the frame
1452 * According to the ICCCM a client message is not sent for a resize, only a
1455 void BlackboxWindow::configure(int dx, int dy,
1456 unsigned int dw, unsigned int dh) {
1457 bool send_event = ((frame.rect.x() != dx || frame.rect.y() != dy) &&
1460 if (dw != frame.rect.width() || dh != frame.rect.height()) {
1461 frame.rect.setRect(dx, dy, dw, dh);
1462 frame.inside_w = frame.rect.width() - (frame.border_w * 2);
1463 frame.inside_h = frame.rect.height() - (frame.border_w * 2);
1465 if (frame.rect.right() <= 0 || frame.rect.bottom() <= 0)
1466 frame.rect.setPos(0, 0);
1468 client.rect.setCoords(frame.rect.left() + frame.margin.left,
1469 frame.rect.top() + frame.margin.top,
1470 frame.rect.right() - frame.margin.right,
1471 frame.rect.bottom() - frame.margin.bottom);
1474 if (blackbox->hasShapeExtensions() && flags.shaped) {
1481 redrawWindowFrame();
1483 frame.rect.setPos(dx, dy);
1485 XMoveWindow(blackbox->getXDisplay(), frame.window,
1486 frame.rect.x(), frame.rect.y());
1488 we may have been called just after an opaque window move, so even though
1489 the old coords match the new ones no ConfigureNotify has been sent yet.
1490 There are likely other times when this will be relevant as well.
1492 if (! flags.moving) send_event = True;
1496 // if moving, the update and event will occur when the move finishes
1497 client.rect.setPos(frame.rect.left() + frame.margin.left,
1498 frame.rect.top() + frame.margin.top);
1501 event.type = ConfigureNotify;
1503 event.xconfigure.display = blackbox->getXDisplay();
1504 event.xconfigure.event = client.window;
1505 event.xconfigure.window = client.window;
1506 event.xconfigure.x = client.rect.x();
1507 event.xconfigure.y = client.rect.y();
1508 event.xconfigure.width = client.rect.width();
1509 event.xconfigure.height = client.rect.height();
1510 event.xconfigure.border_width = client.old_bw;
1511 event.xconfigure.above = frame.window;
1512 event.xconfigure.override_redirect = False;
1514 XSendEvent(blackbox->getXDisplay(), client.window, False,
1515 StructureNotifyMask, &event);
1516 screen->updateNetizenConfigNotify(&event);
1517 XFlush(blackbox->getXDisplay());
1523 void BlackboxWindow::configureShape(void) {
1524 XShapeCombineShape(blackbox->getXDisplay(), frame.window, ShapeBounding,
1525 frame.margin.left - frame.border_w,
1526 frame.margin.top - frame.border_w,
1527 client.window, ShapeBounding, ShapeSet);
1530 XRectangle xrect[2];
1532 if (decorations & Decor_Titlebar) {
1533 xrect[0].x = xrect[0].y = -frame.border_w;
1534 xrect[0].width = frame.rect.width();
1535 xrect[0].height = frame.title_h + (frame.border_w * 2);
1539 if (decorations & Decor_Handle) {
1540 xrect[1].x = -frame.border_w;
1541 xrect[1].y = frame.rect.height() - frame.margin.bottom +
1542 frame.mwm_border_w - frame.border_w;
1543 xrect[1].width = frame.rect.width();
1544 xrect[1].height = frame.handle_h + (frame.border_w * 2);
1548 XShapeCombineRectangles(blackbox->getXDisplay(), frame.window,
1549 ShapeBounding, 0, 0, xrect, num,
1550 ShapeUnion, Unsorted);
1555 bool BlackboxWindow::setInputFocus(void) {
1556 if (flags.focused) return True;
1558 assert(flags.stuck || // window must be on the current workspace or sticky
1559 blackbox_attrib.workspace == screen->getCurrentWorkspaceID());
1562 We only do this check for normal windows and dialogs because other windows
1563 do this on purpose, such as kde's kicker, and we don't want to go moving
1566 if (window_type == Type_Normal || window_type == Type_Dialog)
1567 if (! frame.rect.intersects(screen->getRect())) {
1568 // client is outside the screen, move it to the center
1569 configure((screen->getWidth() - frame.rect.width()) / 2,
1570 (screen->getHeight() - frame.rect.height()) / 2,
1571 frame.rect.width(), frame.rect.height());
1574 if (client.transientList.size() > 0) {
1575 // transfer focus to any modal transients
1576 BlackboxWindowList::iterator it, end = client.transientList.end();
1577 for (it = client.transientList.begin(); it != end; ++it)
1578 if ((*it)->flags.modal) return (*it)->setInputFocus();
1582 if (focus_mode == F_LocallyActive || focus_mode == F_Passive) {
1583 XSetInputFocus(blackbox->getXDisplay(), client.window,
1584 RevertToPointerRoot, CurrentTime);
1586 /* we could set the focus to none, since the window doesn't accept focus,
1587 * but we shouldn't set focus to nothing since this would surely make
1593 if (flags.send_focus_message) {
1595 ce.xclient.type = ClientMessage;
1596 ce.xclient.message_type = xatom->getAtom(XAtom::wm_protocols);
1597 ce.xclient.display = blackbox->getXDisplay();
1598 ce.xclient.window = client.window;
1599 ce.xclient.format = 32;
1600 ce.xclient.data.l[0] = xatom->getAtom(XAtom::wm_take_focus);
1601 ce.xclient.data.l[1] = blackbox->getLastTime();
1602 ce.xclient.data.l[2] = 0l;
1603 ce.xclient.data.l[3] = 0l;
1604 ce.xclient.data.l[4] = 0l;
1605 XSendEvent(blackbox->getXDisplay(), client.window, False,
1607 XFlush(blackbox->getXDisplay());
1614 void BlackboxWindow::iconify(void) {
1615 if (flags.iconic) return;
1617 // We don't need to worry about resizing because resizing always grabs the X
1618 // server. This should only ever happen if using opaque moving.
1622 if (windowmenu) windowmenu->hide();
1625 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1626 * we need to clear the event mask on client.window for a split second.
1627 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1628 * split second, leaving us with a ghost window... so, we need to do this
1629 * while the X server is grabbed
1631 unsigned long event_mask = PropertyChangeMask | FocusChangeMask |
1632 StructureNotifyMask;
1633 XGrabServer(blackbox->getXDisplay());
1634 XSelectInput(blackbox->getXDisplay(), client.window,
1635 event_mask & ~StructureNotifyMask);
1636 XUnmapWindow(blackbox->getXDisplay(), client.window);
1637 XSelectInput(blackbox->getXDisplay(), client.window, event_mask);
1638 XUngrabServer(blackbox->getXDisplay());
1640 XUnmapWindow(blackbox->getXDisplay(), frame.window);
1641 flags.visible = False;
1642 flags.iconic = True;
1644 setState(IconicState);
1646 screen->getWorkspace(blackbox_attrib.workspace)->removeWindow(this);
1648 for (unsigned int i = 0; i < screen->getNumberOfWorkspaces(); ++i)
1649 if (i != blackbox_attrib.workspace)
1650 screen->getWorkspace(i)->removeWindow(this, True);
1653 if (isTransient()) {
1654 if (client.transient_for != (BlackboxWindow *) ~0ul &&
1655 ! client.transient_for->flags.iconic) {
1656 // iconify our transient_for
1657 client.transient_for->iconify();
1661 screen->addIcon(this);
1663 if (client.transientList.size() > 0) {
1664 // iconify all transients
1665 BlackboxWindowList::iterator it, end = client.transientList.end();
1666 for (it = client.transientList.begin(); it != end; ++it) {
1667 if (! (*it)->flags.iconic) (*it)->iconify();
1670 screen->updateStackingList();
1674 void BlackboxWindow::show(void) {
1675 flags.visible = True;
1676 flags.iconic = False;
1678 current_state = (flags.shaded) ? IconicState : NormalState;
1679 setState(current_state);
1681 XMapWindow(blackbox->getXDisplay(), client.window);
1682 XMapSubwindows(blackbox->getXDisplay(), frame.window);
1683 XMapWindow(blackbox->getXDisplay(), frame.window);
1688 XTranslateCoordinates(blackbox->getXDisplay(), client.window,
1689 screen->getRootWindow(),
1690 0, 0, &real_x, &real_y, &child);
1691 fprintf(stderr, "%s -- assumed: (%d, %d), real: (%d, %d)\n", getTitle(),
1692 client.rect.left(), client.rect.top(), real_x, real_y);
1693 assert(client.rect.left() == real_x && client.rect.top() == real_y);
1698 void BlackboxWindow::deiconify(bool reassoc, bool raise) {
1699 if (flags.iconic || reassoc)
1700 screen->reassociateWindow(this, BSENTINEL, False);
1701 else if (blackbox_attrib.workspace != screen->getCurrentWorkspaceID())
1706 // reassociate and deiconify all transients
1707 if (reassoc && client.transientList.size() > 0) {
1708 BlackboxWindowList::iterator it, end = client.transientList.end();
1709 for (it = client.transientList.begin(); it != end; ++it)
1710 (*it)->deiconify(True, False);
1714 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
1718 void BlackboxWindow::close(void) {
1720 ce.xclient.type = ClientMessage;
1721 ce.xclient.message_type = xatom->getAtom(XAtom::wm_protocols);
1722 ce.xclient.display = blackbox->getXDisplay();
1723 ce.xclient.window = client.window;
1724 ce.xclient.format = 32;
1725 ce.xclient.data.l[0] = xatom->getAtom(XAtom::wm_delete_window);
1726 ce.xclient.data.l[1] = CurrentTime;
1727 ce.xclient.data.l[2] = 0l;
1728 ce.xclient.data.l[3] = 0l;
1729 ce.xclient.data.l[4] = 0l;
1730 XSendEvent(blackbox->getXDisplay(), client.window, False, NoEventMask, &ce);
1731 XFlush(blackbox->getXDisplay());
1735 void BlackboxWindow::withdraw(void) {
1736 // We don't need to worry about resizing because resizing always grabs the X
1737 // server. This should only ever happen if using opaque moving.
1741 flags.visible = False;
1742 flags.iconic = False;
1744 setState(current_state);
1746 XUnmapWindow(blackbox->getXDisplay(), frame.window);
1748 XGrabServer(blackbox->getXDisplay());
1750 unsigned long event_mask = PropertyChangeMask | FocusChangeMask |
1751 StructureNotifyMask;
1752 XSelectInput(blackbox->getXDisplay(), client.window,
1753 event_mask & ~StructureNotifyMask);
1754 XUnmapWindow(blackbox->getXDisplay(), client.window);
1755 XSelectInput(blackbox->getXDisplay(), client.window, event_mask);
1757 XUngrabServer(blackbox->getXDisplay());
1759 if (windowmenu) windowmenu->hide();
1763 void BlackboxWindow::maximize(unsigned int button) {
1764 // We don't need to worry about resizing because resizing always grabs the X
1765 // server. This should only ever happen if using opaque moving.
1769 // handle case where menu is open then the max button is used instead
1770 if (windowmenu && windowmenu->isVisible()) windowmenu->hide();
1772 if (flags.maximized) {
1773 flags.maximized = 0;
1775 blackbox_attrib.flags &= ! (AttribMaxHoriz | AttribMaxVert);
1776 blackbox_attrib.attrib &= ! (AttribMaxHoriz | AttribMaxVert);
1779 when a resize finishes, maximize(0) is called to clear any maximization
1780 flags currently set. Otherwise it still thinks it is maximized.
1781 so we do not need to call configure() because resizing will handle it
1783 if (! flags.resizing)
1784 configure(blackbox_attrib.premax_x, blackbox_attrib.premax_y,
1785 blackbox_attrib.premax_w, blackbox_attrib.premax_h);
1787 blackbox_attrib.premax_x = blackbox_attrib.premax_y = 0;
1788 blackbox_attrib.premax_w = blackbox_attrib.premax_h = 0;
1790 redrawAllButtons(); // in case it is not called in configure()
1791 setState(current_state);
1795 blackbox_attrib.premax_x = frame.rect.x();
1796 blackbox_attrib.premax_y = frame.rect.y();
1797 blackbox_attrib.premax_w = frame.rect.width();
1798 // use client.rect so that clients can be restored even if shaded
1799 blackbox_attrib.premax_h =
1800 client.rect.height() + frame.margin.top + frame.margin.bottom;
1803 if (screen->isXineramaActive() && blackbox->doXineramaMaximizing()) {
1804 // find the area to use
1805 RectList availableAreas = screen->allAvailableAreas();
1806 RectList::iterator it, end = availableAreas.end();
1808 for (it = availableAreas.begin(); it != end; ++it)
1809 if (it->intersects(frame.rect)) break;
1810 if (it == end) // the window isn't inside an area
1811 it = availableAreas.begin(); // so just default to the first one
1813 frame.changing = *it;
1816 frame.changing = screen->availableArea();
1820 blackbox_attrib.flags |= AttribMaxHoriz | AttribMaxVert;
1821 blackbox_attrib.attrib |= AttribMaxHoriz | AttribMaxVert;
1825 blackbox_attrib.flags |= AttribMaxVert;
1826 blackbox_attrib.attrib |= AttribMaxVert;
1828 frame.changing.setX(frame.rect.x());
1829 frame.changing.setWidth(frame.rect.width());
1833 blackbox_attrib.flags |= AttribMaxHoriz;
1834 blackbox_attrib.attrib |= AttribMaxHoriz;
1836 frame.changing.setY(frame.rect.y());
1837 frame.changing.setHeight(frame.rect.height());
1844 blackbox_attrib.flags ^= AttribShaded;
1845 blackbox_attrib.attrib ^= AttribShaded;
1846 flags.shaded = False;
1849 flags.maximized = button;
1851 configure(frame.changing.x(), frame.changing.y(),
1852 frame.changing.width(), frame.changing.height());
1854 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
1855 redrawAllButtons(); // in case it is not called in configure()
1856 setState(current_state);
1860 // re-maximizes the window to take into account availableArea changes
1861 void BlackboxWindow::remaximize(void) {
1863 // we only update the window's attributes otherwise we lose the shade bit
1864 switch(flags.maximized) {
1866 blackbox_attrib.flags |= AttribMaxHoriz | AttribMaxVert;
1867 blackbox_attrib.attrib |= AttribMaxHoriz | AttribMaxVert;
1871 blackbox_attrib.flags |= AttribMaxVert;
1872 blackbox_attrib.attrib |= AttribMaxVert;
1876 blackbox_attrib.flags |= AttribMaxHoriz;
1877 blackbox_attrib.attrib |= AttribMaxHoriz;
1883 // save the original dimensions because maximize will wipe them out
1884 int premax_x = blackbox_attrib.premax_x,
1885 premax_y = blackbox_attrib.premax_y,
1886 premax_w = blackbox_attrib.premax_w,
1887 premax_h = blackbox_attrib.premax_h;
1889 unsigned int button = flags.maximized;
1890 flags.maximized = 0; // trick maximize() into working
1893 // restore saved values
1894 blackbox_attrib.premax_x = premax_x;
1895 blackbox_attrib.premax_y = premax_y;
1896 blackbox_attrib.premax_w = premax_w;
1897 blackbox_attrib.premax_h = premax_h;
1901 void BlackboxWindow::setWorkspace(unsigned int n) {
1902 blackbox_attrib.flags |= AttribWorkspace;
1903 blackbox_attrib.workspace = n;
1904 if (n == BSENTINEL) { // iconified window
1906 we set the workspace to 'all workspaces' so that taskbars will show the
1907 window. otherwise, it made uniconifying a window imposible without the
1908 blackbox workspace menu
1912 xatom->setValue(client.window, XAtom::net_wm_desktop, XAtom::cardinal, n);
1916 void BlackboxWindow::shade(void) {
1918 XResizeWindow(blackbox->getXDisplay(), frame.window,
1919 frame.inside_w, frame.inside_h);
1920 flags.shaded = False;
1921 blackbox_attrib.flags ^= AttribShaded;
1922 blackbox_attrib.attrib ^= AttribShaded;
1924 setState(NormalState);
1926 // set the frame rect to the normal size
1927 frame.rect.setHeight(client.rect.height() + frame.margin.top +
1928 frame.margin.bottom);
1930 if (! (decorations & Decor_Titlebar))
1931 return; // can't shade it without a titlebar!
1933 XResizeWindow(blackbox->getXDisplay(), frame.window,
1934 frame.inside_w, frame.title_h);
1935 flags.shaded = True;
1936 blackbox_attrib.flags |= AttribShaded;
1937 blackbox_attrib.attrib |= AttribShaded;
1939 setState(IconicState);
1941 // set the frame rect to the shaded size
1942 frame.rect.setHeight(frame.title_h + (frame.border_w * 2));
1948 * (Un)Sticks a window and its relatives.
1950 void BlackboxWindow::stick(void) {
1952 blackbox_attrib.flags ^= AttribOmnipresent;
1953 blackbox_attrib.attrib ^= AttribOmnipresent;
1955 flags.stuck = False;
1957 for (unsigned int i = 0; i < screen->getNumberOfWorkspaces(); ++i)
1958 if (i != blackbox_attrib.workspace)
1959 screen->getWorkspace(i)->removeWindow(this, True);
1962 screen->reassociateWindow(this, BSENTINEL, True);
1963 // temporary fix since sticky windows suck. set the hint to what we
1964 // actually hold in our data.
1965 xatom->setValue(client.window, XAtom::net_wm_desktop, XAtom::cardinal,
1966 blackbox_attrib.workspace);
1968 setState(current_state);
1972 blackbox_attrib.flags |= AttribOmnipresent;
1973 blackbox_attrib.attrib |= AttribOmnipresent;
1975 // temporary fix since sticky windows suck. set the hint to a different
1976 // value than that contained in the class' data.
1977 xatom->setValue(client.window, XAtom::net_wm_desktop, XAtom::cardinal,
1980 for (unsigned int i = 0; i < screen->getNumberOfWorkspaces(); ++i)
1981 if (i != blackbox_attrib.workspace)
1982 screen->getWorkspace(i)->addWindow(this, False, True);
1984 setState(current_state);
1987 if (isTransient() && client.transient_for != (BlackboxWindow *) ~0ul &&
1988 client.transient_for->isStuck() != flags.stuck)
1989 client.transient_for->stick();
1990 // go down the chain
1991 BlackboxWindowList::iterator it;
1992 const BlackboxWindowList::iterator end = client.transientList.end();
1993 for (it = client.transientList.begin(); it != end; ++it)
1994 if ((*it)->isStuck() != flags.stuck)
1999 void BlackboxWindow::redrawWindowFrame(void) const {
2000 if (decorations & Decor_Titlebar) {
2001 if (flags.focused) {
2003 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2004 frame.title, frame.ftitle);
2006 XSetWindowBackground(blackbox->getXDisplay(),
2007 frame.title, frame.ftitle_pixel);
2010 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2011 frame.title, frame.utitle);
2013 XSetWindowBackground(blackbox->getXDisplay(),
2014 frame.title, frame.utitle_pixel);
2016 XClearWindow(blackbox->getXDisplay(), frame.title);
2022 if (decorations & Decor_Handle) {
2023 if (flags.focused) {
2025 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2026 frame.handle, frame.fhandle);
2028 XSetWindowBackground(blackbox->getXDisplay(),
2029 frame.handle, frame.fhandle_pixel);
2032 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2033 frame.left_grip, frame.fgrip);
2034 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2035 frame.right_grip, frame.fgrip);
2037 XSetWindowBackground(blackbox->getXDisplay(),
2038 frame.left_grip, frame.fgrip_pixel);
2039 XSetWindowBackground(blackbox->getXDisplay(),
2040 frame.right_grip, frame.fgrip_pixel);
2044 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2045 frame.handle, frame.uhandle);
2047 XSetWindowBackground(blackbox->getXDisplay(),
2048 frame.handle, frame.uhandle_pixel);
2051 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2052 frame.left_grip, frame.ugrip);
2053 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2054 frame.right_grip, frame.ugrip);
2056 XSetWindowBackground(blackbox->getXDisplay(),
2057 frame.left_grip, frame.ugrip_pixel);
2058 XSetWindowBackground(blackbox->getXDisplay(),
2059 frame.right_grip, frame.ugrip_pixel);
2062 XClearWindow(blackbox->getXDisplay(), frame.handle);
2063 XClearWindow(blackbox->getXDisplay(), frame.left_grip);
2064 XClearWindow(blackbox->getXDisplay(), frame.right_grip);
2067 if (decorations & Decor_Border) {
2069 XSetWindowBorder(blackbox->getXDisplay(),
2070 frame.plate, frame.fborder_pixel);
2072 XSetWindowBorder(blackbox->getXDisplay(),
2073 frame.plate, frame.uborder_pixel);
2078 void BlackboxWindow::setFocusFlag(bool focus) {
2079 // only focus a window if it is visible
2080 if (focus && ! flags.visible)
2083 flags.focused = focus;
2085 redrawWindowFrame();
2088 blackbox->setFocusedWindow(this);
2090 if (! flags.iconic) {
2091 // iconic windows arent in a workspace menu!
2093 screen->getCurrentWorkspace()->setFocused(this, isFocused());
2095 screen->getWorkspace(blackbox_attrib.workspace)->
2096 setFocused(this, flags.focused);
2101 void BlackboxWindow::installColormap(bool install) {
2102 int i = 0, ncmap = 0;
2103 Colormap *cmaps = XListInstalledColormaps(blackbox->getXDisplay(),
2104 client.window, &ncmap);
2106 XWindowAttributes wattrib;
2107 if (XGetWindowAttributes(blackbox->getXDisplay(),
2108 client.window, &wattrib)) {
2110 // install the window's colormap
2111 for (i = 0; i < ncmap; i++) {
2112 if (*(cmaps + i) == wattrib.colormap)
2113 // this window is using an installed color map... do not install
2116 // otherwise, install the window's colormap
2118 XInstallColormap(blackbox->getXDisplay(), wattrib.colormap);
2120 // uninstall the window's colormap
2121 for (i = 0; i < ncmap; i++) {
2122 if (*(cmaps + i) == wattrib.colormap)
2123 // we found the colormap to uninstall
2124 XUninstallColormap(blackbox->getXDisplay(), wattrib.colormap);
2134 void BlackboxWindow::setAllowedActions(void) {
2138 actions[num++] = xatom->getAtom(XAtom::net_wm_action_shade);
2139 actions[num++] = xatom->getAtom(XAtom::net_wm_action_change_desktop);
2140 actions[num++] = xatom->getAtom(XAtom::net_wm_action_close);
2142 if (functions & Func_Move)
2143 actions[num++] = xatom->getAtom(XAtom::net_wm_action_move);
2144 if (functions & Func_Resize)
2145 actions[num++] = xatom->getAtom(XAtom::net_wm_action_resize);
2146 if (functions & Func_Maximize) {
2147 actions[num++] = xatom->getAtom(XAtom::net_wm_action_maximize_horz);
2148 actions[num++] = xatom->getAtom(XAtom::net_wm_action_maximize_vert);
2151 xatom->setValue(client.window, XAtom::net_wm_allowed_actions, XAtom::atom,
2156 void BlackboxWindow::setState(unsigned long new_state) {
2157 current_state = new_state;
2159 unsigned long state[2];
2160 state[0] = current_state;
2162 xatom->setValue(client.window, XAtom::wm_state, XAtom::wm_state, state, 2);
2164 xatom->setValue(client.window, XAtom::blackbox_attributes,
2165 XAtom::blackbox_attributes, (unsigned long *)&blackbox_attrib,
2166 PropBlackboxAttributesElements);
2171 netstate[num++] = xatom->getAtom(XAtom::net_wm_state_modal);
2173 netstate[num++] = xatom->getAtom(XAtom::net_wm_state_shaded);
2175 netstate[num++] = xatom->getAtom(XAtom::net_wm_state_hidden);
2176 if (flags.skip_taskbar)
2177 netstate[num++] = xatom->getAtom(XAtom::net_wm_state_skip_taskbar);
2178 if (flags.skip_pager)
2179 netstate[num++] = xatom->getAtom(XAtom::net_wm_state_skip_pager);
2180 if (flags.fullscreen)
2181 netstate[num++] = xatom->getAtom(XAtom::net_wm_state_fullscreen);
2182 if (flags.maximized == 1 || flags.maximized == 2)
2183 netstate[num++] = xatom->getAtom(XAtom::net_wm_state_maximized_vert);
2184 if (flags.maximized == 1 || flags.maximized == 3)
2185 netstate[num++] = xatom->getAtom(XAtom::net_wm_state_maximized_horz);
2186 xatom->setValue(client.window, XAtom::net_wm_state, XAtom::atom,
2191 bool BlackboxWindow::getState(void) {
2192 bool ret = xatom->getValue(client.window, XAtom::wm_state, XAtom::wm_state,
2194 if (! ret) current_state = 0;
2199 void BlackboxWindow::restoreAttributes(void) {
2200 unsigned long num = PropBlackboxAttributesElements;
2201 BlackboxAttributes *net;
2202 if (! xatom->getValue(client.window, XAtom::blackbox_attributes,
2203 XAtom::blackbox_attributes, num,
2204 (unsigned long **)&net))
2206 if (num < PropBlackboxAttributesElements) {
2211 if (net->flags & AttribShaded && net->attrib & AttribShaded) {
2212 flags.shaded = False;
2213 unsigned long orig_state = current_state;
2217 At this point in the life of a window, current_state should only be set
2218 to IconicState if the window was an *icon*, not if it was shaded.
2220 if (orig_state != IconicState)
2221 current_state = WithdrawnState;
2224 if (net->workspace != screen->getCurrentWorkspaceID() &&
2225 net->workspace < screen->getWorkspaceCount())
2226 screen->reassociateWindow(this, net->workspace, True);
2228 if ((blackbox_attrib.workspace != screen->getCurrentWorkspaceID()) &&
2229 (blackbox_attrib.workspace < screen->getWorkspaceCount())) {
2230 // set to WithdrawnState so it will be mapped on the new workspace
2231 if (current_state == NormalState) current_state = WithdrawnState;
2232 } else if (current_state == WithdrawnState) {
2233 // the window is on this workspace and is Withdrawn, so it is waiting to
2235 current_state = NormalState;
2238 if (net->flags & AttribOmnipresent && net->attrib & AttribOmnipresent &&
2242 // if the window was on another workspace, it was going to be hidden. this
2243 // specifies that the window should be mapped since it is sticky.
2244 if (current_state == WithdrawnState) current_state = NormalState;
2247 if (net->flags & AttribMaxHoriz || net->flags & AttribMaxVert) {
2248 int x = net->premax_x, y = net->premax_y;
2249 unsigned int w = net->premax_w, h = net->premax_h;
2250 flags.maximized = 0;
2253 if ((net->flags & AttribMaxHoriz) &&
2254 (net->flags & AttribMaxVert))
2255 m = (net->attrib & (AttribMaxHoriz | AttribMaxVert)) ? 1 : 0;
2256 else if (net->flags & AttribMaxVert)
2257 m = (net->attrib & AttribMaxVert) ? 2 : 0;
2258 else if (net->flags & AttribMaxHoriz)
2259 m = (net->attrib & AttribMaxHoriz) ? 3 : 0;
2263 blackbox_attrib.premax_x = x;
2264 blackbox_attrib.premax_y = y;
2265 blackbox_attrib.premax_w = w;
2266 blackbox_attrib.premax_h = h;
2269 if (net->flags & AttribDecoration) {
2270 switch (net->decoration) {
2278 decorations |= Decor_Titlebar | Decor_Handle | Decor_Border |
2279 Decor_Iconify | Decor_Maximize;
2284 decorations |= Decor_Titlebar | Decor_Iconify;
2285 decorations &= ~(Decor_Border | Decor_Handle | Decor_Maximize);
2290 decorations |= Decor_Titlebar;
2291 decorations &= ~(Decor_Iconify | Decor_Border | Decor_Handle);
2296 // sanity check the new decor
2297 if (! (functions & Func_Resize) || isTransient())
2298 decorations &= ~(Decor_Maximize | Decor_Handle);
2299 if (! (functions & Func_Maximize))
2300 decorations &= ~Decor_Maximize;
2302 if (decorations & Decor_Titlebar) {
2303 if (functions & Func_Close) // close button is controlled by function
2304 decorations |= Decor_Close; // not decor type
2306 if (flags.shaded) // we can not be shaded if we lack a titlebar
2310 if (flags.visible && frame.window) {
2311 XMapSubwindows(blackbox->getXDisplay(), frame.window);
2312 XMapWindow(blackbox->getXDisplay(), frame.window);
2316 setState(current_state);
2319 // with the state set it will then be the map event's job to read the
2320 // window's state and behave accordingly
2327 * Positions the Rect r according the the client window position and
2330 void BlackboxWindow::applyGravity(Rect &r) {
2331 // apply horizontal window gravity
2332 switch (client.win_gravity) {
2334 case NorthWestGravity:
2335 case SouthWestGravity:
2337 r.setX(client.rect.x());
2343 r.setX(client.rect.x() - (frame.margin.left + frame.margin.right) / 2);
2346 case NorthEastGravity:
2347 case SouthEastGravity:
2349 r.setX(client.rect.x() - frame.margin.left - frame.margin.right + 2);
2354 r.setX(client.rect.x() - frame.margin.left);
2358 // apply vertical window gravity
2359 switch (client.win_gravity) {
2361 case NorthWestGravity:
2362 case NorthEastGravity:
2364 r.setY(client.rect.y());
2370 r.setY(client.rect.y() - (frame.margin.top + frame.margin.bottom) / 2);
2373 case SouthWestGravity:
2374 case SouthEastGravity:
2376 r.setY(client.rect.y() - frame.margin.top - frame.margin.bottom + 2);
2381 r.setY(client.rect.y() - frame.margin.top);
2388 * The reverse of the applyGravity function.
2390 * Positions the Rect r according to the frame window position and
2393 void BlackboxWindow::restoreGravity(Rect &r) {
2394 // restore horizontal window gravity
2395 switch (client.win_gravity) {
2397 case NorthWestGravity:
2398 case SouthWestGravity:
2400 r.setX(frame.rect.x());
2406 r.setX(frame.rect.x() + (frame.margin.left + frame.margin.right) / 2);
2409 case NorthEastGravity:
2410 case SouthEastGravity:
2412 r.setX(frame.rect.x() + frame.margin.left + frame.margin.right - 2);
2417 r.setX(frame.rect.x() + frame.margin.left);
2421 // restore vertical window gravity
2422 switch (client.win_gravity) {
2424 case NorthWestGravity:
2425 case NorthEastGravity:
2427 r.setY(frame.rect.y());
2433 r.setY(frame.rect.y() + (frame.margin.top + frame.margin.bottom) / 2);
2436 case SouthWestGravity:
2437 case SouthEastGravity:
2439 r.setY(frame.rect.y() + frame.margin.top + frame.margin.bottom - 2);
2444 r.setY(frame.rect.y() + frame.margin.top);
2450 void BlackboxWindow::redrawLabel(void) const {
2451 if (flags.focused) {
2453 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2454 frame.label, frame.flabel);
2456 XSetWindowBackground(blackbox->getXDisplay(),
2457 frame.label, frame.flabel_pixel);
2460 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2461 frame.label, frame.ulabel);
2463 XSetWindowBackground(blackbox->getXDisplay(),
2464 frame.label, frame.ulabel_pixel);
2466 XClearWindow(blackbox->getXDisplay(), frame.label);
2468 WindowStyle *style = screen->getWindowStyle();
2470 int pos = frame.bevel_w * 2;
2471 style->doJustify(client.title.c_str(), pos, frame.label_w, frame.bevel_w * 4);
2472 style->font->drawString(frame.label, pos, 1,
2473 (flags.focused ? style->l_text_focus :
2474 style->l_text_unfocus),
2479 void BlackboxWindow::redrawAllButtons(void) const {
2480 if (frame.iconify_button) redrawIconifyButton(False);
2481 if (frame.maximize_button) redrawMaximizeButton(flags.maximized);
2482 if (frame.close_button) redrawCloseButton(False);
2486 void BlackboxWindow::redrawIconifyButton(bool pressed) const {
2488 if (flags.focused) {
2490 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2491 frame.iconify_button, frame.fbutton);
2493 XSetWindowBackground(blackbox->getXDisplay(),
2494 frame.iconify_button, frame.fbutton_pixel);
2497 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2498 frame.iconify_button, frame.ubutton);
2500 XSetWindowBackground(blackbox->getXDisplay(), frame.iconify_button,
2501 frame.ubutton_pixel);
2505 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2506 frame.iconify_button, frame.pbutton);
2508 XSetWindowBackground(blackbox->getXDisplay(),
2509 frame.iconify_button, frame.pbutton_pixel);
2511 XClearWindow(blackbox->getXDisplay(), frame.iconify_button);
2513 BPen pen((flags.focused) ? screen->getWindowStyle()->b_pic_focus :
2514 screen->getWindowStyle()->b_pic_unfocus);
2515 XDrawRectangle(blackbox->getXDisplay(), frame.iconify_button, pen.gc(),
2516 2, (frame.button_w - 5), (frame.button_w - 5), 2);
2520 void BlackboxWindow::redrawMaximizeButton(bool pressed) const {
2522 if (flags.focused) {
2524 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2525 frame.maximize_button, frame.fbutton);
2527 XSetWindowBackground(blackbox->getXDisplay(), frame.maximize_button,
2528 frame.fbutton_pixel);
2531 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2532 frame.maximize_button, frame.ubutton);
2534 XSetWindowBackground(blackbox->getXDisplay(), frame.maximize_button,
2535 frame.ubutton_pixel);
2539 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2540 frame.maximize_button, frame.pbutton);
2542 XSetWindowBackground(blackbox->getXDisplay(), frame.maximize_button,
2543 frame.pbutton_pixel);
2545 XClearWindow(blackbox->getXDisplay(), frame.maximize_button);
2547 BPen pen((flags.focused) ? screen->getWindowStyle()->b_pic_focus :
2548 screen->getWindowStyle()->b_pic_unfocus);
2549 XDrawRectangle(blackbox->getXDisplay(), frame.maximize_button, pen.gc(),
2550 2, 2, (frame.button_w - 5), (frame.button_w - 5));
2551 XDrawLine(blackbox->getXDisplay(), frame.maximize_button, pen.gc(),
2552 2, 3, (frame.button_w - 3), 3);
2556 void BlackboxWindow::redrawCloseButton(bool pressed) const {
2558 if (flags.focused) {
2560 XSetWindowBackgroundPixmap(blackbox->getXDisplay(), frame.close_button,
2563 XSetWindowBackground(blackbox->getXDisplay(), frame.close_button,
2564 frame.fbutton_pixel);
2567 XSetWindowBackgroundPixmap(blackbox->getXDisplay(), frame.close_button,
2570 XSetWindowBackground(blackbox->getXDisplay(), frame.close_button,
2571 frame.ubutton_pixel);
2575 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2576 frame.close_button, frame.pbutton);
2578 XSetWindowBackground(blackbox->getXDisplay(),
2579 frame.close_button, frame.pbutton_pixel);
2581 XClearWindow(blackbox->getXDisplay(), frame.close_button);
2583 BPen pen((flags.focused) ? screen->getWindowStyle()->b_pic_focus :
2584 screen->getWindowStyle()->b_pic_unfocus);
2585 XDrawLine(blackbox->getXDisplay(), frame.close_button, pen.gc(),
2586 2, 2, (frame.button_w - 3), (frame.button_w - 3));
2587 XDrawLine(blackbox->getXDisplay(), frame.close_button, pen.gc(),
2588 2, (frame.button_w - 3), (frame.button_w - 3), 2);
2592 void BlackboxWindow::mapRequestEvent(const XMapRequestEvent *re) {
2593 if (re->window != client.window)
2597 fprintf(stderr, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2601 switch (current_state) {
2606 case WithdrawnState:
2615 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
2617 if (! blackbox->isStartup()) {
2618 XSync(blackbox->getXDisplay(), False); // make sure the frame is mapped
2619 if (screen->doFocusNew()|| (isTransient() && getTransientFor() &&
2620 getTransientFor()->isFocused())) {
2623 if (screen->getPlacementPolicy() == BScreen::ClickMousePlacement) {
2627 XQueryPointer(blackbox->getXDisplay(), screen->getRootWindow(),
2628 &r, &c, &rx, &ry, &x, &y, &m);
2638 void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent *ue) {
2639 if (ue->window != client.window)
2643 fprintf(stderr, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2647 screen->unmanageWindow(this, False);
2651 void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent *de) {
2652 if (de->window != client.window)
2656 fprintf(stderr, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2660 screen->unmanageWindow(this, False);
2664 void BlackboxWindow::reparentNotifyEvent(const XReparentEvent *re) {
2665 if (re->window != client.window || re->parent == frame.plate)
2669 fprintf(stderr, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2670 "0x%lx.\n", client.window, re->parent);
2675 XPutBackEvent(blackbox->getXDisplay(), &ev);
2676 screen->unmanageWindow(this, True);
2680 void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent *pe) {
2681 if (pe->state == PropertyDelete)
2685 fprintf(stderr, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n",
2691 case XA_WM_CLIENT_MACHINE:
2695 case XA_WM_TRANSIENT_FOR: {
2696 // determine if this is a transient window
2699 // adjust the window decorations based on transience
2700 if (isTransient()) {
2701 decorations &= ~(Decor_Maximize | Decor_Handle);
2702 functions &= ~Func_Maximize;
2703 setAllowedActions();
2714 case XA_WM_ICON_NAME:
2716 if (flags.iconic) screen->propagateWindowName(this);
2719 case XAtom::net_wm_name:
2723 if (decorations & Decor_Titlebar)
2726 screen->propagateWindowName(this);
2729 case XA_WM_NORMAL_HINTS: {
2732 if ((client.normal_hint_flags & PMinSize) &&
2733 (client.normal_hint_flags & PMaxSize)) {
2734 // the window now can/can't resize itself, so the buttons need to be
2737 if (client.max_width <= client.min_width &&
2738 client.max_height <= client.min_height) {
2739 decorations &= ~(Decor_Maximize | Decor_Handle);
2740 functions &= ~(Func_Resize | Func_Maximize);
2742 if (! isTransient()) {
2743 decorations |= Decor_Maximize | Decor_Handle;
2744 functions |= Func_Maximize;
2746 functions |= Func_Resize;
2749 setAllowedActions();
2752 Rect old_rect = frame.rect;
2756 if (old_rect != frame.rect)
2763 if (pe->atom == xatom->getAtom(XAtom::wm_protocols)) {
2766 if ((decorations & Decor_Close) && (! frame.close_button)) {
2767 createCloseButton();
2768 if (decorations & Decor_Titlebar) {
2769 positionButtons(True);
2770 XMapSubwindows(blackbox->getXDisplay(), frame.title);
2772 if (windowmenu) windowmenu->reconfigure();
2774 } else if (pe->atom == xatom->getAtom(XAtom::net_wm_strut)) {
2783 void BlackboxWindow::exposeEvent(const XExposeEvent *ee) {
2785 fprintf(stderr, "BlackboxWindow::exposeEvent() for 0x%lx\n", client.window);
2788 if (frame.label == ee->window && (decorations & Decor_Titlebar))
2790 else if (frame.close_button == ee->window)
2791 redrawCloseButton(False);
2792 else if (frame.maximize_button == ee->window)
2793 redrawMaximizeButton(flags.maximized);
2794 else if (frame.iconify_button == ee->window)
2795 redrawIconifyButton(False);
2799 void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent *cr) {
2800 if (cr->window != client.window || flags.iconic)
2803 if (cr->value_mask & CWBorderWidth)
2804 client.old_bw = cr->border_width;
2806 if (cr->value_mask & (CWX | CWY | CWWidth | CWHeight)) {
2807 Rect req = frame.rect;
2809 if (cr->value_mask & (CWX | CWY)) {
2810 if (cr->value_mask & CWX)
2811 client.rect.setX(cr->x);
2812 if (cr->value_mask & CWY)
2813 client.rect.setY(cr->y);
2818 if (cr->value_mask & CWWidth)
2819 req.setWidth(cr->width + frame.margin.left + frame.margin.right);
2821 if (cr->value_mask & CWHeight)
2822 req.setHeight(cr->height + frame.margin.top + frame.margin.bottom);
2824 configure(req.x(), req.y(), req.width(), req.height());
2827 if (cr->value_mask & CWStackMode && !isDesktop()) {
2828 switch (cr->detail) {
2831 screen->getWorkspace(blackbox_attrib.workspace)->lowerWindow(this);
2837 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
2844 void BlackboxWindow::buttonPressEvent(const XButtonEvent *be) {
2846 fprintf(stderr, "BlackboxWindow::buttonPressEvent() for 0x%lx\n",
2850 if (frame.maximize_button == be->window && be->button <= 3) {
2851 redrawMaximizeButton(True);
2852 } else if (be->button == 1 || (be->button == 3 && be->state == ModMask)) {
2853 if (! flags.focused)
2856 if (frame.iconify_button == be->window) {
2857 redrawIconifyButton(True);
2858 } else if (frame.close_button == be->window) {
2859 redrawCloseButton(True);
2860 } else if (frame.plate == be->window) {
2861 if (windowmenu && windowmenu->isVisible()) windowmenu->hide();
2863 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
2865 XAllowEvents(blackbox->getXDisplay(), ReplayPointer, be->time);
2867 if (frame.title == be->window || frame.label == be->window) {
2868 if (((be->time - lastButtonPressTime) <=
2869 blackbox->getDoubleClickInterval()) ||
2870 (be->state == ControlMask)) {
2871 lastButtonPressTime = 0;
2874 lastButtonPressTime = be->time;
2878 if (windowmenu && windowmenu->isVisible()) windowmenu->hide();
2880 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
2882 } else if (be->button == 2 && (be->window != frame.iconify_button) &&
2883 (be->window != frame.close_button)) {
2884 screen->getWorkspace(blackbox_attrib.workspace)->lowerWindow(this);
2885 } else if (windowmenu && be->button == 3 &&
2886 (frame.title == be->window || frame.label == be->window ||
2887 frame.handle == be->window || frame.window == be->window)) {
2888 if (windowmenu->isVisible()) {
2891 int mx = be->x_root - windowmenu->getWidth() / 2,
2892 my = be->y_root - windowmenu->getHeight() / 2;
2894 // snap the window menu into a corner/side if necessary
2895 int left_edge, right_edge, top_edge, bottom_edge;
2898 the " + (frame.border_w * 2) - 1" bits are to get the proper width
2899 and height of the menu, as the sizes returned by it do not include
2902 left_edge = frame.rect.x();
2903 right_edge = frame.rect.right() -
2904 (windowmenu->getWidth() + (frame.border_w * 2) - 1);
2905 top_edge = client.rect.top() - (frame.border_w + frame.mwm_border_w);
2906 bottom_edge = client.rect.bottom() -
2907 (windowmenu->getHeight() + (frame.border_w * 2) - 1) +
2908 (frame.border_w + frame.mwm_border_w);
2912 if (mx > right_edge)
2916 if (my > bottom_edge)
2919 windowmenu->move(mx, my);
2921 XRaiseWindow(blackbox->getXDisplay(), windowmenu->getWindowID());
2922 XRaiseWindow(blackbox->getXDisplay(),
2923 windowmenu->getSendToMenu()->getWindowID());
2926 } else if (be->button == 4) {
2927 if ((be->window == frame.label ||
2928 be->window == frame.title ||
2929 be->window == frame.maximize_button ||
2930 be->window == frame.iconify_button ||
2931 be->window == frame.close_button) &&
2935 } else if (be->button == 5) {
2936 if ((be->window == frame.label ||
2937 be->window == frame.title ||
2938 be->window == frame.maximize_button ||
2939 be->window == frame.iconify_button ||
2940 be->window == frame.close_button) &&
2947 void BlackboxWindow::buttonReleaseEvent(const XButtonEvent *re) {
2949 fprintf(stderr, "BlackboxWindow::buttonReleaseEvent() for 0x%lx\n",
2953 if (re->window == frame.maximize_button &&
2954 re->button >= 1 && re->button <= 3) {
2955 if ((re->x >= 0 && re->x <= static_cast<signed>(frame.button_w)) &&
2956 (re->y >= 0 && re->y <= static_cast<signed>(frame.button_w))) {
2957 maximize(re->button);
2959 redrawMaximizeButton(flags.maximized);
2961 } else if (re->window == frame.iconify_button && re->button == 1) {
2962 if ((re->x >= 0 && re->x <= static_cast<signed>(frame.button_w)) &&
2963 (re->y >= 0 && re->y <= static_cast<signed>(frame.button_w))) {
2966 redrawIconifyButton(False);
2968 } else if (re->window == frame.close_button & re->button == 1) {
2969 if ((re->x >= 0 && re->x <= static_cast<signed>(frame.button_w)) &&
2970 (re->y >= 0 && re->y <= static_cast<signed>(frame.button_w)))
2972 redrawCloseButton(False);
2973 } else if (flags.moving) {
2975 } else if (flags.resizing) {
2977 } else if (re->window == frame.window) {
2978 if (re->button == 2 && re->state == ModMask)
2979 XUngrabPointer(blackbox->getXDisplay(), CurrentTime);
2985 void BlackboxWindow::beginMove(int x_root, int y_root) {
2986 assert(! (flags.resizing || flags.moving));
2989 Only one window can be moved/resized at a time. If another window is already
2990 being moved or resized, then stop it before whating to work with this one.
2992 BlackboxWindow *changing = blackbox->getChangingWindow();
2993 if (changing && changing != this) {
2994 if (changing->flags.moving)
2995 changing->endMove();
2996 else // if (changing->flags.resizing)
2997 changing->endResize();
3000 XGrabPointer(blackbox->getXDisplay(), frame.window, False,
3001 PointerMotionMask | ButtonReleaseMask,
3002 GrabModeAsync, GrabModeAsync,
3003 None, blackbox->getMoveCursor(), CurrentTime);
3005 if (windowmenu && windowmenu->isVisible())
3008 flags.moving = True;
3009 blackbox->setChangingWindow(this);
3011 if (! screen->doOpaqueMove()) {
3012 XGrabServer(blackbox->getXDisplay());
3014 frame.changing = frame.rect;
3015 screen->showPosition(frame.changing.x(), frame.changing.y());
3017 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
3021 frame.changing.width() - 1,
3022 frame.changing.height() - 1);
3025 frame.grab_x = x_root - frame.rect.x() - frame.border_w;
3026 frame.grab_y = y_root - frame.rect.y() - frame.border_w;
3030 void BlackboxWindow::doMove(int x_root, int y_root) {
3031 assert(flags.moving);
3032 assert(blackbox->getChangingWindow() == this);
3034 int dx = x_root - frame.grab_x, dy = y_root - frame.grab_y;
3035 dx -= frame.border_w;
3036 dy -= frame.border_w;
3038 if (screen->doWorkspaceWarping())
3039 if (doWorkspaceWarping(x_root, y_root, dx, dy))
3042 doWindowSnapping(dx, dy);
3044 if (screen->doOpaqueMove()) {
3045 configure(dx, dy, frame.rect.width(), frame.rect.height());
3047 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
3051 frame.changing.width() - 1,
3052 frame.changing.height() - 1);
3054 frame.changing.setPos(dx, dy);
3056 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
3060 frame.changing.width() - 1,
3061 frame.changing.height() - 1);
3064 screen->showPosition(dx, dy);
3068 bool BlackboxWindow::doWorkspaceWarping(int x_root, int y_root,
3070 // workspace warping
3072 unsigned int dest = screen->getCurrentWorkspaceID();
3076 if (dest > 0) dest--;
3077 else dest = screen->getNumberOfWorkspaces() - 1;
3079 } else if (x_root >= screen->getRect().right()) {
3082 if (dest < screen->getNumberOfWorkspaces() - 1) dest++;
3089 bool focus = flags.focused; // had focus while moving?
3091 screen->reassociateWindow(this, dest, False);
3092 screen->changeWorkspaceID(dest);
3097 If the XWarpPointer is done after the configure, we can end up
3098 grabbing another window, so made sure you do it first.
3102 dest_x = screen->getRect().right() - 1;
3103 XWarpPointer(blackbox->getXDisplay(), None,
3104 screen->getRootWindow(), 0, 0, 0, 0,
3107 configure(dx + (screen->getRect().width() - 1), dy,
3108 frame.rect.width(), frame.rect.height());
3111 XWarpPointer(blackbox->getXDisplay(), None,
3112 screen->getRootWindow(), 0, 0, 0, 0,
3115 configure(dx - (screen->getRect().width() - 1), dy,
3116 frame.rect.width(), frame.rect.height());
3119 beginMove(dest_x, y_root);
3124 void BlackboxWindow::doWindowSnapping(int &dx, int &dy) {
3125 // how much resistance to edges to provide
3126 const int resistance_size = screen->getResistanceSize();
3128 // how far away to snap
3129 const int snap_distance = screen->getSnapThreshold();
3131 // how to snap windows
3132 const int snap_to_windows = screen->getWindowToWindowSnap();
3133 const int snap_to_edges = screen->getWindowToEdgeSnap();
3134 // the amount of space away from the edge to provide resistance/snap
3135 const int snap_offset = screen->getSnapOffset();
3137 // find the geomeetery where the moving window currently is
3138 const Rect &moving = screen->doOpaqueMove() ? frame.rect : frame.changing;
3141 const int wleft = dx,
3142 wright = dx + frame.rect.width() - 1,
3144 wbottom = dy + frame.rect.height() - 1;
3146 if (snap_to_windows) {
3149 Workspace *w = screen->getWorkspace(getWorkspaceNumber());
3152 // add windows on the workspace to the rect list
3153 const BlackboxWindowList& stack_list = w->getStackingList();
3154 BlackboxWindowList::const_iterator st_it, st_end = stack_list.end();
3155 for (st_it = stack_list.begin(); st_it != st_end; ++st_it)
3156 if (*st_it != this) // don't snap to ourself
3157 rectlist.push_back( (*st_it)->frameRect() );
3159 // add the toolbar and the slit to the rect list.
3160 // (only if they are not hidden)
3161 Toolbar *tbar = screen->getToolbar();
3162 Slit *slit = screen->getSlit();
3163 Rect tbar_rect, slit_rect;
3164 unsigned int bwidth = screen->getBorderWidth() * 2;
3166 if (! (screen->doHideToolbar() || tbar->isHidden())) {
3167 tbar_rect.setRect(tbar->getX(), tbar->getY(), tbar->getWidth() + bwidth,
3168 tbar->getHeight() + bwidth);
3169 rectlist.push_back(tbar_rect);
3172 if (! slit->isHidden()) {
3173 slit_rect.setRect(slit->getX(), slit->getY(), slit->getWidth() + bwidth,
3174 slit->getHeight() + bwidth);
3175 rectlist.push_back(slit_rect);
3178 RectList::const_iterator it, end = rectlist.end();
3179 for (it = rectlist.begin(); it != end; ++it) {
3180 bool snapped = False;
3181 const Rect &winrect = *it;
3183 offsetrect.setCoords(winrect.left() - snap_offset,
3184 winrect.top() - snap_offset,
3185 winrect.right() + snap_offset,
3186 winrect.bottom() + snap_offset);
3188 if (snap_to_windows == BScreen::WindowResistance)
3189 // if the window is already over top of this snap target, then
3190 // resistance is futile, so just ignore it
3191 if (winrect.intersects(moving))
3194 int dleft, dright, dtop, dbottom;
3196 // if the windows are in the same plane vertically
3197 if (wtop >= (signed)(winrect.y() - frame.rect.height() + 1) &&
3198 wtop < (signed)(winrect.y() + winrect.height() - 1)) {
3200 if (snap_to_windows == BScreen::WindowResistance) {
3201 dleft = wright - offsetrect.left();
3202 dright = offsetrect.right() - wleft;
3204 // snap left of other window?
3205 if (dleft >= 0 && dleft < resistance_size &&
3206 dleft < (wright - wleft)) {
3207 dx = offsetrect.left() - frame.rect.width();
3210 // snap right of other window?
3211 else if (dright >= 0 && dright < resistance_size &&
3212 dright < (wright - wleft)) {
3213 dx = offsetrect.right() + 1;
3216 } else { // BScreen::WindowSnap
3217 dleft = abs(wright - offsetrect.left());
3218 dright = abs(wleft - offsetrect.right());
3220 // snap left of other window?
3221 if (dleft < snap_distance && dleft <= dright) {
3222 dx = offsetrect.left() - frame.rect.width();
3225 // snap right of other window?
3226 else if (dright < snap_distance) {
3227 dx = offsetrect.right() + 1;
3233 if (screen->getWindowCornerSnap()) {
3234 // try corner-snap to its other sides
3235 if (snap_to_windows == BScreen::WindowResistance) {
3236 dtop = winrect.top() - wtop;
3237 dbottom = wbottom - winrect.bottom();
3238 if (dtop > 0 && dtop < resistance_size) {
3239 // if we're already past the top edge, then don't provide
3241 if (moving.top() >= winrect.top())
3243 } else if (dbottom > 0 && dbottom < resistance_size) {
3244 // if we're already past the bottom edge, then don't provide
3246 if (moving.bottom() <= winrect.bottom())
3247 dy = winrect.bottom() - frame.rect.height() + 1;
3249 } else { // BScreen::WindowSnap
3250 dtop = abs(wtop - winrect.top());
3251 dbottom = abs(wbottom - winrect.bottom());
3252 if (dtop < snap_distance && dtop <= dbottom)
3254 else if (dbottom < snap_distance)
3255 dy = winrect.bottom() - frame.rect.height() + 1;
3263 // if the windows are on the same plane horizontally
3264 if (wleft >= (signed)(winrect.x() - frame.rect.width() + 1) &&
3265 wleft < (signed)(winrect.x() + winrect.width() - 1)) {
3267 if (snap_to_windows == BScreen::WindowResistance) {
3268 dtop = wbottom - offsetrect.top();
3269 dbottom = offsetrect.bottom() - wtop;
3271 // snap top of other window?
3272 if (dtop >= 0 && dtop < resistance_size && dtop < (wbottom - wtop)) {
3273 dy = offsetrect.top() - frame.rect.height();
3276 // snap bottom of other window?
3277 else if (dbottom >= 0 && dbottom < resistance_size &&
3278 dbottom < (wbottom - wtop)) {
3279 dy = offsetrect.bottom() + 1;
3282 } else { // BScreen::WindowSnap
3283 dtop = abs(wbottom - offsetrect.top());
3284 dbottom = abs(wtop - offsetrect.bottom());
3286 // snap top of other window?
3287 if (dtop < snap_distance && dtop <= dbottom) {
3288 dy = offsetrect.top() - frame.rect.height();
3291 // snap bottom of other window?
3292 else if (dbottom < snap_distance) {
3293 dy = offsetrect.bottom() + 1;
3300 if (screen->getWindowCornerSnap()) {
3301 // try corner-snap to its other sides
3302 if (snap_to_windows == BScreen::WindowResistance) {
3303 dleft = winrect.left() - wleft;
3304 dright = wright - winrect.right();
3305 if (dleft > 0 && dleft < resistance_size) {
3306 // if we're already past the left edge, then don't provide
3308 if (moving.left() >= winrect.left())
3309 dx = winrect.left();
3310 } else if (dright > 0 && dright < resistance_size) {
3311 // if we're already past the right edge, then don't provide
3313 if (moving.right() <= winrect.right())
3314 dx = winrect.right() - frame.rect.width() + 1;
3316 } else { // BScreen::WindowSnap
3317 dleft = abs(wleft - winrect.left());
3318 dright = abs(wright - winrect.right());
3319 if (dleft < snap_distance && dleft <= dright)
3320 dx = winrect.left();
3321 else if (dright < snap_distance)
3322 dx = winrect.right() - frame.rect.width() + 1;
3332 if (snap_to_edges) {
3335 // snap to the screen edges (and screen boundaries for xinerama)
3337 if (screen->isXineramaActive() && blackbox->doXineramaSnapping()) {
3338 rectlist.insert(rectlist.begin(),
3339 screen->getXineramaAreas().begin(),
3340 screen->getXineramaAreas().end());
3343 rectlist.push_back(screen->getRect());
3345 RectList::const_iterator it, end = rectlist.end();
3346 for (it = rectlist.begin(); it != end; ++it) {
3347 const Rect &srect = *it;
3349 offsetrect.setCoords(srect.left() + snap_offset,
3350 srect.top() + snap_offset,
3351 srect.right() - snap_offset,
3352 srect.bottom() - snap_offset);
3354 if (snap_to_edges == BScreen::WindowResistance) {
3355 // if we're not in the rectangle then don't snap to it.
3356 if (! srect.contains(moving))
3358 } else { // BScreen::WindowSnap
3359 // if we're not in the rectangle then don't snap to it.
3360 if (! srect.intersects(Rect(wleft, wtop, frame.rect.width(),
3361 frame.rect.height())))
3365 if (snap_to_edges == BScreen::WindowResistance) {
3366 int dleft = offsetrect.left() - wleft,
3367 dright = wright - offsetrect.right(),
3368 dtop = offsetrect.top() - wtop,
3369 dbottom = wbottom - offsetrect.bottom();
3372 if (dleft > 0 && dleft < resistance_size)
3373 dx = offsetrect.left();
3375 else if (dright > 0 && dright < resistance_size)
3376 dx = offsetrect.right() - frame.rect.width() + 1;
3379 if (dtop > 0 && dtop < resistance_size)
3380 dy = offsetrect.top();
3382 else if (dbottom > 0 && dbottom < resistance_size)
3383 dy = offsetrect.bottom() - frame.rect.height() + 1;
3384 } else { // BScreen::WindowSnap
3385 int dleft = abs(wleft - offsetrect.left()),
3386 dright = abs(wright - offsetrect.right()),
3387 dtop = abs(wtop - offsetrect.top()),
3388 dbottom = abs(wbottom - offsetrect.bottom());
3391 if (dleft < snap_distance && dleft <= dright)
3392 dx = offsetrect.left();
3394 else if (dright < snap_distance)
3395 dx = offsetrect.right() - frame.rect.width() + 1;
3398 if (dtop < snap_distance && dtop <= dbottom)
3399 dy = offsetrect.top();
3401 else if (dbottom < snap_distance)
3402 dy = offsetrect.bottom() - frame.rect.height() + 1;
3409 void BlackboxWindow::endMove(void) {
3410 assert(flags.moving);
3411 assert(blackbox->getChangingWindow() == this);
3413 flags.moving = False;
3414 blackbox->setChangingWindow(0);
3416 if (! screen->doOpaqueMove()) {
3417 /* when drawing the rubber band, we need to make sure we only draw inside
3418 * the frame... frame.changing_* contain the new coords for the window,
3419 * so we need to subtract 1 from changing_w/changing_h every where we
3420 * draw the rubber band (for both moving and resizing)
3422 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
3423 screen->getOpGC(), frame.changing.x(), frame.changing.y(),
3424 frame.changing.width() - 1, frame.changing.height() - 1);
3425 XUngrabServer(blackbox->getXDisplay());
3427 configure(frame.changing.x(), frame.changing.y(),
3428 frame.changing.width(), frame.changing.height());
3430 configure(frame.rect.x(), frame.rect.y(),
3431 frame.rect.width(), frame.rect.height());
3433 screen->hideGeometry();
3435 XUngrabPointer(blackbox->getXDisplay(), CurrentTime);
3437 // if there are any left over motions from the move, drop them now
3438 XSync(blackbox->getXDisplay(), false); // make sure we don't miss any
3440 while (XCheckTypedWindowEvent(blackbox->getXDisplay(), frame.window,
3445 void BlackboxWindow::beginResize(int x_root, int y_root, Corner dir) {
3446 assert(! (flags.resizing || flags.moving));
3449 Only one window can be moved/resized at a time. If another window is already
3450 being moved or resized, then stop it before whating to work with this one.
3452 BlackboxWindow *changing = blackbox->getChangingWindow();
3453 if (changing && changing != this) {
3454 if (changing->flags.moving)
3455 changing->endMove();
3456 else // if (changing->flags.resizing)
3457 changing->endResize();
3465 switch (resize_dir) {
3468 cursor = blackbox->getLowerLeftAngleCursor();
3473 cursor = blackbox->getLowerRightAngleCursor();
3477 anchor = BottomRight;
3478 cursor = blackbox->getUpperLeftAngleCursor();
3482 anchor = BottomLeft;
3483 cursor = blackbox->getUpperRightAngleCursor();
3487 assert(false); // unhandled Corner
3488 return; // unreachable, for the compiler
3491 XGrabServer(blackbox->getXDisplay());
3492 XGrabPointer(blackbox->getXDisplay(), frame.window, False,
3493 PointerMotionMask | ButtonReleaseMask,
3494 GrabModeAsync, GrabModeAsync, None, cursor, CurrentTime);
3496 flags.resizing = True;
3497 blackbox->setChangingWindow(this);
3499 unsigned int gw, gh;
3500 frame.changing = frame.rect;
3502 constrain(anchor, &gw, &gh);
3504 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
3505 screen->getOpGC(), frame.changing.x(), frame.changing.y(),
3506 frame.changing.width() - 1, frame.changing.height() - 1);
3508 screen->showGeometry(gw, gh);
3510 frame.grab_x = x_root;
3511 frame.grab_y = y_root;
3515 void BlackboxWindow::doResize(int x_root, int y_root) {
3516 assert(flags.resizing);
3517 assert(blackbox->getChangingWindow() == this);
3519 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
3520 screen->getOpGC(), frame.changing.x(), frame.changing.y(),
3521 frame.changing.width() - 1, frame.changing.height() - 1);
3523 unsigned int gw, gh;
3526 switch (resize_dir) {
3529 frame.changing.setSize(frame.rect.width() - (x_root - frame.grab_x),
3530 frame.rect.height() + (y_root - frame.grab_y));
3534 frame.changing.setSize(frame.rect.width() + (x_root - frame.grab_x),
3535 frame.rect.height() + (y_root - frame.grab_y));
3538 anchor = BottomRight;
3539 frame.changing.setSize(frame.rect.width() - (x_root - frame.grab_x),
3540 frame.rect.height() - (y_root - frame.grab_y));
3543 anchor = BottomLeft;
3544 frame.changing.setSize(frame.rect.width() + (x_root - frame.grab_x),
3545 frame.rect.height() - (y_root - frame.grab_y));
3549 assert(false); // unhandled Corner
3550 return; // unreachable, for the compiler
3553 constrain(anchor, &gw, &gh);
3555 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
3556 screen->getOpGC(), frame.changing.x(), frame.changing.y(),
3557 frame.changing.width() - 1, frame.changing.height() - 1);
3559 screen->showGeometry(gw, gh);
3563 void BlackboxWindow::endResize(void) {
3564 assert(flags.resizing);
3565 assert(blackbox->getChangingWindow() == this);
3567 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
3568 screen->getOpGC(), frame.changing.x(), frame.changing.y(),
3569 frame.changing.width() - 1, frame.changing.height() - 1);
3570 XUngrabServer(blackbox->getXDisplay());
3572 // unset maximized state after resized when fully maximized
3573 if (flags.maximized == 1)
3576 flags.resizing = False;
3577 blackbox->setChangingWindow(0);
3579 configure(frame.changing.x(), frame.changing.y(),
3580 frame.changing.width(), frame.changing.height());
3581 screen->hideGeometry();
3583 XUngrabPointer(blackbox->getXDisplay(), CurrentTime);
3585 // if there are any left over motions from the resize, drop them now
3586 XSync(blackbox->getXDisplay(), false); // make sure we don't miss any
3588 while (XCheckTypedWindowEvent(blackbox->getXDisplay(), frame.window,
3593 void BlackboxWindow::motionNotifyEvent(const XMotionEvent *me) {
3595 fprintf(stderr, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n",
3600 doMove(me->x_root, me->y_root);
3601 } else if (flags.resizing) {
3602 doResize(me->x_root, me->y_root);
3604 if (!flags.resizing && me->state & Button1Mask && (functions & Func_Move) &&
3605 (frame.title == me->window || frame.label == me->window ||
3606 frame.handle == me->window || frame.window == me->window)) {
3607 beginMove(me->x_root, me->y_root);
3608 } else if ((functions & Func_Resize) &&
3609 (me->state & Button1Mask && (me->window == frame.right_grip ||
3610 me->window == frame.left_grip)) ||
3611 (me->state & Button3Mask && me->state & ModMask &&
3612 me->window == frame.window)) {
3613 unsigned int zones = screen->getResizeZones();
3616 if (me->window == frame.left_grip) {
3617 corner = BottomLeft;
3618 } else if (me->window == frame.right_grip || zones == 1) {
3619 corner = BottomRight;
3622 bool left = (me->x_root - frame.rect.x() <=
3623 static_cast<signed>(frame.rect.width() / 2));
3626 else // (zones == 4)
3627 top = (me->y_root - frame.rect.y() <=
3628 static_cast<signed>(frame.rect.height() / 2));
3629 corner = (top ? (left ? TopLeft : TopRight) :
3630 (left ? BottomLeft : BottomRight));
3633 beginResize(me->x_root, me->y_root, corner);
3639 void BlackboxWindow::enterNotifyEvent(const XCrossingEvent* ce) {
3640 if (! (screen->isSloppyFocus() && isVisible() && isNormal()))
3644 bool leave = False, inferior = False;
3646 while (XCheckTypedWindowEvent(blackbox->getXDisplay(), ce->window,
3648 if (e.type == LeaveNotify && e.xcrossing.mode == NotifyNormal) {
3650 inferior = (e.xcrossing.detail == NotifyInferior);
3654 if ((! leave || inferior) && ! isFocused()) {
3655 bool success = setInputFocus();
3656 if (success) // if focus succeeded install the colormap
3657 installColormap(True); // XXX: shouldnt we honour no install?
3660 if (screen->doAutoRaise())
3665 void BlackboxWindow::leaveNotifyEvent(const XCrossingEvent*) {
3666 if (! (screen->isSloppyFocus() && screen->doAutoRaise() && isNormal()))
3669 installColormap(False);
3671 if (timer->isTiming())
3677 void BlackboxWindow::shapeEvent(XShapeEvent *) {
3678 if (blackbox->hasShapeExtensions() && flags.shaped) {
3685 bool BlackboxWindow::validateClient(void) const {
3686 XSync(blackbox->getXDisplay(), False);
3689 if (XCheckTypedWindowEvent(blackbox->getXDisplay(), client.window,
3690 DestroyNotify, &e) ||
3691 XCheckTypedWindowEvent(blackbox->getXDisplay(), client.window,
3693 XPutBackEvent(blackbox->getXDisplay(), &e);
3702 void BlackboxWindow::restore(bool remap) {
3703 XChangeSaveSet(blackbox->getXDisplay(), client.window, SetModeDelete);
3704 XSelectInput(blackbox->getXDisplay(), client.window, NoEventMask);
3705 XSelectInput(blackbox->getXDisplay(), frame.plate, NoEventMask);
3707 // do not leave a shaded window as an icon unless it was an icon
3708 if (flags.shaded && ! flags.iconic)
3709 setState(NormalState);
3711 restoreGravity(client.rect);
3713 XUnmapWindow(blackbox->getXDisplay(), frame.window);
3714 XUnmapWindow(blackbox->getXDisplay(), client.window);
3716 XSetWindowBorderWidth(blackbox->getXDisplay(), client.window, client.old_bw);
3719 if (XCheckTypedWindowEvent(blackbox->getXDisplay(), client.window,
3720 ReparentNotify, &ev)) {
3723 // according to the ICCCM - if the client doesn't reparent to
3724 // root, then we have to do it for them
3725 XReparentWindow(blackbox->getXDisplay(), client.window,
3726 screen->getRootWindow(),
3727 client.rect.x(), client.rect.y());
3730 if (remap) XMapWindow(blackbox->getXDisplay(), client.window);
3734 // timer for autoraise
3735 void BlackboxWindow::timeout(void) {
3736 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
3740 void BlackboxWindow::changeBlackboxHints(const BlackboxHints *net) {
3741 if ((net->flags & AttribShaded) &&
3742 ((blackbox_attrib.attrib & AttribShaded) !=
3743 (net->attrib & AttribShaded)))
3746 if (flags.visible && // watch out for requests when we can not be seen
3747 (net->flags & (AttribMaxVert | AttribMaxHoriz)) &&
3748 ((blackbox_attrib.attrib & (AttribMaxVert | AttribMaxHoriz)) !=
3749 (net->attrib & (AttribMaxVert | AttribMaxHoriz)))) {
3750 if (flags.maximized) {
3755 if ((net->flags & AttribMaxHoriz) && (net->flags & AttribMaxVert))
3756 button = ((net->attrib & (AttribMaxHoriz | AttribMaxVert)) ? 1 : 0);
3757 else if (net->flags & AttribMaxVert)
3758 button = ((net->attrib & AttribMaxVert) ? 2 : 0);
3759 else if (net->flags & AttribMaxHoriz)
3760 button = ((net->attrib & AttribMaxHoriz) ? 3 : 0);
3766 if ((net->flags & AttribOmnipresent) &&
3767 ((blackbox_attrib.attrib & AttribOmnipresent) !=
3768 (net->attrib & AttribOmnipresent)))
3771 if ((net->flags & AttribWorkspace) &&
3772 (blackbox_attrib.workspace != net->workspace)) {
3773 screen->reassociateWindow(this, net->workspace, True);
3775 if (screen->getCurrentWorkspaceID() != net->workspace) {
3779 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
3783 if (net->flags & AttribDecoration) {
3784 switch (net->decoration) {
3792 decorations |= Decor_Titlebar | Decor_Border | Decor_Iconify;
3794 decorations = ((functions & Func_Resize) && !isTransient() ?
3795 decorations | Decor_Handle :
3796 decorations &= ~Decor_Handle);
3797 decorations = (functions & Func_Maximize ?
3798 decorations | Decor_Maximize :
3799 decorations &= ~Decor_Maximize);
3804 decorations |= Decor_Titlebar | Decor_Iconify;
3805 decorations &= ~(Decor_Border | Decor_Handle);
3807 decorations = (functions & Func_Maximize ?
3808 decorations | Decor_Maximize :
3809 decorations &= ~Decor_Maximize);
3814 decorations |= Decor_Titlebar;
3815 decorations &= ~(Decor_Iconify | Decor_Border);
3817 decorations = ((functions & Func_Resize) && !isTransient() ?
3818 decorations | Decor_Handle :
3819 decorations &= ~Decor_Handle);
3820 decorations = (functions & Func_Maximize ?
3821 decorations | Decor_Maximize :
3822 decorations &= ~Decor_Maximize);
3827 // we can not be shaded if we lack a titlebar
3828 if (flags.shaded && ! (decorations & Decor_Titlebar))
3831 if (flags.visible && frame.window) {
3832 XMapSubwindows(blackbox->getXDisplay(), frame.window);
3833 XMapWindow(blackbox->getXDisplay(), frame.window);
3837 setState(current_state);
3843 * Set the sizes of all components of the window frame
3844 * (the window decorations).
3845 * These values are based upon the current style settings and the client
3846 * window's dimensions.
3848 void BlackboxWindow::upsize(void) {
3849 frame.bevel_w = screen->getBevelWidth();
3851 if (decorations & Decor_Border) {
3852 frame.border_w = screen->getBorderWidth();
3853 if (! isTransient())
3854 frame.mwm_border_w = screen->getFrameWidth();
3856 frame.mwm_border_w = 0;
3858 frame.mwm_border_w = frame.border_w = 0;
3861 if (decorations & Decor_Titlebar) {
3862 // the height of the titlebar is based upon the height of the font being
3863 // used to display the window's title
3864 WindowStyle *style = screen->getWindowStyle();
3865 frame.title_h = style->font->height() + (frame.bevel_w * 2) + 2;
3867 frame.label_h = frame.title_h - (frame.bevel_w * 2);
3868 frame.button_w = (frame.label_h - 2);
3870 // set the top frame margin
3871 frame.margin.top = frame.border_w + frame.title_h +
3872 frame.border_w + frame.mwm_border_w;
3878 // set the top frame margin
3879 frame.margin.top = frame.border_w + frame.mwm_border_w;
3882 // set the left/right frame margin
3883 frame.margin.left = frame.margin.right = frame.border_w + frame.mwm_border_w;
3885 if (decorations & Decor_Handle) {
3886 frame.grip_w = frame.button_w * 2;
3887 frame.handle_h = screen->getHandleWidth();
3889 // set the bottom frame margin
3890 frame.margin.bottom = frame.border_w + frame.handle_h +
3891 frame.border_w + frame.mwm_border_w;
3896 // set the bottom frame margin
3897 frame.margin.bottom = frame.border_w + frame.mwm_border_w;
3901 We first get the normal dimensions and use this to define the inside_w/h
3902 then we modify the height if shading is in effect.
3903 If the shade state is not considered then frame.rect gets reset to the
3904 normal window size on a reconfigure() call resulting in improper
3905 dimensions appearing in move/resize and other events.
3908 height = client.rect.height() + frame.margin.top + frame.margin.bottom,
3909 width = client.rect.width() + frame.margin.left + frame.margin.right;
3911 frame.inside_w = width - (frame.border_w * 2);
3912 frame.inside_h = height - (frame.border_w * 2);
3915 height = frame.title_h + (frame.border_w * 2);
3916 frame.rect.setSize(width, height);
3921 * Calculate the size of the client window and constrain it to the
3922 * size specified by the size hints of the client window.
3924 * The logical width and height are placed into pw and ph, if they
3925 * are non-zero. Logical size refers to the users perception of
3926 * the window size (for example an xterm resizes in cells, not in pixels).
3927 * pw and ph are then used to display the geometry during window moves, resize,
3930 * The physical geometry is placed into frame.changing_{x,y,width,height}.
3931 * Physical geometry refers to the geometry of the window in pixels.
3933 void BlackboxWindow::constrain(Corner anchor,
3934 unsigned int *pw, unsigned int *ph) {
3935 // frame.changing represents the requested frame size, we need to
3936 // strip the frame margin off and constrain the client size
3937 frame.changing.setCoords(frame.changing.left() + frame.margin.left,
3938 frame.changing.top() + frame.margin.top,
3939 frame.changing.right() - frame.margin.right,
3940 frame.changing.bottom() - frame.margin.bottom);
3942 unsigned int dw = frame.changing.width(), dh = frame.changing.height(),
3943 base_width = (client.base_width) ? client.base_width : client.min_width,
3944 base_height = (client.base_height) ? client.base_height :
3948 if (dw < client.min_width) dw = client.min_width;
3949 if (dh < client.min_height) dh = client.min_height;
3950 if (dw > client.max_width) dw = client.max_width;
3951 if (dh > client.max_height) dh = client.max_height;
3953 assert(dw >= base_width && dh >= base_height);
3955 if (client.width_inc > 1) {
3957 dw /= client.width_inc;
3959 if (client.height_inc > 1) {
3961 dh /= client.height_inc;
3970 if (client.width_inc > 1) {
3971 dw *= client.width_inc;
3974 if (client.height_inc > 1) {
3975 dh *= client.height_inc;
3979 frame.changing.setSize(dw, dh);
3981 // add the frame margin back onto frame.changing
3982 frame.changing.setCoords(frame.changing.left() - frame.margin.left,
3983 frame.changing.top() - frame.margin.top,
3984 frame.changing.right() + frame.margin.right,
3985 frame.changing.bottom() + frame.margin.bottom);
3987 // move frame.changing to the specified anchor
3995 dx = frame.rect.right() - frame.changing.right();
3999 dy = frame.rect.bottom() - frame.changing.bottom();
4003 dx = frame.rect.right() - frame.changing.right();
4004 dy = frame.rect.bottom() - frame.changing.bottom();
4008 assert(false); // unhandled corner
4010 frame.changing.setPos(frame.changing.x() + dx, frame.changing.y() + dy);
4014 void WindowStyle::doJustify(const std::string &text, int &start_pos,
4015 unsigned int max_length,
4016 unsigned int modifier) const {
4017 size_t text_len = text.size();
4018 unsigned int length;
4021 length = font->measureString(string(text, 0, text_len)) + modifier;
4022 } while (length > max_length && text_len-- > 0);
4026 start_pos += max_length - length;
4030 start_pos += (max_length - length) / 2;
4040 BWindowGroup::BWindowGroup(Blackbox *b, Window _group)
4041 : blackbox(b), group(_group) {
4042 XWindowAttributes wattrib;
4043 if (! XGetWindowAttributes(blackbox->getXDisplay(), group, &wattrib)) {
4044 // group window doesn't seem to exist anymore
4049 XSelectInput(blackbox->getXDisplay(), group,
4050 PropertyChangeMask | FocusChangeMask | StructureNotifyMask);
4052 blackbox->saveGroupSearch(group, this);
4056 BWindowGroup::~BWindowGroup(void) {
4057 blackbox->removeGroupSearch(group);
4062 BWindowGroup::find(BScreen *screen, bool allow_transients) const {
4063 BlackboxWindow *ret = blackbox->getFocusedWindow();
4065 // does the focus window match (or any transient_fors)?
4066 for (; ret; ret = ret->getTransientFor()) {
4067 if (ret->getScreen() == screen && ret->getGroupWindow() == group &&
4068 (! ret->isTransient() || allow_transients))
4072 if (ret) return ret;
4074 // the focus window didn't match, look in the group's window list
4075 BlackboxWindowList::const_iterator it, end = windowList.end();
4076 for (it = windowList.begin(); it != end; ++it) {
4078 if (ret->getScreen() == screen && ret->getGroupWindow() == group &&
4079 (! ret->isTransient() || allow_transients))