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
46 #include "blackbox.hh"
48 #include "Iconmenu.hh"
54 #include "Windowmenu.hh"
55 #include "Workspace.hh"
61 * Initializes the class with default values/the window's set initial values.
63 BlackboxWindow::BlackboxWindow(Blackbox
*b
, Window w
, BScreen
*s
) {
64 // fprintf(stderr, "BlackboxWindow size: %d bytes\n",
65 // sizeof(BlackboxWindow));
68 fprintf(stderr
, "BlackboxWindow::BlackboxWindow(): creating 0x%lx\n", w
);
72 set timer to zero... it is initialized properly later, so we check
73 if timer is zero in the destructor, and assume that the window is not
74 fully constructed if timer is zero...
80 xatom
= blackbox
->getXAtom();
82 if (! validateClient()) {
87 // set the eventmask early in the game so that we make sure we get
88 // all the events we are interested in
89 XSetWindowAttributes attrib_set
;
90 attrib_set
.event_mask
= PropertyChangeMask
| FocusChangeMask
|
92 attrib_set
.do_not_propagate_mask
= ButtonPressMask
| ButtonReleaseMask
|
94 XChangeWindowAttributes(blackbox
->getXDisplay(), client
.window
,
95 CWEventMask
|CWDontPropagate
, &attrib_set
);
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 flags
.moving
= flags
.resizing
= flags
.shaded
= flags
.visible
=
112 flags
.iconic
= flags
.focused
= flags
.stuck
= flags
.modal
=
113 flags
.send_focus_message
= flags
.shaped
= flags
.skip_taskbar
=
114 flags
.skip_pager
= flags
.fullscreen
= False
;
117 blackbox_attrib
.workspace
= window_number
= BSENTINEL
;
119 blackbox_attrib
.flags
= blackbox_attrib
.attrib
= blackbox_attrib
.stack
120 = blackbox_attrib
.decoration
= 0l;
121 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
122 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
125 frame
.window
= frame
.plate
= frame
.title
= frame
.handle
= None
;
126 frame
.close_button
= frame
.iconify_button
= frame
.maximize_button
= None
;
127 frame
.right_grip
= frame
.left_grip
= None
;
129 frame
.ulabel_pixel
= frame
.flabel_pixel
= frame
.utitle_pixel
=
130 frame
.ftitle_pixel
= frame
.uhandle_pixel
= frame
.fhandle_pixel
=
131 frame
.ubutton_pixel
= frame
.fbutton_pixel
= frame
.pbutton_pixel
=
132 frame
.uborder_pixel
= frame
.fborder_pixel
= frame
.ugrip_pixel
=
133 frame
.fgrip_pixel
= 0;
134 frame
.utitle
= frame
.ftitle
= frame
.uhandle
= frame
.fhandle
= None
;
135 frame
.ulabel
= frame
.flabel
= frame
.ubutton
= frame
.fbutton
= None
;
136 frame
.pbutton
= frame
.ugrip
= frame
.fgrip
= decorations
;
138 decorations
= Decor_Titlebar
| Decor_Border
| Decor_Handle
|
139 Decor_Iconify
| Decor_Maximize
;
140 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
142 client
.wm_hint_flags
= client
.normal_hint_flags
= 0;
143 client
.transient_for
= 0;
146 get the initial size and location of client window (relative to the
147 _root window_). This position is the reference point used with the
148 window's gravity to find the window's initial position.
150 client
.rect
.setRect(wattrib
.x
, wattrib
.y
, wattrib
.width
, wattrib
.height
);
151 client
.old_bw
= wattrib
.border_width
;
154 lastButtonPressTime
= 0;
156 timer
= new BTimer(blackbox
, this);
157 timer
->setTimeout(blackbox
->getAutoRaiseDelay());
159 if (! getBlackboxHints()) {
164 // get size, aspect, minimum/maximum size and other hints set by the
170 if (client
.initial_state
== WithdrawnState
) {
171 screen
->getSlit()->addClient(client
.window
);
176 if (isKDESystrayWindow()) {
177 screen
->addSystrayWindow(client
.window
);
182 frame
.window
= createToplevelWindow();
183 frame
.plate
= createChildWindow(frame
.window
);
184 associateClientWindow();
186 blackbox
->saveWindowSearch(frame
.window
, this);
187 blackbox
->saveWindowSearch(frame
.plate
, this);
188 blackbox
->saveWindowSearch(client
.window
, this);
190 screen
->addStrut(&client
.strut
);
193 // determine if this is a transient window
196 // determine the window's type, so we can decide its decorations and
197 // functionality, or if we should not manage it at all
200 // adjust the window decorations/behavior based on the window type
201 switch (window_type
) {
203 // desktop windows are not managed by us, we just make sure they stay on the
208 // docks (such as kicker) cannot be moved, and appear on all workspaces
209 functions
&= ~(Func_Move
);
214 // these windows have minimal decorations, only a titlebar, and cannot
215 // be resized or iconified
216 decorations
&= ~(Decor_Maximize
| Decor_Handle
| Decor_Border
|
218 functions
&= ~(Func_Resize
| Func_Maximize
| Func_Iconify
);
222 // splash screens have no functionality or decorations, they are left up
223 // to the application which created them
229 // dialogs cannot be maximized, and don't display a handle
230 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
231 functions
&= ~Func_Maximize
;
235 // normal windows retain all of the possible decorations and functionality
239 // further adjeust the window's decorations/behavior based on window sizes
240 if ((client
.normal_hint_flags
& PMinSize
) &&
241 (client
.normal_hint_flags
& PMaxSize
) &&
242 client
.max_width
<= client
.min_width
&&
243 client
.max_height
<= client
.min_height
) {
244 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
245 functions
&= ~(Func_Resize
| Func_Maximize
);
251 bool place_window
= True
;
252 if (blackbox
->isStartup() || isTransient() ||
253 client
.normal_hint_flags
& (PPosition
|USPosition
)) {
254 applyGravity(frame
.rect
);
256 if (blackbox
->isStartup() ||
257 client
.rect
.intersects(screen
->availableArea()))
258 place_window
= False
;
261 if (decorations
& Decor_Titlebar
)
264 if (decorations
& Decor_Handle
)
268 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
273 if ((! screen
->isSloppyFocus()) || screen
->doClickRaise()) {
274 // grab button 1 for changing focus/raising
275 blackbox
->grabButton(Button1
, 0, frame
.plate
, True
, ButtonPressMask
,
276 GrabModeSync
, GrabModeSync
, None
, None
);
279 if (functions
& Func_Move
)
280 blackbox
->grabButton(Button1
, Mod1Mask
, frame
.window
, True
,
281 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
282 GrabModeAsync
, frame
.window
,
283 blackbox
->getMoveCursor());
284 blackbox
->grabButton(Button2
, Mod1Mask
, frame
.window
, True
,
285 ButtonReleaseMask
, GrabModeAsync
, GrabModeAsync
,
287 if (functions
& Func_Resize
)
288 blackbox
->grabButton(Button3
, Mod1Mask
, frame
.window
, True
,
289 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
291 blackbox
->getLowerRightAngleCursor());
296 if (decorations
& Decor_Titlebar
)
297 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
298 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
300 windowmenu
= new Windowmenu(this);
302 if (blackbox_attrib
.workspace
>= screen
->getWorkspaceCount())
303 screen
->getCurrentWorkspace()->addWindow(this, place_window
);
305 screen
->getWorkspace(blackbox_attrib
.workspace
)->
306 addWindow(this, place_window
);
308 if (! place_window
) {
309 // don't need to call configure if we are letting the workspace
311 configure(frame
.rect
.x(), frame
.rect
.y(),
312 frame
.rect
.width(), frame
.rect
.height());
315 // preserve the window's initial state on first map, and its current state
318 if (client
.wm_hint_flags
& StateHint
)
319 current_state
= client
.initial_state
;
321 current_state
= NormalState
;
324 // get sticky state from our parent window if we've got one
325 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
326 client
.transient_for
->isStuck() != flags
.stuck
)
330 flags
.shaded
= False
;
334 Because the iconic'ness of shaded windows is lost, we need to set the
335 state to NormalState so that shaded windows on other workspaces will not
336 get shown on the first workspace.
337 At this point in the life of a window, current_state should only be set
338 to IconicState if the window was an *icon*, not if it was shaded.
340 current_state
= NormalState
;
348 if (flags
.maximized
&& (functions
& Func_Maximize
)) {
353 When the window is mapped (and also when its attributes are restored), the
354 current_state that was set here will be used.
355 It is set to Normal if the window is to be mapped or it is set to Iconic
356 if the window is to be iconified.
357 *Note* that for sticky windows, the same rules apply here, they are in
358 fact never set to Iconic since there is no way for us to tell if a sticky
359 window was iconified previously.
366 BlackboxWindow::~BlackboxWindow(void) {
368 fprintf(stderr
, "BlackboxWindow::~BlackboxWindow: destroying 0x%lx\n",
372 if (! timer
) // window not managed...
375 screen
->removeStrut(&client
.strut
);
376 screen
->updateAvailableArea();
378 // We don't need to worry about resizing because resizing always grabs the X
379 // server. This should only ever happen if using opaque moving.
387 if (client
.window_group
) {
388 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
389 if (group
) group
->removeWindow(this);
392 // remove ourselves from our transient_for
394 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
395 client
.transient_for
->client
.transientList
.remove(this);
397 client
.transient_for
= (BlackboxWindow
*) 0;
400 if (client
.transientList
.size() > 0) {
401 // reset transient_for for all transients
402 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
403 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
404 (*it
)->client
.transient_for
= (BlackboxWindow
*) 0;
415 blackbox
->removeWindowSearch(frame
.plate
);
416 XDestroyWindow(blackbox
->getXDisplay(), frame
.plate
);
420 blackbox
->removeWindowSearch(frame
.window
);
421 XDestroyWindow(blackbox
->getXDisplay(), frame
.window
);
424 blackbox
->removeWindowSearch(client
.window
);
429 * Creates a new top level window, with a given location, size, and border
431 * Returns: the newly created window
433 Window
BlackboxWindow::createToplevelWindow(void) {
434 XSetWindowAttributes attrib_create
;
435 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
| CWColormap
|
436 CWOverrideRedirect
| CWEventMask
;
438 attrib_create
.background_pixmap
= None
;
439 attrib_create
.colormap
= screen
->getColormap();
440 attrib_create
.override_redirect
= True
;
441 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
442 ButtonMotionMask
| EnterWindowMask
;
444 return XCreateWindow(blackbox
->getXDisplay(), screen
->getRootWindow(),
445 -1, -1, 1, 1, frame
.border_w
, screen
->getDepth(),
446 InputOutput
, screen
->getVisual(), create_mask
,
452 * Creates a child window, and optionally associates a given cursor with
455 Window
BlackboxWindow::createChildWindow(Window parent
, Cursor cursor
) {
456 XSetWindowAttributes attrib_create
;
457 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
|
460 attrib_create
.background_pixmap
= None
;
461 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
462 ButtonMotionMask
| ExposureMask
;
465 create_mask
|= CWCursor
;
466 attrib_create
.cursor
= cursor
;
469 return XCreateWindow(blackbox
->getXDisplay(), parent
, 0, 0, 1, 1, 0,
470 screen
->getDepth(), InputOutput
, screen
->getVisual(),
471 create_mask
, &attrib_create
);
475 void BlackboxWindow::associateClientWindow(void) {
476 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, 0);
480 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeInsert
);
482 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, SubstructureRedirectMask
);
484 XGrabServer(blackbox
->getXDisplay());
485 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
486 XReparentWindow(blackbox
->getXDisplay(), client
.window
, frame
.plate
, 0, 0);
487 XSelectInput(blackbox
->getXDisplay(), client
.window
,
488 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
489 XUngrabServer(blackbox
->getXDisplay());
491 XRaiseWindow(blackbox
->getXDisplay(), frame
.plate
);
492 XMapSubwindows(blackbox
->getXDisplay(), frame
.plate
);
496 if (blackbox
->hasShapeExtensions()) {
497 XShapeSelectInput(blackbox
->getXDisplay(), client
.window
,
504 XShapeQueryExtents(blackbox
->getXDisplay(), client
.window
, &shaped
,
505 &foo
, &foo
, &ufoo
, &ufoo
, &foo
, &foo
, &foo
,
507 flags
.shaped
= shaped
;
513 void BlackboxWindow::decorate(void) {
516 texture
= &(screen
->getWindowStyle()->b_focus
);
517 frame
.fbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
520 frame
.fbutton_pixel
= texture
->color().pixel();
522 texture
= &(screen
->getWindowStyle()->b_unfocus
);
523 frame
.ubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
526 frame
.ubutton_pixel
= texture
->color().pixel();
528 texture
= &(screen
->getWindowStyle()->b_pressed
);
529 frame
.pbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
532 frame
.pbutton_pixel
= texture
->color().pixel();
534 if (decorations
& Decor_Titlebar
) {
535 texture
= &(screen
->getWindowStyle()->t_focus
);
536 frame
.ftitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
539 frame
.ftitle_pixel
= texture
->color().pixel();
541 texture
= &(screen
->getWindowStyle()->t_unfocus
);
542 frame
.utitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
545 frame
.utitle_pixel
= texture
->color().pixel();
547 XSetWindowBorder(blackbox
->getXDisplay(), frame
.title
,
548 screen
->getBorderColor()->pixel());
553 if (decorations
& Decor_Border
) {
554 frame
.fborder_pixel
= screen
->getWindowStyle()->f_focus
.pixel();
555 frame
.uborder_pixel
= screen
->getWindowStyle()->f_unfocus
.pixel();
556 blackbox_attrib
.flags
|= AttribDecoration
;
557 blackbox_attrib
.decoration
= DecorNormal
;
559 blackbox_attrib
.flags
|= AttribDecoration
;
560 blackbox_attrib
.decoration
= DecorNone
;
563 if (decorations
& Decor_Handle
) {
564 texture
= &(screen
->getWindowStyle()->h_focus
);
565 frame
.fhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
568 frame
.fhandle_pixel
= texture
->color().pixel();
570 texture
= &(screen
->getWindowStyle()->h_unfocus
);
571 frame
.uhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
574 frame
.uhandle_pixel
= texture
->color().pixel();
576 texture
= &(screen
->getWindowStyle()->g_focus
);
577 frame
.fgrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.fgrip
);
579 frame
.fgrip_pixel
= texture
->color().pixel();
581 texture
= &(screen
->getWindowStyle()->g_unfocus
);
582 frame
.ugrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.ugrip
);
584 frame
.ugrip_pixel
= texture
->color().pixel();
586 XSetWindowBorder(blackbox
->getXDisplay(), frame
.handle
,
587 screen
->getBorderColor()->pixel());
588 XSetWindowBorder(blackbox
->getXDisplay(), frame
.left_grip
,
589 screen
->getBorderColor()->pixel());
590 XSetWindowBorder(blackbox
->getXDisplay(), frame
.right_grip
,
591 screen
->getBorderColor()->pixel());
594 XSetWindowBorder(blackbox
->getXDisplay(), frame
.window
,
595 screen
->getBorderColor()->pixel());
599 void BlackboxWindow::decorateLabel(void) {
602 texture
= &(screen
->getWindowStyle()->l_focus
);
603 frame
.flabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.flabel
);
605 frame
.flabel_pixel
= texture
->color().pixel();
607 texture
= &(screen
->getWindowStyle()->l_unfocus
);
608 frame
.ulabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.ulabel
);
610 frame
.ulabel_pixel
= texture
->color().pixel();
614 void BlackboxWindow::createHandle(void) {
615 frame
.handle
= createChildWindow(frame
.window
);
616 blackbox
->saveWindowSearch(frame
.handle
, this);
619 createChildWindow(frame
.handle
, blackbox
->getLowerLeftAngleCursor());
620 blackbox
->saveWindowSearch(frame
.left_grip
, this);
623 createChildWindow(frame
.handle
, blackbox
->getLowerRightAngleCursor());
624 blackbox
->saveWindowSearch(frame
.right_grip
, this);
628 void BlackboxWindow::destroyHandle(void) {
630 screen
->getImageControl()->removeImage(frame
.fhandle
);
633 screen
->getImageControl()->removeImage(frame
.uhandle
);
636 screen
->getImageControl()->removeImage(frame
.fgrip
);
639 screen
->getImageControl()->removeImage(frame
.ugrip
);
641 blackbox
->removeWindowSearch(frame
.left_grip
);
642 blackbox
->removeWindowSearch(frame
.right_grip
);
644 XDestroyWindow(blackbox
->getXDisplay(), frame
.left_grip
);
645 XDestroyWindow(blackbox
->getXDisplay(), frame
.right_grip
);
646 frame
.left_grip
= frame
.right_grip
= None
;
648 blackbox
->removeWindowSearch(frame
.handle
);
649 XDestroyWindow(blackbox
->getXDisplay(), frame
.handle
);
654 void BlackboxWindow::createTitlebar(void) {
655 frame
.title
= createChildWindow(frame
.window
);
656 frame
.label
= createChildWindow(frame
.title
);
657 blackbox
->saveWindowSearch(frame
.title
, this);
658 blackbox
->saveWindowSearch(frame
.label
, this);
660 if (decorations
& Decor_Iconify
) createIconifyButton();
661 if (decorations
& Decor_Maximize
) createMaximizeButton();
662 if (decorations
& Decor_Close
) createCloseButton();
666 void BlackboxWindow::destroyTitlebar(void) {
667 if (frame
.close_button
)
668 destroyCloseButton();
670 if (frame
.iconify_button
)
671 destroyIconifyButton();
673 if (frame
.maximize_button
)
674 destroyMaximizeButton();
677 screen
->getImageControl()->removeImage(frame
.ftitle
);
680 screen
->getImageControl()->removeImage(frame
.utitle
);
683 screen
->getImageControl()->removeImage(frame
.flabel
);
686 screen
->getImageControl()->removeImage(frame
.ulabel
);
689 screen
->getImageControl()->removeImage(frame
.fbutton
);
692 screen
->getImageControl()->removeImage(frame
.ubutton
);
695 screen
->getImageControl()->removeImage(frame
.pbutton
);
697 blackbox
->removeWindowSearch(frame
.title
);
698 blackbox
->removeWindowSearch(frame
.label
);
700 XDestroyWindow(blackbox
->getXDisplay(), frame
.label
);
701 XDestroyWindow(blackbox
->getXDisplay(), frame
.title
);
702 frame
.title
= frame
.label
= None
;
706 void BlackboxWindow::createCloseButton(void) {
707 if (frame
.title
!= None
) {
708 frame
.close_button
= createChildWindow(frame
.title
);
709 blackbox
->saveWindowSearch(frame
.close_button
, this);
714 void BlackboxWindow::destroyCloseButton(void) {
715 blackbox
->removeWindowSearch(frame
.close_button
);
716 XDestroyWindow(blackbox
->getXDisplay(), frame
.close_button
);
717 frame
.close_button
= None
;
721 void BlackboxWindow::createIconifyButton(void) {
722 if (frame
.title
!= None
) {
723 frame
.iconify_button
= createChildWindow(frame
.title
);
724 blackbox
->saveWindowSearch(frame
.iconify_button
, this);
729 void BlackboxWindow::destroyIconifyButton(void) {
730 blackbox
->removeWindowSearch(frame
.iconify_button
);
731 XDestroyWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
732 frame
.iconify_button
= None
;
736 void BlackboxWindow::createMaximizeButton(void) {
737 if (frame
.title
!= None
) {
738 frame
.maximize_button
= createChildWindow(frame
.title
);
739 blackbox
->saveWindowSearch(frame
.maximize_button
, this);
744 void BlackboxWindow::destroyMaximizeButton(void) {
745 blackbox
->removeWindowSearch(frame
.maximize_button
);
746 XDestroyWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
747 frame
.maximize_button
= None
;
751 void BlackboxWindow::positionButtons(bool redecorate_label
) {
752 string layout
= blackbox
->getTitlebarLayout();
755 bool hasclose
, hasiconify
, hasmaximize
, haslabel
;
756 hasclose
= hasiconify
= hasmaximize
= haslabel
= false;
758 string::const_iterator it
, end
;
759 for (it
= layout
.begin(), end
= layout
.end(); it
!= end
; ++it
) {
762 if (! hasclose
&& (decorations
& Decor_Close
)) {
768 if (! hasiconify
&& (decorations
& Decor_Iconify
)) {
774 if (! hasmaximize
&& (decorations
& Decor_Maximize
)) {
786 if (! hasclose
&& frame
.close_button
)
787 destroyCloseButton();
788 if (! hasiconify
&& frame
.iconify_button
)
789 destroyIconifyButton();
790 if (! hasmaximize
&& frame
.maximize_button
)
791 destroyMaximizeButton();
793 parsed
+= 'L'; // require that the label be in the layout
795 const unsigned int bsep
= frame
.bevel_w
+ 1; // separation between elements
796 const unsigned int by
= frame
.bevel_w
+ 1;
797 const unsigned int ty
= frame
.bevel_w
;
799 frame
.label_w
= frame
.inside_w
- bsep
* 2 -
800 (frame
.button_w
+ bsep
) * (parsed
.size() - 1);
802 unsigned int x
= bsep
;
803 for (it
= parsed
.begin(), end
= parsed
.end(); it
!= end
; ++it
) {
806 if (! frame
.close_button
) createCloseButton();
807 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.close_button
, x
, by
,
808 frame
.button_w
, frame
.button_w
);
809 x
+= frame
.button_w
+ bsep
;
812 if (! frame
.iconify_button
) createIconifyButton();
813 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.iconify_button
, x
, by
,
814 frame
.button_w
, frame
.button_w
);
815 x
+= frame
.button_w
+ bsep
;
818 if (! frame
.maximize_button
) createMaximizeButton();
819 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.maximize_button
, x
, by
,
820 frame
.button_w
, frame
.button_w
);
821 x
+= frame
.button_w
+ bsep
;
824 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.label
, x
, ty
,
825 frame
.label_w
, frame
.label_h
);
826 x
+= frame
.label_w
+ bsep
;
831 if (redecorate_label
) decorateLabel();
837 void BlackboxWindow::reconfigure(void) {
840 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
841 frame
.rect
.top() + frame
.margin
.top
);
848 configure(frame
.rect
.x(), frame
.rect
.y(),
849 frame
.rect
.width(), frame
.rect
.height());
852 windowmenu
->move(windowmenu
->getX(), frame
.rect
.y() + frame
.title_h
);
853 windowmenu
->reconfigure();
858 void BlackboxWindow::updateFocusModel(void) {
859 if ((! screen
->isSloppyFocus()) || screen
->doClickRaise()) {
860 // grab button 1 for changing focus/raising
861 blackbox
->grabButton(Button1
, 0, frame
.plate
, True
, ButtonPressMask
,
862 GrabModeSync
, GrabModeSync
, None
, None
);
864 blackbox
->ungrabButton(Button1
, 0, frame
.plate
);
869 void BlackboxWindow::positionWindows(void) {
870 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.window
,
871 frame
.rect
.x(), frame
.rect
.y(), frame
.inside_w
,
872 (flags
.shaded
) ? frame
.title_h
: frame
.inside_h
);
873 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.window
,
875 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.plate
,
877 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.plate
,
878 frame
.margin
.left
- frame
.mwm_border_w
- frame
.border_w
,
879 frame
.margin
.top
- frame
.mwm_border_w
- frame
.border_w
,
880 client
.rect
.width(), client
.rect
.height());
881 XMoveResizeWindow(blackbox
->getXDisplay(), client
.window
,
882 0, 0, client
.rect
.width(), client
.rect
.height());
884 if (decorations
& Decor_Titlebar
) {
885 if (frame
.title
== None
) createTitlebar();
887 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.title
,
889 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.title
, -frame
.border_w
,
890 -frame
.border_w
, frame
.inside_w
, frame
.title_h
);
893 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
894 XMapWindow(blackbox
->getXDisplay(), frame
.title
);
895 } else if (frame
.title
) {
898 if (decorations
& Decor_Handle
) {
899 if (frame
.handle
== None
) createHandle();
900 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.handle
,
902 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.left_grip
,
904 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.right_grip
,
907 // use client.rect here so the value is correct even if shaded
908 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.handle
,
910 client
.rect
.height() + frame
.margin
.top
+
911 frame
.mwm_border_w
- frame
.border_w
,
912 frame
.inside_w
, frame
.handle_h
);
913 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.left_grip
,
914 -frame
.border_w
, -frame
.border_w
,
915 frame
.grip_w
, frame
.handle_h
);
916 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.right_grip
,
917 frame
.inside_w
- frame
.grip_w
- frame
.border_w
,
918 -frame
.border_w
, frame
.grip_w
, frame
.handle_h
);
920 XMapSubwindows(blackbox
->getXDisplay(), frame
.handle
);
921 XMapWindow(blackbox
->getXDisplay(), frame
.handle
);
922 } else if (frame
.handle
) {
928 void BlackboxWindow::updateStrut(void) {
929 unsigned long num
= 4;
931 if (! xatom
->getValue(client
.window
, XAtom::net_wm_strut
, XAtom::cardinal
,
936 client
.strut
.left
= data
[0];
937 client
.strut
.right
= data
[1];
938 client
.strut
.top
= data
[2];
939 client
.strut
.bottom
= data
[3];
941 screen
->updateAvailableArea();
948 void BlackboxWindow::getWindowType(void) {
950 if (xatom
->getValue(client
.window
, XAtom::net_wm_window_type
, XAtom::atom
,
952 if (val
== xatom
->getAtom(XAtom::net_wm_window_type_desktop
))
953 window_type
= Type_Desktop
;
954 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_dock
))
955 window_type
= Type_Dock
;
956 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_toolbar
))
957 window_type
= Type_Toolbar
;
958 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_menu
))
959 window_type
= Type_Menu
;
960 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_utility
))
961 window_type
= Type_Utility
;
962 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_splash
))
963 window_type
= Type_Splash
;
964 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_dialog
))
965 window_type
= Type_Dialog
;
966 else //if (val[0] == xatom->getAtom(XAtom::net_wm_window_type_normal))
967 window_type
= Type_Normal
;
972 * the window type hint was not set, which means we either classify ourself
973 * as a normal window or a dialog, depending on if we are a transient.
976 window_type
= Type_Dialog
;
978 window_type
= Type_Normal
;
982 void BlackboxWindow::getWMName(void) {
983 if (xatom
->getValue(client
.window
, XAtom::net_wm_name
,
984 XAtom::utf8
, client
.title
) &&
985 !client
.title
.empty()) {
986 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
989 //fall through to using WM_NAME
990 if (xatom
->getValue(client
.window
, XAtom::wm_name
, XAtom::ansi
, client
.title
)
991 && !client
.title
.empty()) {
992 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
995 // fall back to an internal default
996 client
.title
= i18n(WindowSet
, WindowUnnamed
, "Unnamed");
997 xatom
->setValue(client
.window
, XAtom::net_wm_visible_name
, XAtom::utf8
,
1002 void BlackboxWindow::getWMIconName(void) {
1003 if (xatom
->getValue(client
.window
, XAtom::net_wm_icon_name
,
1004 XAtom::utf8
, client
.icon_title
) &&
1005 !client
.icon_title
.empty()) {
1006 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1009 //fall through to using WM_ICON_NAME
1010 if (xatom
->getValue(client
.window
, XAtom::wm_icon_name
, XAtom::ansi
,
1011 client
.icon_title
) &&
1012 !client
.icon_title
.empty()) {
1013 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1016 // fall back to using the main name
1017 client
.icon_title
= client
.title
;
1018 xatom
->setValue(client
.window
, XAtom::net_wm_visible_icon_name
, XAtom::utf8
,
1024 * Retrieve which WM Protocols are supported by the client window.
1025 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
1026 * window's decorations and allow the close behavior.
1027 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
1030 void BlackboxWindow::getWMProtocols(void) {
1034 if (XGetWMProtocols(blackbox
->getXDisplay(), client
.window
,
1035 &proto
, &num_return
)) {
1036 for (int i
= 0; i
< num_return
; ++i
) {
1037 if (proto
[i
] == xatom
->getAtom(XAtom::wm_delete_window
)) {
1038 decorations
|= Decor_Close
;
1039 functions
|= Func_Close
;
1040 } else if (proto
[i
] == xatom
->getAtom(XAtom::wm_take_focus
))
1041 flags
.send_focus_message
= True
;
1042 else if (proto
[i
] == xatom
->getAtom(XAtom::blackbox_structure_messages
))
1043 screen
->addNetizen(new Netizen(screen
, client
.window
));
1052 * Gets the value of the WM_HINTS property.
1053 * If the property is not set, then use a set of default values.
1055 void BlackboxWindow::getWMHints(void) {
1056 focus_mode
= F_Passive
;
1057 client
.initial_state
= NormalState
;
1059 // remove from current window group
1060 if (client
.window_group
) {
1061 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1062 if (group
) group
->removeWindow(this);
1064 client
.window_group
= None
;
1066 XWMHints
*wmhint
= XGetWMHints(blackbox
->getXDisplay(), client
.window
);
1071 if (wmhint
->flags
& InputHint
) {
1072 if (wmhint
->input
== True
) {
1073 if (flags
.send_focus_message
)
1074 focus_mode
= F_LocallyActive
;
1076 if (flags
.send_focus_message
)
1077 focus_mode
= F_GloballyActive
;
1079 focus_mode
= F_NoInput
;
1083 if (wmhint
->flags
& StateHint
)
1084 client
.initial_state
= wmhint
->initial_state
;
1086 if (wmhint
->flags
& WindowGroupHint
) {
1087 client
.window_group
= wmhint
->window_group
;
1089 // add window to the appropriate group
1090 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1091 if (! group
) // no group found, create it!
1092 group
= new BWindowGroup(blackbox
, client
.window_group
);
1093 group
->addWindow(this);
1096 client
.wm_hint_flags
= wmhint
->flags
;
1102 * Gets the value of the WM_NORMAL_HINTS property.
1103 * If the property is not set, then use a set of default values.
1105 void BlackboxWindow::getWMNormalHints(void) {
1107 XSizeHints sizehint
;
1109 client
.min_width
= client
.min_height
=
1110 client
.width_inc
= client
.height_inc
= 1;
1111 client
.base_width
= client
.base_height
= 0;
1114 use the full screen, not the strut modified size. otherwise when the
1115 availableArea changes max_width/height will be incorrect and lead to odd
1118 const Rect
& screen_area
= screen
->getRect();
1119 client
.max_width
= screen_area
.width();
1121 client
.max_height
= screen_area
.height();
1122 client
.min_aspect_x
= client
.min_aspect_y
=
1123 client
.max_aspect_x
= client
.max_aspect_y
= 1;
1124 client
.win_gravity
= NorthWestGravity
;
1126 if (! XGetWMNormalHints(blackbox
->getXDisplay(), client
.window
,
1127 &sizehint
, &icccm_mask
))
1130 client
.normal_hint_flags
= sizehint
.flags
;
1132 if (sizehint
.flags
& PMinSize
) {
1133 client
.min_width
= sizehint
.min_width
;
1134 client
.min_height
= sizehint
.min_height
;
1137 if (sizehint
.flags
& PMaxSize
) {
1138 client
.max_width
= sizehint
.max_width
;
1139 client
.max_height
= sizehint
.max_height
;
1142 if (sizehint
.flags
& PResizeInc
) {
1143 client
.width_inc
= sizehint
.width_inc
;
1144 client
.height_inc
= sizehint
.height_inc
;
1147 if (sizehint
.flags
& PAspect
) {
1148 client
.min_aspect_x
= sizehint
.min_aspect
.x
;
1149 client
.min_aspect_y
= sizehint
.min_aspect
.y
;
1150 client
.max_aspect_x
= sizehint
.max_aspect
.x
;
1151 client
.max_aspect_y
= sizehint
.max_aspect
.y
;
1154 if (sizehint
.flags
& PBaseSize
) {
1155 client
.base_width
= sizehint
.base_width
;
1156 client
.base_height
= sizehint
.base_height
;
1159 if (sizehint
.flags
& PWinGravity
)
1160 client
.win_gravity
= sizehint
.win_gravity
;
1165 * Gets the NETWM hints for the class' contained window.
1167 void BlackboxWindow::getNetWMHints(void) {
1168 unsigned long workspace
;
1170 if (xatom
->getValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1172 if (workspace
== 0xffffffff)
1175 blackbox_attrib
.workspace
= workspace
;
1178 unsigned long *state
;
1179 unsigned long num
= (unsigned) -1;
1180 if (xatom
->getValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
1184 for (unsigned long i
= 0; i
< num
; ++i
) {
1185 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
))
1187 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_shaded
))
1188 flags
.shaded
= True
;
1189 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
))
1190 flags
.skip_taskbar
= True
;
1191 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_pager
))
1192 flags
.skip_pager
= True
;
1193 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_fullscreen
))
1194 flags
.fullscreen
= True
;
1195 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_hidden
))
1196 setState(IconicState
);
1197 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_vert
))
1199 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_horz
))
1203 flags
.maximized
= 1;
1205 flags
.maximized
= 2;
1207 flags
.maximized
= 3;
1215 * Gets the MWM hints for the class' contained window.
1216 * This is used while initializing the window to its first state, and not
1218 * Returns: true if the MWM hints are successfully retreived and applied;
1219 * false if they are not.
1221 void BlackboxWindow::getMWMHints(void) {
1225 num
= PropMwmHintsElements
;
1226 if (! xatom
->getValue(client
.window
, XAtom::motif_wm_hints
,
1227 XAtom::motif_wm_hints
, num
,
1228 (unsigned long **)&mwm_hint
))
1230 if (num
< PropMwmHintsElements
) {
1235 if (mwm_hint
->flags
& MwmHintsDecorations
) {
1236 if (mwm_hint
->decorations
& MwmDecorAll
) {
1237 decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
1238 Decor_Iconify
| Decor_Maximize
| Decor_Close
;
1242 if (mwm_hint
->decorations
& MwmDecorBorder
)
1243 decorations
|= Decor_Border
;
1244 if (mwm_hint
->decorations
& MwmDecorHandle
)
1245 decorations
|= Decor_Handle
;
1246 if (mwm_hint
->decorations
& MwmDecorTitle
)
1247 decorations
|= Decor_Titlebar
;
1248 if (mwm_hint
->decorations
& MwmDecorIconify
)
1249 decorations
|= Decor_Iconify
;
1250 if (mwm_hint
->decorations
& MwmDecorMaximize
)
1251 decorations
|= Decor_Maximize
;
1255 if (mwm_hint
->flags
& MwmHintsFunctions
) {
1256 if (mwm_hint
->functions
& MwmFuncAll
) {
1257 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
|
1262 if (mwm_hint
->functions
& MwmFuncResize
)
1263 functions
|= Func_Resize
;
1264 if (mwm_hint
->functions
& MwmFuncMove
)
1265 functions
|= Func_Move
;
1266 if (mwm_hint
->functions
& MwmFuncIconify
)
1267 functions
|= Func_Iconify
;
1268 if (mwm_hint
->functions
& MwmFuncMaximize
)
1269 functions
|= Func_Maximize
;
1270 if (mwm_hint
->functions
& MwmFuncClose
)
1271 functions
|= Func_Close
;
1279 * Gets the blackbox hints from the class' contained window.
1280 * This is used while initializing the window to its first state, and not
1282 * Returns: true if the hints are successfully retreived and applied; false if
1285 bool BlackboxWindow::getBlackboxHints(void) {
1287 BlackboxHints
*blackbox_hint
;
1289 num
= PropBlackboxHintsElements
;
1290 if (! xatom
->getValue(client
.window
, XAtom::blackbox_hints
,
1291 XAtom::blackbox_hints
, num
,
1292 (unsigned long **)&blackbox_hint
))
1294 if (num
< PropBlackboxHintsElements
) {
1295 delete [] blackbox_hint
;
1299 if (blackbox_hint
->flags
& AttribShaded
)
1300 flags
.shaded
= (blackbox_hint
->attrib
& AttribShaded
);
1302 if ((blackbox_hint
->flags
& AttribMaxHoriz
) &&
1303 (blackbox_hint
->flags
& AttribMaxVert
))
1304 flags
.maximized
= (blackbox_hint
->attrib
&
1305 (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1306 else if (blackbox_hint
->flags
& AttribMaxVert
)
1307 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxVert
) ? 2 : 0;
1308 else if (blackbox_hint
->flags
& AttribMaxHoriz
)
1309 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1311 if (blackbox_hint
->flags
& AttribOmnipresent
)
1312 flags
.stuck
= (blackbox_hint
->attrib
& AttribOmnipresent
);
1314 if (blackbox_hint
->flags
& AttribWorkspace
)
1315 blackbox_attrib
.workspace
= blackbox_hint
->workspace
;
1317 // if (blackbox_hint->flags & AttribStack)
1318 // don't yet have always on top/bottom for blackbox yet... working
1321 if (blackbox_hint
->flags
& AttribDecoration
) {
1322 switch (blackbox_hint
->decoration
) {
1324 // clear all decorations except close
1325 decorations
&= Decor_Close
;
1326 // clear all functions except close
1327 functions
&= Func_Close
;
1332 decorations
|= Decor_Titlebar
| Decor_Iconify
;
1333 decorations
&= ~(Decor_Border
| Decor_Handle
| Decor_Maximize
);
1334 functions
|= Func_Move
| Func_Iconify
;
1335 functions
&= ~(Func_Resize
| Func_Maximize
);
1340 decorations
|= Decor_Titlebar
;
1341 decorations
&= ~(Decor_Iconify
| Decor_Border
| Decor_Handle
);
1342 functions
|= Func_Move
;
1343 functions
&= ~(Func_Resize
| Func_Maximize
| Func_Iconify
);
1349 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Handle
|
1350 Decor_Iconify
| Decor_Maximize
;
1351 functions
|= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
1359 delete [] blackbox_hint
;
1365 void BlackboxWindow::getTransientInfo(void) {
1366 if (client
.transient_for
&&
1367 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1368 // the transient for hint was removed, so we need to tell our
1369 // previous transient_for that we are going away
1370 client
.transient_for
->client
.transientList
.remove(this);
1373 // we have no transient_for until we find a new one
1374 client
.transient_for
= 0;
1377 if (! XGetTransientForHint(blackbox
->getXDisplay(), client
.window
,
1379 // transient_for hint not set
1383 if (trans_for
== client
.window
) {
1384 // wierd client... treat this window as a normal window
1388 if (trans_for
== None
|| trans_for
== screen
->getRootWindow()) {
1389 // this is an undocumented interpretation of the ICCCM. a transient
1390 // associated with None/Root/itself is assumed to be a modal root
1391 // transient. we don't support the concept of a global transient,
1392 // so we just associate this transient with nothing, and perhaps
1393 // we will add support later for global modality.
1394 client
.transient_for
= (BlackboxWindow
*) ~0ul;
1399 client
.transient_for
= blackbox
->searchWindow(trans_for
);
1400 if (! client
.transient_for
&&
1401 client
.window_group
&& trans_for
== client
.window_group
) {
1402 // no direct transient_for, perhaps this is a group transient?
1403 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1404 if (group
) client
.transient_for
= group
->find(screen
);
1407 if (! client
.transient_for
|| client
.transient_for
== this) {
1408 // no transient_for found, or we have a wierd client that wants to be
1409 // a transient for itself, so we treat this window as a normal window
1410 client
.transient_for
= (BlackboxWindow
*) 0;
1414 // register ourselves with our new transient_for
1415 client
.transient_for
->client
.transientList
.push_back(this);
1416 flags
.stuck
= client
.transient_for
->flags
.stuck
;
1420 bool BlackboxWindow::isKDESystrayWindow(void) {
1422 if (xatom
->getValue(client
.window
, XAtom::kde_net_wm_system_tray_window_for
,
1423 XAtom::window
, systray
) && systray
)
1429 BlackboxWindow
*BlackboxWindow::getTransientFor(void) const {
1430 if (client
.transient_for
&&
1431 client
.transient_for
!= (BlackboxWindow
*) ~0ul)
1432 return client
.transient_for
;
1437 void BlackboxWindow::configure(int dx
, int dy
,
1438 unsigned int dw
, unsigned int dh
) {
1439 bool send_event
= False
;
1441 if (dw
!= frame
.rect
.width() || dh
!= frame
.rect
.height()) {
1442 frame
.rect
.setRect(dx
, dy
, dw
, dh
);
1443 frame
.inside_w
= frame
.rect
.width() - (frame
.border_w
* 2);
1444 frame
.inside_h
= frame
.rect
.height() - (frame
.border_w
* 2);
1446 if (frame
.rect
.right() <= 0 || frame
.rect
.bottom() <= 0)
1447 frame
.rect
.setPos(0, 0);
1449 client
.rect
.setCoords(frame
.rect
.left() + frame
.margin
.left
,
1450 frame
.rect
.top() + frame
.margin
.top
,
1451 frame
.rect
.right() - frame
.margin
.right
,
1452 frame
.rect
.bottom() - frame
.margin
.bottom
);
1455 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
1462 redrawWindowFrame();
1463 } else if (frame
.rect
.x() != dx
|| frame
.rect
.y() != dy
) {
1466 frame
.rect
.setPos(dx
, dy
);
1468 XMoveWindow(blackbox
->getXDisplay(), frame
.window
,
1469 frame
.rect
.x(), frame
.rect
.y());
1472 if (send_event
&& ! flags
.moving
) {
1473 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1474 frame
.rect
.top() + frame
.margin
.top
);
1477 event
.type
= ConfigureNotify
;
1479 event
.xconfigure
.display
= blackbox
->getXDisplay();
1480 event
.xconfigure
.event
= client
.window
;
1481 event
.xconfigure
.window
= client
.window
;
1482 event
.xconfigure
.x
= client
.rect
.x();
1483 event
.xconfigure
.y
= client
.rect
.y();
1484 event
.xconfigure
.width
= client
.rect
.width();
1485 event
.xconfigure
.height
= client
.rect
.height();
1486 event
.xconfigure
.border_width
= client
.old_bw
;
1487 event
.xconfigure
.above
= frame
.window
;
1488 event
.xconfigure
.override_redirect
= False
;
1490 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1491 StructureNotifyMask
, &event
);
1493 screen
->updateNetizenConfigNotify(&event
);
1499 void BlackboxWindow::configureShape(void) {
1500 XShapeCombineShape(blackbox
->getXDisplay(), frame
.window
, ShapeBounding
,
1501 frame
.margin
.left
- frame
.border_w
,
1502 frame
.margin
.top
- frame
.border_w
,
1503 client
.window
, ShapeBounding
, ShapeSet
);
1506 XRectangle xrect
[2];
1508 if (decorations
& Decor_Titlebar
) {
1509 xrect
[0].x
= xrect
[0].y
= -frame
.border_w
;
1510 xrect
[0].width
= frame
.rect
.width();
1511 xrect
[0].height
= frame
.title_h
+ (frame
.border_w
* 2);
1515 if (decorations
& Decor_Handle
) {
1516 xrect
[1].x
= -frame
.border_w
;
1517 xrect
[1].y
= frame
.rect
.height() - frame
.margin
.bottom
+
1518 frame
.mwm_border_w
- frame
.border_w
;
1519 xrect
[1].width
= frame
.rect
.width();
1520 xrect
[1].height
= frame
.handle_h
+ (frame
.border_w
* 2);
1524 XShapeCombineRectangles(blackbox
->getXDisplay(), frame
.window
,
1525 ShapeBounding
, 0, 0, xrect
, num
,
1526 ShapeUnion
, Unsorted
);
1531 bool BlackboxWindow::setInputFocus(void) {
1532 if (flags
.focused
) return True
;
1534 assert(! flags
.iconic
);
1536 // if the window is not visible, mark the window as wanting focus rather
1537 // than give it focus.
1538 if (! flags
.visible
) {
1539 Workspace
*wkspc
= screen
->getWorkspace(blackbox_attrib
.workspace
);
1540 wkspc
->setLastFocusedWindow(this);
1544 if (! frame
.rect
.intersects(screen
->getRect())) {
1545 // client is outside the screen, move it to the center
1546 configure((screen
->getWidth() - frame
.rect
.width()) / 2,
1547 (screen
->getHeight() - frame
.rect
.height()) / 2,
1548 frame
.rect
.width(), frame
.rect
.height());
1551 if (client
.transientList
.size() > 0) {
1552 // transfer focus to any modal transients
1553 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1554 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1555 if ((*it
)->flags
.modal
) return (*it
)->setInputFocus();
1560 if (focus_mode
== F_LocallyActive
|| focus_mode
== F_Passive
) {
1561 XSetInputFocus(blackbox
->getXDisplay(), client
.window
,
1562 RevertToPointerRoot
, CurrentTime
);
1564 blackbox
->setFocusedWindow(this);
1566 /* we could set the focus to none, since the window doesn't accept focus,
1567 * but we shouldn't set focus to nothing since this would surely make
1573 if (flags
.send_focus_message
) {
1575 ce
.xclient
.type
= ClientMessage
;
1576 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1577 ce
.xclient
.display
= blackbox
->getXDisplay();
1578 ce
.xclient
.window
= client
.window
;
1579 ce
.xclient
.format
= 32;
1580 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_take_focus
);
1581 ce
.xclient
.data
.l
[1] = blackbox
->getLastTime();
1582 ce
.xclient
.data
.l
[2] = 0l;
1583 ce
.xclient
.data
.l
[3] = 0l;
1584 ce
.xclient
.data
.l
[4] = 0l;
1585 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1593 void BlackboxWindow::iconify(void) {
1594 if (flags
.iconic
) return;
1596 // We don't need to worry about resizing because resizing always grabs the X
1597 // server. This should only ever happen if using opaque moving.
1601 if (windowmenu
) windowmenu
->hide();
1604 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1605 * we need to clear the event mask on client.window for a split second.
1606 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1607 * split second, leaving us with a ghost window... so, we need to do this
1608 * while the X server is grabbed
1610 XGrabServer(blackbox
->getXDisplay());
1611 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
1612 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1613 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1614 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
1615 XUngrabServer(blackbox
->getXDisplay());
1617 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1618 flags
.visible
= False
;
1619 flags
.iconic
= True
;
1621 setState(IconicState
);
1623 screen
->getWorkspace(blackbox_attrib
.workspace
)->removeWindow(this);
1625 if (isTransient()) {
1626 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1627 ! client
.transient_for
->flags
.iconic
) {
1628 // iconify our transient_for
1629 client
.transient_for
->iconify();
1633 screen
->addIcon(this);
1635 if (client
.transientList
.size() > 0) {
1636 // iconify all transients
1637 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1638 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1639 if (! (*it
)->flags
.iconic
) (*it
)->iconify();
1645 void BlackboxWindow::show(void) {
1646 flags
.visible
= True
;
1647 flags
.iconic
= False
;
1649 current_state
= (flags
.shaded
) ? IconicState
: NormalState
;
1650 setState(current_state
);
1652 XMapWindow(blackbox
->getXDisplay(), client
.window
);
1653 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
1654 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
1658 void BlackboxWindow::deiconify(bool reassoc
, bool raise
) {
1659 if (flags
.iconic
|| reassoc
)
1660 screen
->reassociateWindow(this, BSENTINEL
, False
);
1661 else if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspace()->getID())
1666 // reassociate and deiconify all transients
1667 if (reassoc
&& client
.transientList
.size() > 0) {
1668 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1669 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1670 (*it
)->deiconify(True
, False
);
1675 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1679 void BlackboxWindow::close(void) {
1681 ce
.xclient
.type
= ClientMessage
;
1682 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1683 ce
.xclient
.display
= blackbox
->getXDisplay();
1684 ce
.xclient
.window
= client
.window
;
1685 ce
.xclient
.format
= 32;
1686 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_delete_window
);
1687 ce
.xclient
.data
.l
[1] = CurrentTime
;
1688 ce
.xclient
.data
.l
[2] = 0l;
1689 ce
.xclient
.data
.l
[3] = 0l;
1690 ce
.xclient
.data
.l
[4] = 0l;
1691 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
, NoEventMask
, &ce
);
1695 void BlackboxWindow::withdraw(void) {
1696 // We don't need to worry about resizing because resizing always grabs the X
1697 // server. This should only ever happen if using opaque moving.
1701 flags
.visible
= False
;
1702 flags
.iconic
= False
;
1704 setState(current_state
);
1706 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1708 XGrabServer(blackbox
->getXDisplay());
1710 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
1711 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1712 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1713 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
1715 XUngrabServer(blackbox
->getXDisplay());
1717 if (windowmenu
) windowmenu
->hide();
1721 void BlackboxWindow::maximize(unsigned int button
) {
1722 // We don't need to worry about resizing because resizing always grabs the X
1723 // server. This should only ever happen if using opaque moving.
1727 // handle case where menu is open then the max button is used instead
1728 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
1730 if (flags
.maximized
) {
1731 flags
.maximized
= 0;
1733 blackbox_attrib
.flags
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1734 blackbox_attrib
.attrib
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1737 when a resize finishes, maximize(0) is called to clear any maximization
1738 flags currently set. Otherwise it still thinks it is maximized.
1739 so we do not need to call configure() because resizing will handle it
1741 if (! flags
.resizing
)
1742 configure(blackbox_attrib
.premax_x
, blackbox_attrib
.premax_y
,
1743 blackbox_attrib
.premax_w
, blackbox_attrib
.premax_h
);
1745 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
1746 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
1748 redrawAllButtons(); // in case it is not called in configure()
1749 setState(current_state
);
1753 blackbox_attrib
.premax_x
= frame
.rect
.x();
1754 blackbox_attrib
.premax_y
= frame
.rect
.y();
1755 blackbox_attrib
.premax_w
= frame
.rect
.width();
1756 // use client.rect so that clients can be restored even if shaded
1757 blackbox_attrib
.premax_h
=
1758 client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
;
1760 const Rect
&screen_area
= screen
->availableArea();
1761 frame
.changing
= screen_area
;
1765 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1766 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1770 blackbox_attrib
.flags
|= AttribMaxVert
;
1771 blackbox_attrib
.attrib
|= AttribMaxVert
;
1773 frame
.changing
.setX(frame
.rect
.x());
1774 frame
.changing
.setWidth(frame
.rect
.width());
1778 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1779 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1781 frame
.changing
.setY(frame
.rect
.y());
1782 frame
.changing
.setHeight(frame
.rect
.height());
1789 blackbox_attrib
.flags
^= AttribShaded
;
1790 blackbox_attrib
.attrib
^= AttribShaded
;
1791 flags
.shaded
= False
;
1794 flags
.maximized
= button
;
1796 configure(frame
.changing
.x(), frame
.changing
.y(),
1797 frame
.changing
.width(), frame
.changing
.height());
1799 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1800 redrawAllButtons(); // in case it is not called in configure()
1801 setState(current_state
);
1805 // re-maximizes the window to take into account availableArea changes
1806 void BlackboxWindow::remaximize(void) {
1807 // save the original dimensions because maximize will wipe them out
1808 int premax_x
= blackbox_attrib
.premax_x
,
1809 premax_y
= blackbox_attrib
.premax_y
,
1810 premax_w
= blackbox_attrib
.premax_w
,
1811 premax_h
= blackbox_attrib
.premax_h
;
1813 unsigned int button
= flags
.maximized
;
1814 flags
.maximized
= 0; // trick maximize() into working
1817 // restore saved values
1818 blackbox_attrib
.premax_x
= premax_x
;
1819 blackbox_attrib
.premax_y
= premax_y
;
1820 blackbox_attrib
.premax_w
= premax_w
;
1821 blackbox_attrib
.premax_h
= premax_h
;
1825 void BlackboxWindow::setWorkspace(unsigned int n
) {
1826 blackbox_attrib
.flags
|= AttribWorkspace
;
1827 blackbox_attrib
.workspace
= n
;
1828 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
, n
);
1832 void BlackboxWindow::shade(void) {
1834 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1835 frame
.inside_w
, frame
.inside_h
);
1836 flags
.shaded
= False
;
1837 blackbox_attrib
.flags
^= AttribShaded
;
1838 blackbox_attrib
.attrib
^= AttribShaded
;
1840 setState(NormalState
);
1842 // set the frame rect to the normal size
1843 frame
.rect
.setHeight(client
.rect
.height() + frame
.margin
.top
+
1844 frame
.margin
.bottom
);
1846 if (! (decorations
& Decor_Titlebar
))
1847 return; // can't shade it without a titlebar!
1849 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1850 frame
.inside_w
, frame
.title_h
);
1851 flags
.shaded
= True
;
1852 blackbox_attrib
.flags
|= AttribShaded
;
1853 blackbox_attrib
.attrib
|= AttribShaded
;
1855 setState(IconicState
);
1857 // set the frame rect to the shaded size
1858 frame
.rect
.setHeight(frame
.title_h
+ (frame
.border_w
* 2));
1864 * (Un)Sticks a window and its relatives.
1866 void BlackboxWindow::stick(void) {
1868 blackbox_attrib
.flags
^= AttribOmnipresent
;
1869 blackbox_attrib
.attrib
^= AttribOmnipresent
;
1871 flags
.stuck
= False
;
1874 screen
->reassociateWindow(this, BSENTINEL
, True
);
1876 // temporary fix since sticky windows suck. set the hint to what we
1877 // actually hold in our data.
1878 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1879 blackbox_attrib
.workspace
);
1881 setState(current_state
);
1885 blackbox_attrib
.flags
|= AttribOmnipresent
;
1886 blackbox_attrib
.attrib
|= AttribOmnipresent
;
1888 // temporary fix since sticky windows suck. set the hint to a different
1889 // value than that contained in the class' data.
1890 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1893 setState(current_state
);
1896 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1897 client
.transient_for
->isStuck() != flags
.stuck
)
1898 client
.transient_for
->stick();
1899 // go down the chain
1900 BlackboxWindowList::iterator it
;
1901 const BlackboxWindowList::iterator end
= client
.transientList
.end();
1902 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1903 if ((*it
)->isStuck() != flags
.stuck
)
1908 void BlackboxWindow::redrawWindowFrame(void) const {
1909 if (decorations
& Decor_Titlebar
) {
1910 if (flags
.focused
) {
1912 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1913 frame
.title
, frame
.ftitle
);
1915 XSetWindowBackground(blackbox
->getXDisplay(),
1916 frame
.title
, frame
.ftitle_pixel
);
1919 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1920 frame
.title
, frame
.utitle
);
1922 XSetWindowBackground(blackbox
->getXDisplay(),
1923 frame
.title
, frame
.utitle_pixel
);
1925 XClearWindow(blackbox
->getXDisplay(), frame
.title
);
1931 if (decorations
& Decor_Handle
) {
1932 if (flags
.focused
) {
1934 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1935 frame
.handle
, frame
.fhandle
);
1937 XSetWindowBackground(blackbox
->getXDisplay(),
1938 frame
.handle
, frame
.fhandle_pixel
);
1941 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1942 frame
.left_grip
, frame
.fgrip
);
1943 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1944 frame
.right_grip
, frame
.fgrip
);
1946 XSetWindowBackground(blackbox
->getXDisplay(),
1947 frame
.left_grip
, frame
.fgrip_pixel
);
1948 XSetWindowBackground(blackbox
->getXDisplay(),
1949 frame
.right_grip
, frame
.fgrip_pixel
);
1953 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1954 frame
.handle
, frame
.uhandle
);
1956 XSetWindowBackground(blackbox
->getXDisplay(),
1957 frame
.handle
, frame
.uhandle_pixel
);
1960 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1961 frame
.left_grip
, frame
.ugrip
);
1962 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1963 frame
.right_grip
, frame
.ugrip
);
1965 XSetWindowBackground(blackbox
->getXDisplay(),
1966 frame
.left_grip
, frame
.ugrip_pixel
);
1967 XSetWindowBackground(blackbox
->getXDisplay(),
1968 frame
.right_grip
, frame
.ugrip_pixel
);
1971 XClearWindow(blackbox
->getXDisplay(), frame
.handle
);
1972 XClearWindow(blackbox
->getXDisplay(), frame
.left_grip
);
1973 XClearWindow(blackbox
->getXDisplay(), frame
.right_grip
);
1976 if (decorations
& Decor_Border
) {
1978 XSetWindowBorder(blackbox
->getXDisplay(),
1979 frame
.plate
, frame
.fborder_pixel
);
1981 XSetWindowBorder(blackbox
->getXDisplay(),
1982 frame
.plate
, frame
.uborder_pixel
);
1987 void BlackboxWindow::setFocusFlag(bool focus
) {
1988 // only focus a window if it is visible
1989 if (focus
&& !flags
.visible
)
1992 flags
.focused
= focus
;
1994 redrawWindowFrame();
1996 if (screen
->isSloppyFocus() && screen
->doAutoRaise()) {
1997 if (isFocused()) timer
->start();
2002 blackbox
->setFocusedWindow(this);
2006 void BlackboxWindow::installColormap(bool install
) {
2007 int i
= 0, ncmap
= 0;
2008 Colormap
*cmaps
= XListInstalledColormaps(blackbox
->getXDisplay(),
2009 client
.window
, &ncmap
);
2011 XWindowAttributes wattrib
;
2012 if (XGetWindowAttributes(blackbox
->getXDisplay(),
2013 client
.window
, &wattrib
)) {
2015 // install the window's colormap
2016 for (i
= 0; i
< ncmap
; i
++) {
2017 if (*(cmaps
+ i
) == wattrib
.colormap
)
2018 // this window is using an installed color map... do not install
2021 // otherwise, install the window's colormap
2023 XInstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2025 // uninstall the window's colormap
2026 for (i
= 0; i
< ncmap
; i
++) {
2027 if (*(cmaps
+ i
) == wattrib
.colormap
)
2028 // we found the colormap to uninstall
2029 XUninstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2039 void BlackboxWindow::setAllowedActions(void) {
2043 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_shade
);
2044 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_change_desktop
);
2045 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_close
);
2047 if (functions
& Func_Move
)
2048 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_move
);
2049 if (functions
& Func_Resize
)
2050 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_resize
);
2051 if (functions
& Func_Maximize
) {
2052 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_horz
);
2053 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_vert
);
2056 xatom
->setValue(client
.window
, XAtom::net_wm_allowed_actions
, XAtom::atom
,
2061 void BlackboxWindow::setState(unsigned long new_state
) {
2062 current_state
= new_state
;
2064 unsigned long state
[2];
2065 state
[0] = current_state
;
2067 xatom
->setValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
, state
, 2);
2069 xatom
->setValue(client
.window
, XAtom::blackbox_attributes
,
2070 XAtom::blackbox_attributes
, (unsigned long *)&blackbox_attrib
,
2071 PropBlackboxAttributesElements
);
2076 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_modal
);
2078 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_shaded
);
2080 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_hidden
);
2081 if (flags
.skip_taskbar
)
2082 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
);
2083 if (flags
.skip_pager
)
2084 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_pager
);
2085 if (flags
.fullscreen
)
2086 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_fullscreen
);
2087 if (flags
.maximized
== 1 || flags
.maximized
== 2)
2088 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_vert
);
2089 if (flags
.maximized
== 1 || flags
.maximized
== 3)
2090 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_horz
);
2091 xatom
->setValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
2096 bool BlackboxWindow::getState(void) {
2097 bool ret
= xatom
->getValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
,
2099 if (! ret
) current_state
= 0;
2104 void BlackboxWindow::restoreAttributes(void) {
2105 unsigned long num
= PropBlackboxAttributesElements
;
2106 BlackboxAttributes
*net
;
2107 if (! xatom
->getValue(client
.window
, XAtom::blackbox_attributes
,
2108 XAtom::blackbox_attributes
, num
,
2109 (unsigned long **)&net
))
2111 if (num
< PropBlackboxAttributesElements
) {
2116 if (net
->flags
& AttribShaded
&& net
->attrib
& AttribShaded
) {
2117 flags
.shaded
= False
;
2121 Because the iconic'ness of shaded windows is lost, we need to set the
2122 state to NormalState so that shaded windows on other workspaces will not
2123 get shown on the first workspace.
2124 At this point in the life of a window, current_state should only be set
2125 to IconicState if the window was an *icon*, not if it was shaded.
2127 current_state
= NormalState
;
2130 if ((net
->workspace
!= screen
->getCurrentWorkspaceID()) &&
2131 (net
->workspace
< screen
->getWorkspaceCount()))
2132 screen
->reassociateWindow(this, net
->workspace
, True
);
2134 if ((blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID()) &&
2135 (blackbox_attrib
.workspace
< screen
->getWorkspaceCount())) {
2136 // set to WithdrawnState so it will be mapped on the new workspace
2137 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2138 } else if (current_state
== WithdrawnState
) {
2139 // the window is on this workspace and is Withdrawn, so it is waiting to
2141 current_state
= NormalState
;
2144 if (net
->flags
& AttribOmnipresent
&& net
->attrib
& AttribOmnipresent
) {
2145 flags
.stuck
= False
;
2148 // if the window was on another workspace, it was going to be hidden. this
2149 // specifies that the window should be mapped since it is sticky.
2150 if (current_state
== WithdrawnState
) current_state
= NormalState
;
2153 if (net
->flags
& AttribMaxHoriz
|| net
->flags
& AttribMaxVert
) {
2154 int x
= net
->premax_x
, y
= net
->premax_y
;
2155 unsigned int w
= net
->premax_w
, h
= net
->premax_h
;
2156 flags
.maximized
= 0;
2159 if ((net
->flags
& AttribMaxHoriz
) &&
2160 (net
->flags
& AttribMaxVert
))
2161 m
= (net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
2162 else if (net
->flags
& AttribMaxVert
)
2163 m
= (net
->attrib
& AttribMaxVert
) ? 2 : 0;
2164 else if (net
->flags
& AttribMaxHoriz
)
2165 m
= (net
->attrib
& AttribMaxHoriz
) ? 3 : 0;
2169 blackbox_attrib
.premax_x
= x
;
2170 blackbox_attrib
.premax_y
= y
;
2171 blackbox_attrib
.premax_w
= w
;
2172 blackbox_attrib
.premax_h
= h
;
2175 // with the state set it will then be the map event's job to read the
2176 // window's state and behave accordingly
2183 * Positions the Rect r according the the client window position and
2186 void BlackboxWindow::applyGravity(Rect
&r
) {
2187 // apply horizontal window gravity
2188 switch (client
.win_gravity
) {
2190 case NorthWestGravity
:
2191 case SouthWestGravity
:
2193 r
.setX(client
.rect
.x());
2199 r
.setX(client
.rect
.x() - (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2202 case NorthEastGravity
:
2203 case SouthEastGravity
:
2205 r
.setX(client
.rect
.x() - frame
.margin
.left
- frame
.margin
.right
);
2210 r
.setX(client
.rect
.x() - frame
.margin
.left
);
2214 // apply vertical window gravity
2215 switch (client
.win_gravity
) {
2217 case NorthWestGravity
:
2218 case NorthEastGravity
:
2220 r
.setY(client
.rect
.y());
2226 r
.setY(client
.rect
.y() - (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2229 case SouthWestGravity
:
2230 case SouthEastGravity
:
2232 r
.setY(client
.rect
.y() - frame
.margin
.top
- frame
.margin
.bottom
);
2237 r
.setY(client
.rect
.y() - frame
.margin
.top
);
2244 * The reverse of the applyGravity function.
2246 * Positions the Rect r according to the frame window position and
2249 void BlackboxWindow::restoreGravity(Rect
&r
) {
2250 // restore horizontal window gravity
2251 switch (client
.win_gravity
) {
2253 case NorthWestGravity
:
2254 case SouthWestGravity
:
2256 r
.setX(frame
.rect
.x());
2262 r
.setX(frame
.rect
.x() + (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2265 case NorthEastGravity
:
2266 case SouthEastGravity
:
2268 r
.setX(frame
.rect
.x() + frame
.margin
.left
+ frame
.margin
.right
);
2273 r
.setX(frame
.rect
.x() + frame
.margin
.left
);
2277 // restore vertical window gravity
2278 switch (client
.win_gravity
) {
2280 case NorthWestGravity
:
2281 case NorthEastGravity
:
2283 r
.setY(frame
.rect
.y());
2289 r
.setY(frame
.rect
.y() + (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2292 case SouthWestGravity
:
2293 case SouthEastGravity
:
2295 r
.setY(frame
.rect
.y() + frame
.margin
.top
+ frame
.margin
.bottom
);
2300 r
.setY(frame
.rect
.y() + frame
.margin
.top
);
2306 void BlackboxWindow::redrawLabel(void) const {
2307 if (flags
.focused
) {
2309 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2310 frame
.label
, frame
.flabel
);
2312 XSetWindowBackground(blackbox
->getXDisplay(),
2313 frame
.label
, frame
.flabel_pixel
);
2316 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2317 frame
.label
, frame
.ulabel
);
2319 XSetWindowBackground(blackbox
->getXDisplay(),
2320 frame
.label
, frame
.ulabel_pixel
);
2322 XClearWindow(blackbox
->getXDisplay(), frame
.label
);
2324 WindowStyle
*style
= screen
->getWindowStyle();
2326 int pos
= frame
.bevel_w
* 2,
2327 dlen
= style
->doJustify(client
.title
.c_str(), pos
, frame
.label_w
,
2328 frame
.bevel_w
* 4, i18n
.multibyte());
2330 BPen
pen((flags
.focused
) ? style
->l_text_focus
: style
->l_text_unfocus
,
2332 if (i18n
.multibyte())
2333 XmbDrawString(blackbox
->getXDisplay(), frame
.label
, style
->fontset
,
2335 (1 - style
->fontset_extents
->max_ink_extent
.y
),
2336 client
.title
.c_str(), dlen
);
2338 XDrawString(blackbox
->getXDisplay(), frame
.label
, pen
.gc(), pos
,
2339 (style
->font
->ascent
+ 1), client
.title
.c_str(), dlen
);
2343 void BlackboxWindow::redrawAllButtons(void) const {
2344 if (frame
.iconify_button
) redrawIconifyButton(False
);
2345 if (frame
.maximize_button
) redrawMaximizeButton(flags
.maximized
);
2346 if (frame
.close_button
) redrawCloseButton(False
);
2350 void BlackboxWindow::redrawIconifyButton(bool pressed
) const {
2352 if (flags
.focused
) {
2354 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2355 frame
.iconify_button
, frame
.fbutton
);
2357 XSetWindowBackground(blackbox
->getXDisplay(),
2358 frame
.iconify_button
, frame
.fbutton_pixel
);
2361 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2362 frame
.iconify_button
, frame
.ubutton
);
2364 XSetWindowBackground(blackbox
->getXDisplay(), frame
.iconify_button
,
2365 frame
.ubutton_pixel
);
2369 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2370 frame
.iconify_button
, frame
.pbutton
);
2372 XSetWindowBackground(blackbox
->getXDisplay(),
2373 frame
.iconify_button
, frame
.pbutton_pixel
);
2375 XClearWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
2377 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2378 screen
->getWindowStyle()->b_pic_unfocus
);
2379 XDrawRectangle(blackbox
->getXDisplay(), frame
.iconify_button
, pen
.gc(),
2380 2, (frame
.button_w
- 5), (frame
.button_w
- 5), 2);
2384 void BlackboxWindow::redrawMaximizeButton(bool pressed
) const {
2386 if (flags
.focused
) {
2388 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2389 frame
.maximize_button
, frame
.fbutton
);
2391 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2392 frame
.fbutton_pixel
);
2395 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2396 frame
.maximize_button
, frame
.ubutton
);
2398 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2399 frame
.ubutton_pixel
);
2403 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2404 frame
.maximize_button
, frame
.pbutton
);
2406 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2407 frame
.pbutton_pixel
);
2409 XClearWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
2411 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2412 screen
->getWindowStyle()->b_pic_unfocus
);
2413 XDrawRectangle(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2414 2, 2, (frame
.button_w
- 5), (frame
.button_w
- 5));
2415 XDrawLine(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2416 2, 3, (frame
.button_w
- 3), 3);
2420 void BlackboxWindow::redrawCloseButton(bool pressed
) const {
2422 if (flags
.focused
) {
2424 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2427 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2428 frame
.fbutton_pixel
);
2431 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2434 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2435 frame
.ubutton_pixel
);
2439 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2440 frame
.close_button
, frame
.pbutton
);
2442 XSetWindowBackground(blackbox
->getXDisplay(),
2443 frame
.close_button
, frame
.pbutton_pixel
);
2445 XClearWindow(blackbox
->getXDisplay(), frame
.close_button
);
2447 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2448 screen
->getWindowStyle()->b_pic_unfocus
);
2449 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2450 2, 2, (frame
.button_w
- 3), (frame
.button_w
- 3));
2451 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2452 2, (frame
.button_w
- 3), (frame
.button_w
- 3), 2);
2456 void BlackboxWindow::mapRequestEvent(const XMapRequestEvent
*re
) {
2457 if (re
->window
!= client
.window
)
2461 fprintf(stderr
, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2465 switch (current_state
) {
2470 case WithdrawnState
:
2479 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2480 if (! blackbox
->isStartup() && (isTransient() || screen
->doFocusNew())) {
2481 XSync(blackbox
->getXDisplay(), False
); // make sure the frame is mapped..
2489 void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent
*ue
) {
2490 if (ue
->window
!= client
.window
)
2494 fprintf(stderr
, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2498 screen
->unmanageWindow(this, False
);
2502 void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent
*de
) {
2503 if (de
->window
!= client
.window
)
2507 fprintf(stderr
, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2511 screen
->unmanageWindow(this, False
);
2515 void BlackboxWindow::reparentNotifyEvent(const XReparentEvent
*re
) {
2516 if (re
->window
!= client
.window
|| re
->parent
== frame
.plate
)
2520 fprintf(stderr
, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2521 "0x%lx.\n", client
.window
, re
->parent
);
2526 XPutBackEvent(blackbox
->getXDisplay(), &ev
);
2527 screen
->unmanageWindow(this, True
);
2531 void BlackboxWindow::propertyNotifyEvent(Atom atom
) {
2534 case XA_WM_CLIENT_MACHINE
:
2538 case XA_WM_TRANSIENT_FOR
: {
2539 // determine if this is a transient window
2542 // adjust the window decorations based on transience
2543 if (isTransient()) {
2544 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2545 functions
&= ~Func_Maximize
;
2546 setAllowedActions();
2557 case XA_WM_ICON_NAME
:
2559 if (flags
.iconic
) screen
->propagateWindowName(this);
2562 case XAtom::net_wm_name
:
2566 if (decorations
& Decor_Titlebar
)
2569 screen
->propagateWindowName(this);
2572 case XA_WM_NORMAL_HINTS
: {
2575 if ((client
.normal_hint_flags
& PMinSize
) &&
2576 (client
.normal_hint_flags
& PMaxSize
)) {
2577 if (client
.max_width
<= client
.min_width
&&
2578 client
.max_height
<= client
.min_height
) {
2579 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2580 functions
&= ~(Func_Resize
| Func_Maximize
);
2582 decorations
|= Decor_Maximize
| Decor_Handle
;
2583 functions
|= Func_Resize
| Func_Maximize
;
2585 setAllowedActions();
2588 Rect old_rect
= frame
.rect
;
2592 if (old_rect
!= frame
.rect
)
2599 if (atom
== xatom
->getAtom(XAtom::wm_protocols
)) {
2602 if ((decorations
& Decor_Close
) && (! frame
.close_button
)) {
2603 createCloseButton();
2604 if (decorations
& Decor_Titlebar
) {
2605 positionButtons(True
);
2606 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
2608 if (windowmenu
) windowmenu
->reconfigure();
2610 } else if (atom
== xatom
->getAtom(XAtom::net_wm_strut
)) {
2619 void BlackboxWindow::exposeEvent(const XExposeEvent
*ee
) {
2620 if (frame
.label
== ee
->window
&& (decorations
& Decor_Titlebar
))
2622 else if (frame
.close_button
== ee
->window
)
2623 redrawCloseButton(False
);
2624 else if (frame
.maximize_button
== ee
->window
)
2625 redrawMaximizeButton(flags
.maximized
);
2626 else if (frame
.iconify_button
== ee
->window
)
2627 redrawIconifyButton(False
);
2631 void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent
*cr
) {
2632 if (cr
->window
!= client
.window
|| flags
.iconic
)
2635 if (cr
->value_mask
& CWBorderWidth
)
2636 client
.old_bw
= cr
->border_width
;
2638 if (cr
->value_mask
& (CWX
| CWY
| CWWidth
| CWHeight
)) {
2639 Rect req
= frame
.rect
;
2641 if (cr
->value_mask
& (CWX
| CWY
)) {
2642 if (cr
->value_mask
& CWX
)
2643 client
.rect
.setX(cr
->x
);
2644 if (cr
->value_mask
& CWY
)
2645 client
.rect
.setY(cr
->y
);
2650 if (cr
->value_mask
& CWWidth
)
2651 req
.setWidth(cr
->width
+ frame
.margin
.left
+ frame
.margin
.right
);
2653 if (cr
->value_mask
& CWHeight
)
2654 req
.setHeight(cr
->height
+ frame
.margin
.top
+ frame
.margin
.bottom
);
2656 configure(req
.x(), req
.y(), req
.width(), req
.height());
2659 if (cr
->value_mask
& CWStackMode
) {
2660 switch (cr
->detail
) {
2663 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2669 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2676 void BlackboxWindow::buttonPressEvent(const XButtonEvent
*be
) {
2677 if (frame
.maximize_button
== be
->window
) {
2678 redrawMaximizeButton(True
);
2679 } else if (be
->button
== 1 || (be
->button
== 3 && be
->state
== Mod1Mask
)) {
2680 if (! flags
.focused
)
2683 if (frame
.iconify_button
== be
->window
) {
2684 redrawIconifyButton(True
);
2685 } else if (frame
.close_button
== be
->window
) {
2686 redrawCloseButton(True
);
2687 } else if (frame
.plate
== be
->window
) {
2688 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2690 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2692 XAllowEvents(blackbox
->getXDisplay(), ReplayPointer
, be
->time
);
2694 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
2695 if (((be
->time
- lastButtonPressTime
) <=
2696 blackbox
->getDoubleClickInterval()) ||
2697 (be
->state
& ControlMask
)) {
2698 lastButtonPressTime
= 0;
2701 lastButtonPressTime
= be
->time
;
2705 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2707 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2709 } else if (be
->button
== 2 && (be
->window
!= frame
.iconify_button
) &&
2710 (be
->window
!= frame
.close_button
)) {
2711 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2712 } else if (windowmenu
&& be
->button
== 3 &&
2713 (frame
.title
== be
->window
|| frame
.label
== be
->window
||
2714 frame
.handle
== be
->window
|| frame
.window
== be
->window
)) {
2717 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
2718 mx
= be
->x_root
- (windowmenu
->getWidth() / 2);
2719 my
= frame
.rect
.y() + frame
.title_h
+ frame
.border_w
;
2720 } else if (frame
.handle
== be
->window
) {
2721 mx
= be
->x_root
- (windowmenu
->getWidth() / 2);
2722 my
= frame
.rect
.bottom() - frame
.handle_h
- (frame
.border_w
* 3) -
2723 windowmenu
->getHeight();
2725 mx
= be
->x_root
- (windowmenu
->getWidth() / 2);
2727 if (be
->y
<= static_cast<signed>(frame
.bevel_w
))
2728 my
= frame
.rect
.y() + frame
.title_h
;
2730 my
= be
->y_root
- (windowmenu
->getHeight() / 2);
2733 // snap the window menu into a corner if necessary - we check the
2734 // position of the menu with the coordinates of the client to
2735 // make the comparisions easier.
2736 // XXX: this needs some work!
2737 if (mx
> client
.rect
.right() -
2738 static_cast<signed>(windowmenu
->getWidth()))
2739 mx
= frame
.rect
.right() - windowmenu
->getWidth() - frame
.border_w
+ 1;
2740 if (mx
< client
.rect
.left())
2741 mx
= frame
.rect
.x();
2743 if (my
> client
.rect
.bottom() -
2744 static_cast<signed>(windowmenu
->getHeight()))
2745 my
= frame
.rect
.bottom() - windowmenu
->getHeight() - frame
.border_w
+ 1;
2746 if (my
< client
.rect
.top())
2747 my
= frame
.rect
.y() + ((decorations
& Decor_Titlebar
) ?
2751 if (! windowmenu
->isVisible()) {
2752 windowmenu
->move(mx
, my
);
2754 XRaiseWindow(blackbox
->getXDisplay(), windowmenu
->getWindowID());
2755 XRaiseWindow(blackbox
->getXDisplay(),
2756 windowmenu
->getSendToMenu()->getWindowID());
2762 } else if (be
->button
== 4) {
2763 if ((be
->window
== frame
.label
||
2764 be
->window
== frame
.title
) &&
2768 } else if (be
->button
== 5) {
2769 if ((be
->window
== frame
.label
||
2770 be
->window
== frame
.title
) &&
2777 void BlackboxWindow::buttonReleaseEvent(const XButtonEvent
*re
) {
2778 if (re
->window
== frame
.maximize_button
) {
2779 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2780 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2781 maximize(re
->button
);
2783 redrawMaximizeButton(flags
.maximized
);
2785 } else if (re
->window
== frame
.iconify_button
) {
2786 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2787 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2790 redrawIconifyButton(False
);
2792 } else if (re
->window
== frame
.close_button
) {
2793 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2794 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
)))
2796 redrawCloseButton(False
);
2797 } else if (flags
.moving
) {
2799 } else if (flags
.resizing
) {
2801 } else if (re
->window
== frame
.window
) {
2802 if (re
->button
== 2 && re
->state
== Mod1Mask
)
2803 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
2809 void BlackboxWindow::beginMove(int x_root
, int y_root
) {
2810 assert(! (flags
.resizing
|| flags
.moving
));
2813 Only one window can be moved/resized at a time. If another window is already
2814 being moved or resized, then stop it before whating to work with this one.
2816 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
2817 if (changing
&& changing
!= this) {
2818 if (changing
->flags
.moving
)
2819 changing
->endMove();
2820 else // if (changing->flags.resizing)
2821 changing
->endResize();
2824 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
2825 PointerMotionMask
| ButtonReleaseMask
,
2826 GrabModeAsync
, GrabModeAsync
,
2827 None
, blackbox
->getMoveCursor(), CurrentTime
);
2829 if (windowmenu
&& windowmenu
->isVisible())
2832 flags
.moving
= True
;
2833 blackbox
->setChangingWindow(this);
2835 if (! screen
->doOpaqueMove()) {
2836 XGrabServer(blackbox
->getXDisplay());
2838 frame
.changing
= frame
.rect
;
2839 screen
->showPosition(frame
.changing
.x(), frame
.changing
.y());
2841 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2845 frame
.changing
.width() - 1,
2846 frame
.changing
.height() - 1);
2849 frame
.grab_x
= x_root
- frame
.rect
.x() - frame
.border_w
;
2850 frame
.grab_y
= y_root
- frame
.rect
.y() - frame
.border_w
;
2854 void BlackboxWindow::doMove(int x_root
, int y_root
) {
2855 assert(flags
.moving
);
2856 assert(blackbox
->getChangingWindow() == this);
2858 int dx
= x_root
- frame
.grab_x
, dy
= y_root
- frame
.grab_y
;
2859 dx
-= frame
.border_w
;
2860 dy
-= frame
.border_w
;
2862 const int snap_distance
= screen
->getEdgeSnapThreshold();
2864 if (snap_distance
) {
2866 const int wleft
= dx
,
2867 wright
= dx
+ frame
.rect
.width() - 1,
2869 wbottom
= dy
+ frame
.rect
.height() - 1;
2871 if (screen
->getWindowToWindowSnap()) {
2872 Workspace
*w
= screen
->getWorkspace(getWorkspaceNumber());
2875 // try snap to another window
2876 for (unsigned int i
= 0, c
= w
->getCount(); i
< c
; ++i
) {
2877 BlackboxWindow
*snapwin
= w
->getWindow(i
);
2878 if (snapwin
== this)
2879 continue; // don't snap to self
2881 bool snapped
= False
;
2883 const Rect
&winrect
= snapwin
->frameRect();
2884 int dleft
= std::abs(wright
- winrect
.left()),
2885 dright
= std::abs(wleft
- winrect
.right()),
2886 dtop
= std::abs(wbottom
- winrect
.top()),
2887 dbottom
= std::abs(wtop
- winrect
.bottom());
2889 if (wtop
>= (signed)(winrect
.y() - frame
.rect
.height() + 1) &&
2890 wtop
< (signed)(winrect
.y() + winrect
.height() - 1)) {
2892 // snap left of other window?
2893 if (dleft
< snap_distance
&& dleft
<= dright
) {
2894 dx
= winrect
.left() - frame
.rect
.width();
2897 // snap right of other window?
2898 else if (dright
< snap_distance
) {
2899 dx
= winrect
.right() + 1;
2904 if (screen
->getWindowCornerSnap()) {
2905 // try corner-snap to its other sides
2906 dtop
= std::abs(wtop
- winrect
.top());
2907 dbottom
= std::abs(wbottom
- winrect
.bottom());
2908 if (dtop
< snap_distance
&& dtop
<= dbottom
)
2910 else if (dbottom
< snap_distance
)
2911 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
2918 if (wleft
>= (signed)(winrect
.x() - frame
.rect
.width() + 1) &&
2919 wleft
< (signed)(winrect
.x() + winrect
.width() - 1)) {
2921 // snap top of other window?
2922 if (dtop
< snap_distance
&& dtop
<= dbottom
) {
2923 dy
= winrect
.top() - frame
.rect
.height();
2926 // snap bottom of other window?
2927 else if (dbottom
< snap_distance
) {
2928 dy
= winrect
.bottom() + 1;
2933 if (screen
->getWindowCornerSnap()) {
2934 // try corner-snap to its other sides
2935 dleft
= std::abs(wleft
- winrect
.left());
2936 dright
= std::abs(wright
- winrect
.right());
2937 if (dleft
< snap_distance
&& dleft
<= dright
)
2938 dx
= winrect
.left();
2939 else if (dright
< snap_distance
)
2940 dx
= winrect
.right() - frame
.rect
.width() + 1;
2949 // try snap to the screen's available area
2950 Rect srect
= screen
->availableArea();
2952 int dleft
= std::abs(wleft
- srect
.left()),
2953 dright
= std::abs(wright
- srect
.right()),
2954 dtop
= std::abs(wtop
- srect
.top()),
2955 dbottom
= std::abs(wbottom
- srect
.bottom());
2958 if (dleft
< snap_distance
&& dleft
<= dright
)
2961 else if (dright
< snap_distance
)
2962 dx
= srect
.right() - frame
.rect
.width() + 1;
2965 if (dtop
< snap_distance
&& dtop
<= dbottom
)
2968 else if (dbottom
< snap_distance
)
2969 dy
= srect
.bottom() - frame
.rect
.height() + 1;
2971 srect
= screen
->getRect(); // now get the full screen
2973 dleft
= std::abs(wleft
- srect
.left()),
2974 dright
= std::abs(wright
- srect
.right()),
2975 dtop
= std::abs(wtop
- srect
.top()),
2976 dbottom
= std::abs(wbottom
- srect
.bottom());
2979 if (dleft
< snap_distance
&& dleft
<= dright
)
2982 else if (dright
< snap_distance
)
2983 dx
= srect
.right() - frame
.rect
.width() + 1;
2986 if (dtop
< snap_distance
&& dtop
<= dbottom
)
2989 else if (dbottom
< snap_distance
)
2990 dy
= srect
.bottom() - frame
.rect
.height() + 1;
2993 if (screen
->doOpaqueMove()) {
2994 configure(dx
, dy
, frame
.rect
.width(), frame
.rect
.height());
2996 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3000 frame
.changing
.width() - 1,
3001 frame
.changing
.height() - 1);
3003 frame
.changing
.setPos(dx
, dy
);
3005 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3009 frame
.changing
.width() - 1,
3010 frame
.changing
.height() - 1);
3013 screen
->showPosition(dx
, dy
);
3017 void BlackboxWindow::endMove(void) {
3018 assert(flags
.moving
);
3019 assert(blackbox
->getChangingWindow() == this);
3021 flags
.moving
= False
;
3022 blackbox
->setChangingWindow(0);
3024 if (! screen
->doOpaqueMove()) {
3025 /* when drawing the rubber band, we need to make sure we only draw inside
3026 * the frame... frame.changing_* contain the new coords for the window,
3027 * so we need to subtract 1 from changing_w/changing_h every where we
3028 * draw the rubber band (for both moving and resizing)
3030 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3031 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3032 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3033 XUngrabServer(blackbox
->getXDisplay());
3035 configure(frame
.changing
.x(), frame
.changing
.y(),
3036 frame
.changing
.width(), frame
.changing
.height());
3038 configure(frame
.rect
.x(), frame
.rect
.y(),
3039 frame
.rect
.width(), frame
.rect
.height());
3041 screen
->hideGeometry();
3043 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3045 // if there are any left over motions from the move, drop them now
3046 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3048 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3053 void BlackboxWindow::beginResize(int x_root
, int y_root
, Corner dir
) {
3054 assert(! (flags
.resizing
|| flags
.moving
));
3057 Only one window can be moved/resized at a time. If another window is already
3058 being moved or resized, then stop it before whating to work with this one.
3060 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3061 if (changing
&& changing
!= this) {
3062 if (changing
->flags
.moving
)
3063 changing
->endMove();
3064 else // if (changing->flags.resizing)
3065 changing
->endResize();
3073 switch (resize_dir
) {
3076 cursor
= blackbox
->getLowerLeftAngleCursor();
3081 cursor
= blackbox
->getLowerRightAngleCursor();
3085 anchor
= BottomRight
;
3086 cursor
= blackbox
->getUpperLeftAngleCursor();
3090 anchor
= BottomLeft
;
3091 cursor
= blackbox
->getUpperRightAngleCursor();
3095 assert(false); // unhandled Corner
3098 XGrabServer(blackbox
->getXDisplay());
3099 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3100 PointerMotionMask
| ButtonReleaseMask
,
3101 GrabModeAsync
, GrabModeAsync
, None
, cursor
, CurrentTime
);
3103 flags
.resizing
= True
;
3104 blackbox
->setChangingWindow(this);
3107 frame
.changing
= frame
.rect
;
3109 constrain(anchor
, &gw
, &gh
);
3111 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3112 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3113 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3115 screen
->showGeometry(gw
, gh
);
3117 frame
.grab_x
= x_root
;
3118 frame
.grab_y
= y_root
;
3122 void BlackboxWindow::doResize(int x_root
, int y_root
) {
3123 assert(flags
.resizing
);
3124 assert(blackbox
->getChangingWindow() == this);
3126 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3127 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3128 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3133 switch (resize_dir
) {
3136 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3137 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3141 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3142 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3145 anchor
= BottomRight
;
3146 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3147 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3150 anchor
= BottomLeft
;
3151 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3152 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3156 assert(false); // unhandled Corner
3159 constrain(anchor
, &gw
, &gh
);
3161 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3162 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3163 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3165 screen
->showGeometry(gw
, gh
);
3169 void BlackboxWindow::endResize(void) {
3170 assert(flags
.resizing
);
3171 assert(blackbox
->getChangingWindow() == this);
3173 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3174 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3175 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3176 XUngrabServer(blackbox
->getXDisplay());
3178 // unset maximized state after resized when fully maximized
3179 if (flags
.maximized
== 1)
3182 flags
.resizing
= False
;
3183 blackbox
->setChangingWindow(0);
3185 configure(frame
.changing
.x(), frame
.changing
.y(),
3186 frame
.changing
.width(), frame
.changing
.height());
3187 screen
->hideGeometry();
3189 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3191 // if there are any left over motions from the resize, drop them now
3192 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3194 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3199 void BlackboxWindow::motionNotifyEvent(const XMotionEvent
*me
) {
3201 doMove(me
->x_root
, me
->y_root
);
3202 } else if (flags
.resizing
) {
3203 doResize(me
->x_root
, me
->y_root
);
3205 if (! flags
.resizing
&& (me
->state
& Button1Mask
) &&
3206 (functions
& Func_Move
) &&
3207 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3208 frame
.handle
== me
->window
|| frame
.window
== me
->window
)) {
3209 beginMove(me
->x_root
, me
->y_root
);
3210 } else if ((functions
& Func_Resize
) &&
3211 (((me
->state
& Button1Mask
) &&
3212 (me
->window
== frame
.right_grip
||
3213 me
->window
== frame
.left_grip
)) ||
3214 (me
->state
& (Mod1Mask
| Button3Mask
) &&
3215 me
->window
== frame
.window
))) {
3216 beginResize(me
->x_root
, me
->y_root
,
3217 (me
->window
== frame
.left_grip
) ? BottomLeft
: BottomRight
);
3224 void BlackboxWindow::shapeEvent(XShapeEvent
*) {
3225 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
3232 bool BlackboxWindow::validateClient(void) const {
3233 XSync(blackbox
->getXDisplay(), False
);
3236 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3237 DestroyNotify
, &e
) ||
3238 XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3240 XPutBackEvent(blackbox
->getXDisplay(), &e
);
3249 void BlackboxWindow::restore(bool remap
) {
3250 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeDelete
);
3251 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
3252 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, NoEventMask
);
3254 restoreGravity(client
.rect
);
3256 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
3257 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
3259 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, client
.old_bw
);
3262 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3263 ReparentNotify
, &ev
)) {
3266 // according to the ICCCM - if the client doesn't reparent to
3267 // root, then we have to do it for them
3268 XReparentWindow(blackbox
->getXDisplay(), client
.window
,
3269 screen
->getRootWindow(),
3270 client
.rect
.x(), client
.rect
.y());
3273 if (remap
) XMapWindow(blackbox
->getXDisplay(), client
.window
);
3277 // timer for autoraise
3278 void BlackboxWindow::timeout(void) {
3279 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3283 void BlackboxWindow::changeBlackboxHints(BlackboxHints
*net
) {
3284 if ((net
->flags
& AttribShaded
) &&
3285 ((blackbox_attrib
.attrib
& AttribShaded
) !=
3286 (net
->attrib
& AttribShaded
)))
3289 if (flags
.visible
&& // watch out for requests when we can not be seen
3290 (net
->flags
& (AttribMaxVert
| AttribMaxHoriz
)) &&
3291 ((blackbox_attrib
.attrib
& (AttribMaxVert
| AttribMaxHoriz
)) !=
3292 (net
->attrib
& (AttribMaxVert
| AttribMaxHoriz
)))) {
3293 if (flags
.maximized
) {
3298 if ((net
->flags
& AttribMaxHoriz
) && (net
->flags
& AttribMaxVert
))
3299 button
= ((net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0);
3300 else if (net
->flags
& AttribMaxVert
)
3301 button
= ((net
->attrib
& AttribMaxVert
) ? 2 : 0);
3302 else if (net
->flags
& AttribMaxHoriz
)
3303 button
= ((net
->attrib
& AttribMaxHoriz
) ? 3 : 0);
3309 if ((net
->flags
& AttribOmnipresent
) &&
3310 ((blackbox_attrib
.attrib
& AttribOmnipresent
) !=
3311 (net
->attrib
& AttribOmnipresent
)))
3314 if ((net
->flags
& AttribWorkspace
) &&
3315 (blackbox_attrib
.workspace
!= net
->workspace
)) {
3316 screen
->reassociateWindow(this, net
->workspace
, True
);
3318 if (screen
->getCurrentWorkspaceID() != net
->workspace
) {
3322 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3326 if (net
->flags
& AttribDecoration
) {
3327 switch (net
->decoration
) {
3329 // clear all decorations except close
3330 decorations
&= Decor_Close
;
3336 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Iconify
;
3338 decorations
= ((functions
& Func_Resize
) && !isTransient() ?
3339 decorations
| Decor_Handle
:
3340 decorations
&= ~Decor_Handle
);
3341 decorations
= (functions
& Func_Maximize
?
3342 decorations
| Decor_Maximize
:
3343 decorations
&= ~Decor_Maximize
);
3348 decorations
|= Decor_Titlebar
| Decor_Iconify
;
3349 decorations
&= ~(Decor_Border
| Decor_Handle
);
3351 decorations
= (functions
& Func_Maximize
?
3352 decorations
| Decor_Maximize
:
3353 decorations
&= ~Decor_Maximize
);
3358 decorations
|= Decor_Titlebar
;
3359 decorations
&= ~(Decor_Iconify
| Decor_Border
);
3361 decorations
= ((functions
& Func_Resize
) && !isTransient() ?
3362 decorations
| Decor_Handle
:
3363 decorations
&= ~Decor_Handle
);
3364 decorations
= (functions
& Func_Maximize
?
3365 decorations
| Decor_Maximize
:
3366 decorations
&= ~Decor_Maximize
);
3371 // we can not be shaded if we lack a titlebar
3372 if (flags
.shaded
&& ! (decorations
& Decor_Titlebar
))
3375 if (flags
.visible
&& frame
.window
) {
3376 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
3377 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
3381 setState(current_state
);
3387 * Set the sizes of all components of the window frame
3388 * (the window decorations).
3389 * These values are based upon the current style settings and the client
3390 * window's dimensions.
3392 void BlackboxWindow::upsize(void) {
3393 frame
.bevel_w
= screen
->getBevelWidth();
3395 if (decorations
& Decor_Border
) {
3396 frame
.border_w
= screen
->getBorderWidth();
3397 if (! isTransient())
3398 frame
.mwm_border_w
= screen
->getFrameWidth();
3400 frame
.mwm_border_w
= 0;
3402 frame
.mwm_border_w
= frame
.border_w
= 0;
3405 if (decorations
& Decor_Titlebar
) {
3406 // the height of the titlebar is based upon the height of the font being
3407 // used to display the window's title
3408 WindowStyle
*style
= screen
->getWindowStyle();
3409 if (i18n
.multibyte())
3410 frame
.title_h
= (style
->fontset_extents
->max_ink_extent
.height
+
3411 (frame
.bevel_w
* 2) + 2);
3413 frame
.title_h
= (style
->font
->ascent
+ style
->font
->descent
+
3414 (frame
.bevel_w
* 2) + 2);
3416 frame
.label_h
= frame
.title_h
- (frame
.bevel_w
* 2);
3417 frame
.button_w
= (frame
.label_h
- 2);
3419 // set the top frame margin
3420 frame
.margin
.top
= frame
.border_w
+ frame
.title_h
+
3421 frame
.border_w
+ frame
.mwm_border_w
;
3427 // set the top frame margin
3428 frame
.margin
.top
= frame
.border_w
+ frame
.mwm_border_w
;
3431 // set the left/right frame margin
3432 frame
.margin
.left
= frame
.margin
.right
= frame
.border_w
+ frame
.mwm_border_w
;
3434 if (decorations
& Decor_Handle
) {
3435 frame
.grip_w
= frame
.button_w
* 2;
3436 frame
.handle_h
= screen
->getHandleWidth();
3438 // set the bottom frame margin
3439 frame
.margin
.bottom
= frame
.border_w
+ frame
.handle_h
+
3440 frame
.border_w
+ frame
.mwm_border_w
;
3445 // set the bottom frame margin
3446 frame
.margin
.bottom
= frame
.border_w
+ frame
.mwm_border_w
;
3450 We first get the normal dimensions and use this to define the inside_w/h
3451 then we modify the height if shading is in effect.
3452 If the shade state is not considered then frame.rect gets reset to the
3453 normal window size on a reconfigure() call resulting in improper
3454 dimensions appearing in move/resize and other events.
3457 height
= client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
,
3458 width
= client
.rect
.width() + frame
.margin
.left
+ frame
.margin
.right
;
3460 frame
.inside_w
= width
- (frame
.border_w
* 2);
3461 frame
.inside_h
= height
- (frame
.border_w
* 2);
3464 height
= frame
.title_h
+ (frame
.border_w
* 2);
3465 frame
.rect
.setSize(width
, height
);
3470 * Calculate the size of the client window and constrain it to the
3471 * size specified by the size hints of the client window.
3473 * The logical width and height are placed into pw and ph, if they
3474 * are non-zero. Logical size refers to the users perception of
3475 * the window size (for example an xterm resizes in cells, not in pixels).
3477 * The physical geometry is placed into frame.changing_{x,y,width,height}.
3478 * Physical geometry refers to the geometry of the window in pixels.
3480 void BlackboxWindow::constrain(Corner anchor
, int *pw
, int *ph
) {
3481 // frame.changing represents the requested frame size, we need to
3482 // strip the frame margin off and constrain the client size
3483 frame
.changing
.setCoords(frame
.changing
.left() + frame
.margin
.left
,
3484 frame
.changing
.top() + frame
.margin
.top
,
3485 frame
.changing
.right() - frame
.margin
.right
,
3486 frame
.changing
.bottom() - frame
.margin
.bottom
);
3488 int dw
= frame
.changing
.width(), dh
= frame
.changing
.height(),
3489 base_width
= (client
.base_width
) ? client
.base_width
: client
.min_width
,
3490 base_height
= (client
.base_height
) ? client
.base_height
:
3494 if (dw
< static_cast<signed>(client
.min_width
)) dw
= client
.min_width
;
3495 if (dh
< static_cast<signed>(client
.min_height
)) dh
= client
.min_height
;
3496 if (dw
> static_cast<signed>(client
.max_width
)) dw
= client
.max_width
;
3497 if (dh
> static_cast<signed>(client
.max_height
)) dh
= client
.max_height
;
3500 dw
/= client
.width_inc
;
3502 dh
/= client
.height_inc
;
3505 if (client
.width_inc
== 1)
3506 *pw
= dw
+ base_width
;
3511 if (client
.height_inc
== 1)
3512 *ph
= dh
+ base_height
;
3517 dw
*= client
.width_inc
;
3519 dh
*= client
.height_inc
;
3522 frame
.changing
.setSize(dw
, dh
);
3524 // add the frame margin back onto frame.changing
3525 frame
.changing
.setCoords(frame
.changing
.left() - frame
.margin
.left
,
3526 frame
.changing
.top() - frame
.margin
.top
,
3527 frame
.changing
.right() + frame
.margin
.right
,
3528 frame
.changing
.bottom() + frame
.margin
.bottom
);
3530 // move frame.changing to the specified anchor
3538 dx
= frame
.rect
.right() - frame
.changing
.right();
3542 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3546 dx
= frame
.rect
.right() - frame
.changing
.right();
3547 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3551 assert(false); // unhandled corner
3553 frame
.changing
.setPos(frame
.changing
.x() + dx
, frame
.changing
.y() + dy
);
3557 int WindowStyle::doJustify(const char *text
, int &start_pos
,
3558 unsigned int max_length
, unsigned int modifier
,
3559 bool multibyte
) const {
3560 size_t text_len
= strlen(text
);
3561 unsigned int length
;
3565 XRectangle ink
, logical
;
3566 XmbTextExtents(fontset
, text
, text_len
, &ink
, &logical
);
3567 length
= logical
.width
;
3569 length
= XTextWidth(font
, text
, text_len
);
3572 } while (length
> max_length
&& text_len
-- > 0);
3576 start_pos
+= max_length
- length
;
3580 start_pos
+= (max_length
- length
) / 2;
3592 BWindowGroup::BWindowGroup(Blackbox
*b
, Window _group
)
3593 : blackbox(b
), group(_group
) {
3594 XWindowAttributes wattrib
;
3595 if (! XGetWindowAttributes(blackbox
->getXDisplay(), group
, &wattrib
)) {
3596 // group window doesn't seem to exist anymore
3602 watch for destroy notify on the group window (in addition to
3603 any other events we are looking for)
3605 since some managed windows can also be window group controllers,
3606 we need to make sure that we don't clobber the event mask for the
3609 XSelectInput(blackbox
->getXDisplay(), group
,
3610 wattrib
.your_event_mask
| StructureNotifyMask
);
3612 blackbox
->saveGroupSearch(group
, this);
3616 BWindowGroup::~BWindowGroup(void) {
3617 blackbox
->removeGroupSearch(group
);
3622 BWindowGroup::find(BScreen
*screen
, bool allow_transients
) const {
3623 BlackboxWindow
*ret
= blackbox
->getFocusedWindow();
3625 // does the focus window match (or any transient_fors)?
3627 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3628 if (ret
->isTransient() && allow_transients
) break;
3629 else if (! ret
->isTransient()) break;
3632 ret
= ret
->getTransientFor();
3635 if (ret
) return ret
;
3637 // the focus window didn't match, look in the group's window list
3638 BlackboxWindowList::const_iterator it
, end
= windowList
.end();
3639 for (it
= windowList
.begin(); it
!= end
; ++it
) {
3641 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3642 if (ret
->isTransient() && allow_transients
) break;
3643 else if (! ret
->isTransient()) break;