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
) ||
1229 num
< PropMwmHintsElements
)
1232 if (mwm_hint
->flags
& MwmHintsDecorations
) {
1233 if (mwm_hint
->decorations
& MwmDecorAll
) {
1234 decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
1235 Decor_Iconify
| Decor_Maximize
| Decor_Close
;
1239 if (mwm_hint
->decorations
& MwmDecorBorder
)
1240 decorations
|= Decor_Border
;
1241 if (mwm_hint
->decorations
& MwmDecorHandle
)
1242 decorations
|= Decor_Handle
;
1243 if (mwm_hint
->decorations
& MwmDecorTitle
)
1244 decorations
|= Decor_Titlebar
;
1245 if (mwm_hint
->decorations
& MwmDecorIconify
)
1246 decorations
|= Decor_Iconify
;
1247 if (mwm_hint
->decorations
& MwmDecorMaximize
)
1248 decorations
|= Decor_Maximize
;
1252 if (mwm_hint
->flags
& MwmHintsFunctions
) {
1253 if (mwm_hint
->functions
& MwmFuncAll
) {
1254 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
|
1259 if (mwm_hint
->functions
& MwmFuncResize
)
1260 functions
|= Func_Resize
;
1261 if (mwm_hint
->functions
& MwmFuncMove
)
1262 functions
|= Func_Move
;
1263 if (mwm_hint
->functions
& MwmFuncIconify
)
1264 functions
|= Func_Iconify
;
1265 if (mwm_hint
->functions
& MwmFuncMaximize
)
1266 functions
|= Func_Maximize
;
1267 if (mwm_hint
->functions
& MwmFuncClose
)
1268 functions
|= Func_Close
;
1276 * Gets the blackbox hints from the class' contained window.
1277 * This is used while initializing the window to its first state, and not
1279 * Returns: true if the hints are successfully retreived and applied; false if
1282 bool BlackboxWindow::getBlackboxHints(void) {
1284 BlackboxHints
*blackbox_hint
;
1286 num
= PropBlackboxHintsElements
;
1287 if (! xatom
->getValue(client
.window
, XAtom::blackbox_hints
,
1288 XAtom::blackbox_hints
, num
,
1289 (unsigned long **)&blackbox_hint
) ||
1290 num
< PropBlackboxHintsElements
)
1293 if (blackbox_hint
->flags
& AttribShaded
)
1294 flags
.shaded
= (blackbox_hint
->attrib
& AttribShaded
);
1296 if ((blackbox_hint
->flags
& AttribMaxHoriz
) &&
1297 (blackbox_hint
->flags
& AttribMaxVert
))
1298 flags
.maximized
= (blackbox_hint
->attrib
&
1299 (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1300 else if (blackbox_hint
->flags
& AttribMaxVert
)
1301 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxVert
) ? 2 : 0;
1302 else if (blackbox_hint
->flags
& AttribMaxHoriz
)
1303 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1305 if (blackbox_hint
->flags
& AttribOmnipresent
)
1306 flags
.stuck
= (blackbox_hint
->attrib
& AttribOmnipresent
);
1308 if (blackbox_hint
->flags
& AttribWorkspace
)
1309 blackbox_attrib
.workspace
= blackbox_hint
->workspace
;
1311 // if (blackbox_hint->flags & AttribStack)
1312 // don't yet have always on top/bottom for blackbox yet... working
1315 if (blackbox_hint
->flags
& AttribDecoration
) {
1316 switch (blackbox_hint
->decoration
) {
1318 // clear all decorations except close
1319 decorations
&= Decor_Close
;
1320 // clear all functions except close
1321 functions
&= Func_Close
;
1326 decorations
|= Decor_Titlebar
| Decor_Iconify
;
1327 decorations
&= ~(Decor_Border
| Decor_Handle
| Decor_Maximize
);
1328 functions
|= Func_Move
| Func_Iconify
;
1329 functions
&= ~(Func_Resize
| Func_Maximize
);
1334 decorations
|= Decor_Titlebar
;
1335 decorations
&= ~(Decor_Iconify
| Decor_Border
| Decor_Handle
);
1336 functions
|= Func_Move
;
1337 functions
&= ~(Func_Resize
| Func_Maximize
| Func_Iconify
);
1343 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Handle
|
1344 Decor_Iconify
| Decor_Maximize
;
1345 functions
|= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
1353 delete blackbox_hint
;
1359 void BlackboxWindow::getTransientInfo(void) {
1360 if (client
.transient_for
&&
1361 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1362 // the transient for hint was removed, so we need to tell our
1363 // previous transient_for that we are going away
1364 client
.transient_for
->client
.transientList
.remove(this);
1367 // we have no transient_for until we find a new one
1368 client
.transient_for
= 0;
1371 if (! XGetTransientForHint(blackbox
->getXDisplay(), client
.window
,
1373 // transient_for hint not set
1377 if (trans_for
== client
.window
) {
1378 // wierd client... treat this window as a normal window
1382 if (trans_for
== None
|| trans_for
== screen
->getRootWindow()) {
1383 // this is an undocumented interpretation of the ICCCM. a transient
1384 // associated with None/Root/itself is assumed to be a modal root
1385 // transient. we don't support the concept of a global transient,
1386 // so we just associate this transient with nothing, and perhaps
1387 // we will add support later for global modality.
1388 client
.transient_for
= (BlackboxWindow
*) ~0ul;
1393 client
.transient_for
= blackbox
->searchWindow(trans_for
);
1394 if (! client
.transient_for
&&
1395 client
.window_group
&& trans_for
== client
.window_group
) {
1396 // no direct transient_for, perhaps this is a group transient?
1397 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1398 if (group
) client
.transient_for
= group
->find(screen
);
1401 if (! client
.transient_for
|| client
.transient_for
== this) {
1402 // no transient_for found, or we have a wierd client that wants to be
1403 // a transient for itself, so we treat this window as a normal window
1404 client
.transient_for
= (BlackboxWindow
*) 0;
1408 // register ourselves with our new transient_for
1409 client
.transient_for
->client
.transientList
.push_back(this);
1410 flags
.stuck
= client
.transient_for
->flags
.stuck
;
1414 bool BlackboxWindow::isKDESystrayWindow(void) {
1416 if (xatom
->getValue(client
.window
, XAtom::kde_net_wm_system_tray_window_for
,
1417 XAtom::window
, systray
) && systray
)
1423 BlackboxWindow
*BlackboxWindow::getTransientFor(void) const {
1424 if (client
.transient_for
&&
1425 client
.transient_for
!= (BlackboxWindow
*) ~0ul)
1426 return client
.transient_for
;
1431 void BlackboxWindow::configure(int dx
, int dy
,
1432 unsigned int dw
, unsigned int dh
) {
1433 bool send_event
= False
;
1435 if (dw
!= frame
.rect
.width() || dh
!= frame
.rect
.height()) {
1436 frame
.rect
.setRect(dx
, dy
, dw
, dh
);
1437 frame
.inside_w
= frame
.rect
.width() - (frame
.border_w
* 2);
1438 frame
.inside_h
= frame
.rect
.height() - (frame
.border_w
* 2);
1440 if (frame
.rect
.right() <= 0 || frame
.rect
.bottom() <= 0)
1441 frame
.rect
.setPos(0, 0);
1443 client
.rect
.setCoords(frame
.rect
.left() + frame
.margin
.left
,
1444 frame
.rect
.top() + frame
.margin
.top
,
1445 frame
.rect
.right() - frame
.margin
.right
,
1446 frame
.rect
.bottom() - frame
.margin
.bottom
);
1449 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
1456 redrawWindowFrame();
1457 } else if (frame
.rect
.x() != dx
|| frame
.rect
.y() != dy
) {
1460 frame
.rect
.setPos(dx
, dy
);
1462 XMoveWindow(blackbox
->getXDisplay(), frame
.window
,
1463 frame
.rect
.x(), frame
.rect
.y());
1466 if (send_event
&& ! flags
.moving
) {
1467 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1468 frame
.rect
.top() + frame
.margin
.top
);
1471 event
.type
= ConfigureNotify
;
1473 event
.xconfigure
.display
= blackbox
->getXDisplay();
1474 event
.xconfigure
.event
= client
.window
;
1475 event
.xconfigure
.window
= client
.window
;
1476 event
.xconfigure
.x
= client
.rect
.x();
1477 event
.xconfigure
.y
= client
.rect
.y();
1478 event
.xconfigure
.width
= client
.rect
.width();
1479 event
.xconfigure
.height
= client
.rect
.height();
1480 event
.xconfigure
.border_width
= client
.old_bw
;
1481 event
.xconfigure
.above
= frame
.window
;
1482 event
.xconfigure
.override_redirect
= False
;
1484 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1485 StructureNotifyMask
, &event
);
1487 screen
->updateNetizenConfigNotify(&event
);
1493 void BlackboxWindow::configureShape(void) {
1494 XShapeCombineShape(blackbox
->getXDisplay(), frame
.window
, ShapeBounding
,
1495 frame
.margin
.left
- frame
.border_w
,
1496 frame
.margin
.top
- frame
.border_w
,
1497 client
.window
, ShapeBounding
, ShapeSet
);
1500 XRectangle xrect
[2];
1502 if (decorations
& Decor_Titlebar
) {
1503 xrect
[0].x
= xrect
[0].y
= -frame
.border_w
;
1504 xrect
[0].width
= frame
.rect
.width();
1505 xrect
[0].height
= frame
.title_h
+ (frame
.border_w
* 2);
1509 if (decorations
& Decor_Handle
) {
1510 xrect
[1].x
= -frame
.border_w
;
1511 xrect
[1].y
= frame
.rect
.height() - frame
.margin
.bottom
+
1512 frame
.mwm_border_w
- frame
.border_w
;
1513 xrect
[1].width
= frame
.rect
.width();
1514 xrect
[1].height
= frame
.handle_h
+ (frame
.border_w
* 2);
1518 XShapeCombineRectangles(blackbox
->getXDisplay(), frame
.window
,
1519 ShapeBounding
, 0, 0, xrect
, num
,
1520 ShapeUnion
, Unsorted
);
1525 bool BlackboxWindow::setInputFocus(void) {
1526 if (flags
.focused
) return True
;
1528 assert(! flags
.iconic
);
1530 // if the window is not visible, mark the window as wanting focus rather
1531 // than give it focus.
1532 if (! flags
.visible
) {
1533 Workspace
*wkspc
= screen
->getWorkspace(blackbox_attrib
.workspace
);
1534 wkspc
->setLastFocusedWindow(this);
1538 if (! frame
.rect
.intersects(screen
->getRect())) {
1539 // client is outside the screen, move it to the center
1540 configure((screen
->getWidth() - frame
.rect
.width()) / 2,
1541 (screen
->getHeight() - frame
.rect
.height()) / 2,
1542 frame
.rect
.width(), frame
.rect
.height());
1545 if (client
.transientList
.size() > 0) {
1546 // transfer focus to any modal transients
1547 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1548 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1549 if ((*it
)->flags
.modal
) return (*it
)->setInputFocus();
1554 if (focus_mode
== F_LocallyActive
|| focus_mode
== F_Passive
) {
1555 XSetInputFocus(blackbox
->getXDisplay(), client
.window
,
1556 RevertToPointerRoot
, CurrentTime
);
1558 blackbox
->setFocusedWindow(this);
1560 /* we could set the focus to none, since the window doesn't accept focus,
1561 * but we shouldn't set focus to nothing since this would surely make
1567 if (flags
.send_focus_message
) {
1569 ce
.xclient
.type
= ClientMessage
;
1570 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1571 ce
.xclient
.display
= blackbox
->getXDisplay();
1572 ce
.xclient
.window
= client
.window
;
1573 ce
.xclient
.format
= 32;
1574 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_take_focus
);
1575 ce
.xclient
.data
.l
[1] = blackbox
->getLastTime();
1576 ce
.xclient
.data
.l
[2] = 0l;
1577 ce
.xclient
.data
.l
[3] = 0l;
1578 ce
.xclient
.data
.l
[4] = 0l;
1579 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1587 void BlackboxWindow::iconify(void) {
1588 if (flags
.iconic
) return;
1590 // We don't need to worry about resizing because resizing always grabs the X
1591 // server. This should only ever happen if using opaque moving.
1595 if (windowmenu
) windowmenu
->hide();
1598 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1599 * we need to clear the event mask on client.window for a split second.
1600 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1601 * split second, leaving us with a ghost window... so, we need to do this
1602 * while the X server is grabbed
1604 XGrabServer(blackbox
->getXDisplay());
1605 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
1606 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1607 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1608 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
1609 XUngrabServer(blackbox
->getXDisplay());
1611 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1612 flags
.visible
= False
;
1613 flags
.iconic
= True
;
1615 setState(IconicState
);
1617 screen
->getWorkspace(blackbox_attrib
.workspace
)->removeWindow(this);
1619 if (isTransient()) {
1620 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1621 ! client
.transient_for
->flags
.iconic
) {
1622 // iconify our transient_for
1623 client
.transient_for
->iconify();
1627 screen
->addIcon(this);
1629 if (client
.transientList
.size() > 0) {
1630 // iconify all transients
1631 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1632 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1633 if (! (*it
)->flags
.iconic
) (*it
)->iconify();
1639 void BlackboxWindow::show(void) {
1640 flags
.visible
= True
;
1641 flags
.iconic
= False
;
1643 current_state
= (flags
.shaded
) ? IconicState
: NormalState
;
1644 setState(current_state
);
1646 XMapWindow(blackbox
->getXDisplay(), client
.window
);
1647 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
1648 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
1652 void BlackboxWindow::deiconify(bool reassoc
, bool raise
) {
1653 if (flags
.iconic
|| reassoc
)
1654 screen
->reassociateWindow(this, BSENTINEL
, False
);
1655 else if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspace()->getID())
1660 // reassociate and deiconify all transients
1661 if (reassoc
&& client
.transientList
.size() > 0) {
1662 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1663 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1664 (*it
)->deiconify(True
, False
);
1669 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1673 void BlackboxWindow::close(void) {
1675 ce
.xclient
.type
= ClientMessage
;
1676 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1677 ce
.xclient
.display
= blackbox
->getXDisplay();
1678 ce
.xclient
.window
= client
.window
;
1679 ce
.xclient
.format
= 32;
1680 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_delete_window
);
1681 ce
.xclient
.data
.l
[1] = CurrentTime
;
1682 ce
.xclient
.data
.l
[2] = 0l;
1683 ce
.xclient
.data
.l
[3] = 0l;
1684 ce
.xclient
.data
.l
[4] = 0l;
1685 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
, NoEventMask
, &ce
);
1689 void BlackboxWindow::withdraw(void) {
1690 // We don't need to worry about resizing because resizing always grabs the X
1691 // server. This should only ever happen if using opaque moving.
1695 flags
.visible
= False
;
1696 flags
.iconic
= False
;
1698 setState(current_state
);
1700 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1702 XGrabServer(blackbox
->getXDisplay());
1704 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
1705 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1706 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1707 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
1709 XUngrabServer(blackbox
->getXDisplay());
1711 if (windowmenu
) windowmenu
->hide();
1715 void BlackboxWindow::maximize(unsigned int button
) {
1716 // We don't need to worry about resizing because resizing always grabs the X
1717 // server. This should only ever happen if using opaque moving.
1721 // handle case where menu is open then the max button is used instead
1722 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
1724 if (flags
.maximized
) {
1725 flags
.maximized
= 0;
1727 blackbox_attrib
.flags
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1728 blackbox_attrib
.attrib
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1731 when a resize finishes, maximize(0) is called to clear any maximization
1732 flags currently set. Otherwise it still thinks it is maximized.
1733 so we do not need to call configure() because resizing will handle it
1735 if (! flags
.resizing
)
1736 configure(blackbox_attrib
.premax_x
, blackbox_attrib
.premax_y
,
1737 blackbox_attrib
.premax_w
, blackbox_attrib
.premax_h
);
1739 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
1740 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
1742 redrawAllButtons(); // in case it is not called in configure()
1743 setState(current_state
);
1747 blackbox_attrib
.premax_x
= frame
.rect
.x();
1748 blackbox_attrib
.premax_y
= frame
.rect
.y();
1749 blackbox_attrib
.premax_w
= frame
.rect
.width();
1750 // use client.rect so that clients can be restored even if shaded
1751 blackbox_attrib
.premax_h
=
1752 client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
;
1754 const Rect
&screen_area
= screen
->availableArea();
1755 frame
.changing
= screen_area
;
1759 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1760 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1764 blackbox_attrib
.flags
|= AttribMaxVert
;
1765 blackbox_attrib
.attrib
|= AttribMaxVert
;
1767 frame
.changing
.setX(frame
.rect
.x());
1768 frame
.changing
.setWidth(frame
.rect
.width());
1772 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1773 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1775 frame
.changing
.setY(frame
.rect
.y());
1776 frame
.changing
.setHeight(frame
.rect
.height());
1783 blackbox_attrib
.flags
^= AttribShaded
;
1784 blackbox_attrib
.attrib
^= AttribShaded
;
1785 flags
.shaded
= False
;
1788 flags
.maximized
= button
;
1790 configure(frame
.changing
.x(), frame
.changing
.y(),
1791 frame
.changing
.width(), frame
.changing
.height());
1793 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1794 redrawAllButtons(); // in case it is not called in configure()
1795 setState(current_state
);
1799 // re-maximizes the window to take into account availableArea changes
1800 void BlackboxWindow::remaximize(void) {
1801 // save the original dimensions because maximize will wipe them out
1802 int premax_x
= blackbox_attrib
.premax_x
,
1803 premax_y
= blackbox_attrib
.premax_y
,
1804 premax_w
= blackbox_attrib
.premax_w
,
1805 premax_h
= blackbox_attrib
.premax_h
;
1807 unsigned int button
= flags
.maximized
;
1808 flags
.maximized
= 0; // trick maximize() into working
1811 // restore saved values
1812 blackbox_attrib
.premax_x
= premax_x
;
1813 blackbox_attrib
.premax_y
= premax_y
;
1814 blackbox_attrib
.premax_w
= premax_w
;
1815 blackbox_attrib
.premax_h
= premax_h
;
1819 void BlackboxWindow::setWorkspace(unsigned int n
) {
1820 blackbox_attrib
.flags
|= AttribWorkspace
;
1821 blackbox_attrib
.workspace
= n
;
1822 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
, n
);
1826 void BlackboxWindow::shade(void) {
1828 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1829 frame
.inside_w
, frame
.inside_h
);
1830 flags
.shaded
= False
;
1831 blackbox_attrib
.flags
^= AttribShaded
;
1832 blackbox_attrib
.attrib
^= AttribShaded
;
1834 setState(NormalState
);
1836 // set the frame rect to the normal size
1837 frame
.rect
.setHeight(client
.rect
.height() + frame
.margin
.top
+
1838 frame
.margin
.bottom
);
1840 if (! (decorations
& Decor_Titlebar
))
1841 return; // can't shade it without a titlebar!
1843 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1844 frame
.inside_w
, frame
.title_h
);
1845 flags
.shaded
= True
;
1846 blackbox_attrib
.flags
|= AttribShaded
;
1847 blackbox_attrib
.attrib
|= AttribShaded
;
1849 setState(IconicState
);
1851 // set the frame rect to the shaded size
1852 frame
.rect
.setHeight(frame
.title_h
+ (frame
.border_w
* 2));
1858 * (Un)Sticks a window and its relatives.
1860 void BlackboxWindow::stick(void) {
1862 blackbox_attrib
.flags
^= AttribOmnipresent
;
1863 blackbox_attrib
.attrib
^= AttribOmnipresent
;
1865 flags
.stuck
= False
;
1868 screen
->reassociateWindow(this, BSENTINEL
, True
);
1870 // temporary fix since sticky windows suck. set the hint to what we
1871 // actually hold in our data.
1872 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1873 blackbox_attrib
.workspace
);
1875 setState(current_state
);
1879 blackbox_attrib
.flags
|= AttribOmnipresent
;
1880 blackbox_attrib
.attrib
|= AttribOmnipresent
;
1882 // temporary fix since sticky windows suck. set the hint to a different
1883 // value than that contained in the class' data.
1884 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1887 setState(current_state
);
1890 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1891 client
.transient_for
->isStuck() != flags
.stuck
)
1892 client
.transient_for
->stick();
1893 // go down the chain
1894 BlackboxWindowList::iterator it
;
1895 const BlackboxWindowList::iterator end
= client
.transientList
.end();
1896 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1897 if ((*it
)->isStuck() != flags
.stuck
)
1902 void BlackboxWindow::redrawWindowFrame(void) const {
1903 if (decorations
& Decor_Titlebar
) {
1904 if (flags
.focused
) {
1906 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1907 frame
.title
, frame
.ftitle
);
1909 XSetWindowBackground(blackbox
->getXDisplay(),
1910 frame
.title
, frame
.ftitle_pixel
);
1913 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1914 frame
.title
, frame
.utitle
);
1916 XSetWindowBackground(blackbox
->getXDisplay(),
1917 frame
.title
, frame
.utitle_pixel
);
1919 XClearWindow(blackbox
->getXDisplay(), frame
.title
);
1925 if (decorations
& Decor_Handle
) {
1926 if (flags
.focused
) {
1928 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1929 frame
.handle
, frame
.fhandle
);
1931 XSetWindowBackground(blackbox
->getXDisplay(),
1932 frame
.handle
, frame
.fhandle_pixel
);
1935 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1936 frame
.left_grip
, frame
.fgrip
);
1937 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1938 frame
.right_grip
, frame
.fgrip
);
1940 XSetWindowBackground(blackbox
->getXDisplay(),
1941 frame
.left_grip
, frame
.fgrip_pixel
);
1942 XSetWindowBackground(blackbox
->getXDisplay(),
1943 frame
.right_grip
, frame
.fgrip_pixel
);
1947 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1948 frame
.handle
, frame
.uhandle
);
1950 XSetWindowBackground(blackbox
->getXDisplay(),
1951 frame
.handle
, frame
.uhandle_pixel
);
1954 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1955 frame
.left_grip
, frame
.ugrip
);
1956 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1957 frame
.right_grip
, frame
.ugrip
);
1959 XSetWindowBackground(blackbox
->getXDisplay(),
1960 frame
.left_grip
, frame
.ugrip_pixel
);
1961 XSetWindowBackground(blackbox
->getXDisplay(),
1962 frame
.right_grip
, frame
.ugrip_pixel
);
1965 XClearWindow(blackbox
->getXDisplay(), frame
.handle
);
1966 XClearWindow(blackbox
->getXDisplay(), frame
.left_grip
);
1967 XClearWindow(blackbox
->getXDisplay(), frame
.right_grip
);
1970 if (decorations
& Decor_Border
) {
1972 XSetWindowBorder(blackbox
->getXDisplay(),
1973 frame
.plate
, frame
.fborder_pixel
);
1975 XSetWindowBorder(blackbox
->getXDisplay(),
1976 frame
.plate
, frame
.uborder_pixel
);
1981 void BlackboxWindow::setFocusFlag(bool focus
) {
1982 // only focus a window if it is visible
1983 if (focus
&& !flags
.visible
)
1986 flags
.focused
= focus
;
1988 redrawWindowFrame();
1990 if (screen
->isSloppyFocus() && screen
->doAutoRaise()) {
1991 if (isFocused()) timer
->start();
1996 blackbox
->setFocusedWindow(this);
2000 void BlackboxWindow::installColormap(bool install
) {
2001 int i
= 0, ncmap
= 0;
2002 Colormap
*cmaps
= XListInstalledColormaps(blackbox
->getXDisplay(),
2003 client
.window
, &ncmap
);
2005 XWindowAttributes wattrib
;
2006 if (XGetWindowAttributes(blackbox
->getXDisplay(),
2007 client
.window
, &wattrib
)) {
2009 // install the window's colormap
2010 for (i
= 0; i
< ncmap
; i
++) {
2011 if (*(cmaps
+ i
) == wattrib
.colormap
)
2012 // this window is using an installed color map... do not install
2015 // otherwise, install the window's colormap
2017 XInstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2019 // uninstall the window's colormap
2020 for (i
= 0; i
< ncmap
; i
++) {
2021 if (*(cmaps
+ i
) == wattrib
.colormap
)
2022 // we found the colormap to uninstall
2023 XUninstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2033 void BlackboxWindow::setAllowedActions(void) {
2037 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_shade
);
2038 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_change_desktop
);
2039 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_close
);
2041 if (functions
& Func_Move
)
2042 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_move
);
2043 if (functions
& Func_Resize
)
2044 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_resize
);
2045 if (functions
& Func_Maximize
) {
2046 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_horz
);
2047 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_vert
);
2050 xatom
->setValue(client
.window
, XAtom::net_wm_allowed_actions
, XAtom::atom
,
2055 void BlackboxWindow::setState(unsigned long new_state
) {
2056 current_state
= new_state
;
2058 unsigned long state
[2];
2059 state
[0] = current_state
;
2061 xatom
->setValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
, state
, 2);
2063 xatom
->setValue(client
.window
, XAtom::blackbox_attributes
,
2064 XAtom::blackbox_attributes
, (unsigned long *)&blackbox_attrib
,
2065 PropBlackboxAttributesElements
);
2070 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_modal
);
2072 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_shaded
);
2074 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_hidden
);
2075 if (flags
.skip_taskbar
)
2076 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
);
2077 if (flags
.skip_pager
)
2078 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_pager
);
2079 if (flags
.fullscreen
)
2080 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_fullscreen
);
2081 if (flags
.maximized
== 1 || flags
.maximized
== 2)
2082 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_vert
);
2083 if (flags
.maximized
== 1 || flags
.maximized
== 3)
2084 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_horz
);
2085 xatom
->setValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
2090 bool BlackboxWindow::getState(void) {
2091 bool ret
= xatom
->getValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
,
2093 if (! ret
) current_state
= 0;
2098 void BlackboxWindow::restoreAttributes(void) {
2099 unsigned long num
= PropBlackboxAttributesElements
;
2100 BlackboxAttributes
*net
;
2101 if (! xatom
->getValue(client
.window
, XAtom::blackbox_attributes
,
2102 XAtom::blackbox_attributes
, num
,
2103 (unsigned long **)&net
))
2105 if (num
< PropBlackboxAttributesElements
) {
2110 if (net
->flags
& AttribShaded
&& net
->attrib
& AttribShaded
) {
2111 flags
.shaded
= False
;
2115 Because the iconic'ness of shaded windows is lost, we need to set the
2116 state to NormalState so that shaded windows on other workspaces will not
2117 get shown on the first workspace.
2118 At this point in the life of a window, current_state should only be set
2119 to IconicState if the window was an *icon*, not if it was shaded.
2121 current_state
= NormalState
;
2124 if ((net
->workspace
!= screen
->getCurrentWorkspaceID()) &&
2125 (net
->workspace
< screen
->getWorkspaceCount()))
2126 screen
->reassociateWindow(this, net
->workspace
, True
);
2128 if ((blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID()) &&
2129 (blackbox_attrib
.workspace
< screen
->getWorkspaceCount())) {
2130 // set to WithdrawnState so it will be mapped on the new workspace
2131 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2132 } else if (current_state
== WithdrawnState
) {
2133 // the window is on this workspace and is Withdrawn, so it is waiting to
2135 current_state
= NormalState
;
2138 if (net
->flags
& AttribOmnipresent
&& net
->attrib
& AttribOmnipresent
) {
2139 flags
.stuck
= False
;
2142 // if the window was on another workspace, it was going to be hidden. this
2143 // specifies that the window should be mapped since it is sticky.
2144 if (current_state
== WithdrawnState
) current_state
= NormalState
;
2147 if (net
->flags
& AttribMaxHoriz
|| net
->flags
& AttribMaxVert
) {
2148 int x
= net
->premax_x
, y
= net
->premax_y
;
2149 unsigned int w
= net
->premax_w
, h
= net
->premax_h
;
2150 flags
.maximized
= 0;
2153 if ((net
->flags
& AttribMaxHoriz
) &&
2154 (net
->flags
& AttribMaxVert
))
2155 m
= (net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
2156 else if (net
->flags
& AttribMaxVert
)
2157 m
= (net
->attrib
& AttribMaxVert
) ? 2 : 0;
2158 else if (net
->flags
& AttribMaxHoriz
)
2159 m
= (net
->attrib
& AttribMaxHoriz
) ? 3 : 0;
2163 blackbox_attrib
.premax_x
= x
;
2164 blackbox_attrib
.premax_y
= y
;
2165 blackbox_attrib
.premax_w
= w
;
2166 blackbox_attrib
.premax_h
= h
;
2169 // with the state set it will then be the map event's job to read the
2170 // window's state and behave accordingly
2177 * Positions the Rect r according the the client window position and
2180 void BlackboxWindow::applyGravity(Rect
&r
) {
2181 // apply horizontal window gravity
2182 switch (client
.win_gravity
) {
2184 case NorthWestGravity
:
2185 case SouthWestGravity
:
2187 r
.setX(client
.rect
.x());
2193 r
.setX(client
.rect
.x() - (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2196 case NorthEastGravity
:
2197 case SouthEastGravity
:
2199 r
.setX(client
.rect
.x() - frame
.margin
.left
- frame
.margin
.right
);
2204 r
.setX(client
.rect
.x() - frame
.margin
.left
);
2208 // apply vertical window gravity
2209 switch (client
.win_gravity
) {
2211 case NorthWestGravity
:
2212 case NorthEastGravity
:
2214 r
.setY(client
.rect
.y());
2220 r
.setY(client
.rect
.y() - (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2223 case SouthWestGravity
:
2224 case SouthEastGravity
:
2226 r
.setY(client
.rect
.y() - frame
.margin
.top
- frame
.margin
.bottom
);
2231 r
.setY(client
.rect
.y() - frame
.margin
.top
);
2238 * The reverse of the applyGravity function.
2240 * Positions the Rect r according to the frame window position and
2243 void BlackboxWindow::restoreGravity(Rect
&r
) {
2244 // restore horizontal window gravity
2245 switch (client
.win_gravity
) {
2247 case NorthWestGravity
:
2248 case SouthWestGravity
:
2250 r
.setX(frame
.rect
.x());
2256 r
.setX(frame
.rect
.x() + (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2259 case NorthEastGravity
:
2260 case SouthEastGravity
:
2262 r
.setX(frame
.rect
.x() + frame
.margin
.left
+ frame
.margin
.right
);
2267 r
.setX(frame
.rect
.x() + frame
.margin
.left
);
2271 // restore vertical window gravity
2272 switch (client
.win_gravity
) {
2274 case NorthWestGravity
:
2275 case NorthEastGravity
:
2277 r
.setY(frame
.rect
.y());
2283 r
.setY(frame
.rect
.y() + (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2286 case SouthWestGravity
:
2287 case SouthEastGravity
:
2289 r
.setY(frame
.rect
.y() + frame
.margin
.top
+ frame
.margin
.bottom
);
2294 r
.setY(frame
.rect
.y() + frame
.margin
.top
);
2300 void BlackboxWindow::redrawLabel(void) const {
2301 if (flags
.focused
) {
2303 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2304 frame
.label
, frame
.flabel
);
2306 XSetWindowBackground(blackbox
->getXDisplay(),
2307 frame
.label
, frame
.flabel_pixel
);
2310 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2311 frame
.label
, frame
.ulabel
);
2313 XSetWindowBackground(blackbox
->getXDisplay(),
2314 frame
.label
, frame
.ulabel_pixel
);
2316 XClearWindow(blackbox
->getXDisplay(), frame
.label
);
2318 WindowStyle
*style
= screen
->getWindowStyle();
2320 int pos
= frame
.bevel_w
* 2,
2321 dlen
= style
->doJustify(client
.title
.c_str(), pos
, frame
.label_w
,
2322 frame
.bevel_w
* 4, i18n
.multibyte());
2324 BPen
pen((flags
.focused
) ? style
->l_text_focus
: style
->l_text_unfocus
,
2326 if (i18n
.multibyte())
2327 XmbDrawString(blackbox
->getXDisplay(), frame
.label
, style
->fontset
,
2329 (1 - style
->fontset_extents
->max_ink_extent
.y
),
2330 client
.title
.c_str(), dlen
);
2332 XDrawString(blackbox
->getXDisplay(), frame
.label
, pen
.gc(), pos
,
2333 (style
->font
->ascent
+ 1), client
.title
.c_str(), dlen
);
2337 void BlackboxWindow::redrawAllButtons(void) const {
2338 if (frame
.iconify_button
) redrawIconifyButton(False
);
2339 if (frame
.maximize_button
) redrawMaximizeButton(flags
.maximized
);
2340 if (frame
.close_button
) redrawCloseButton(False
);
2344 void BlackboxWindow::redrawIconifyButton(bool pressed
) const {
2346 if (flags
.focused
) {
2348 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2349 frame
.iconify_button
, frame
.fbutton
);
2351 XSetWindowBackground(blackbox
->getXDisplay(),
2352 frame
.iconify_button
, frame
.fbutton_pixel
);
2355 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2356 frame
.iconify_button
, frame
.ubutton
);
2358 XSetWindowBackground(blackbox
->getXDisplay(), frame
.iconify_button
,
2359 frame
.ubutton_pixel
);
2363 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2364 frame
.iconify_button
, frame
.pbutton
);
2366 XSetWindowBackground(blackbox
->getXDisplay(),
2367 frame
.iconify_button
, frame
.pbutton_pixel
);
2369 XClearWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
2371 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2372 screen
->getWindowStyle()->b_pic_unfocus
);
2373 XDrawRectangle(blackbox
->getXDisplay(), frame
.iconify_button
, pen
.gc(),
2374 2, (frame
.button_w
- 5), (frame
.button_w
- 5), 2);
2378 void BlackboxWindow::redrawMaximizeButton(bool pressed
) const {
2380 if (flags
.focused
) {
2382 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2383 frame
.maximize_button
, frame
.fbutton
);
2385 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2386 frame
.fbutton_pixel
);
2389 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2390 frame
.maximize_button
, frame
.ubutton
);
2392 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2393 frame
.ubutton_pixel
);
2397 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2398 frame
.maximize_button
, frame
.pbutton
);
2400 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2401 frame
.pbutton_pixel
);
2403 XClearWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
2405 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2406 screen
->getWindowStyle()->b_pic_unfocus
);
2407 XDrawRectangle(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2408 2, 2, (frame
.button_w
- 5), (frame
.button_w
- 5));
2409 XDrawLine(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2410 2, 3, (frame
.button_w
- 3), 3);
2414 void BlackboxWindow::redrawCloseButton(bool pressed
) const {
2416 if (flags
.focused
) {
2418 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2421 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2422 frame
.fbutton_pixel
);
2425 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2428 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2429 frame
.ubutton_pixel
);
2433 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2434 frame
.close_button
, frame
.pbutton
);
2436 XSetWindowBackground(blackbox
->getXDisplay(),
2437 frame
.close_button
, frame
.pbutton_pixel
);
2439 XClearWindow(blackbox
->getXDisplay(), frame
.close_button
);
2441 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2442 screen
->getWindowStyle()->b_pic_unfocus
);
2443 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2444 2, 2, (frame
.button_w
- 3), (frame
.button_w
- 3));
2445 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2446 2, (frame
.button_w
- 3), (frame
.button_w
- 3), 2);
2450 void BlackboxWindow::mapRequestEvent(const XMapRequestEvent
*re
) {
2451 if (re
->window
!= client
.window
)
2455 fprintf(stderr
, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2459 switch (current_state
) {
2464 case WithdrawnState
:
2473 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2474 if (! blackbox
->isStartup() && (isTransient() || screen
->doFocusNew())) {
2475 XSync(blackbox
->getXDisplay(), False
); // make sure the frame is mapped..
2483 void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent
*ue
) {
2484 if (ue
->window
!= client
.window
)
2488 fprintf(stderr
, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2492 screen
->unmanageWindow(this, False
);
2496 void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent
*de
) {
2497 if (de
->window
!= client
.window
)
2501 fprintf(stderr
, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2505 screen
->unmanageWindow(this, False
);
2509 void BlackboxWindow::reparentNotifyEvent(const XReparentEvent
*re
) {
2510 if (re
->window
!= client
.window
|| re
->parent
== frame
.plate
)
2514 fprintf(stderr
, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2515 "0x%lx.\n", client
.window
, re
->parent
);
2520 XPutBackEvent(blackbox
->getXDisplay(), &ev
);
2521 screen
->unmanageWindow(this, True
);
2525 void BlackboxWindow::propertyNotifyEvent(Atom atom
) {
2528 case XA_WM_CLIENT_MACHINE
:
2532 case XA_WM_TRANSIENT_FOR
: {
2533 // determine if this is a transient window
2536 // adjust the window decorations based on transience
2537 if (isTransient()) {
2538 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2539 functions
&= ~Func_Maximize
;
2540 setAllowedActions();
2551 case XA_WM_ICON_NAME
:
2553 if (flags
.iconic
) screen
->propagateWindowName(this);
2556 case XAtom::net_wm_name
:
2560 if (decorations
& Decor_Titlebar
)
2563 screen
->propagateWindowName(this);
2566 case XA_WM_NORMAL_HINTS
: {
2569 if ((client
.normal_hint_flags
& PMinSize
) &&
2570 (client
.normal_hint_flags
& PMaxSize
)) {
2571 if (client
.max_width
<= client
.min_width
&&
2572 client
.max_height
<= client
.min_height
) {
2573 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2574 functions
&= ~(Func_Resize
| Func_Maximize
);
2576 decorations
|= Decor_Maximize
| Decor_Handle
;
2577 functions
|= Func_Resize
| Func_Maximize
;
2579 setAllowedActions();
2582 Rect old_rect
= frame
.rect
;
2586 if (old_rect
!= frame
.rect
)
2593 if (atom
== xatom
->getAtom(XAtom::wm_protocols
)) {
2596 if ((decorations
& Decor_Close
) && (! frame
.close_button
)) {
2597 createCloseButton();
2598 if (decorations
& Decor_Titlebar
) {
2599 positionButtons(True
);
2600 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
2602 if (windowmenu
) windowmenu
->reconfigure();
2604 } else if (atom
== xatom
->getAtom(XAtom::net_wm_strut
)) {
2613 void BlackboxWindow::exposeEvent(const XExposeEvent
*ee
) {
2614 if (frame
.label
== ee
->window
&& (decorations
& Decor_Titlebar
))
2616 else if (frame
.close_button
== ee
->window
)
2617 redrawCloseButton(False
);
2618 else if (frame
.maximize_button
== ee
->window
)
2619 redrawMaximizeButton(flags
.maximized
);
2620 else if (frame
.iconify_button
== ee
->window
)
2621 redrawIconifyButton(False
);
2625 void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent
*cr
) {
2626 if (cr
->window
!= client
.window
|| flags
.iconic
)
2629 if (cr
->value_mask
& CWBorderWidth
)
2630 client
.old_bw
= cr
->border_width
;
2632 if (cr
->value_mask
& (CWX
| CWY
| CWWidth
| CWHeight
)) {
2633 Rect req
= frame
.rect
;
2635 if (cr
->value_mask
& (CWX
| CWY
)) {
2636 if (cr
->value_mask
& CWX
)
2637 client
.rect
.setX(cr
->x
);
2638 if (cr
->value_mask
& CWY
)
2639 client
.rect
.setY(cr
->y
);
2644 if (cr
->value_mask
& CWWidth
)
2645 req
.setWidth(cr
->width
+ frame
.margin
.left
+ frame
.margin
.right
);
2647 if (cr
->value_mask
& CWHeight
)
2648 req
.setHeight(cr
->height
+ frame
.margin
.top
+ frame
.margin
.bottom
);
2650 configure(req
.x(), req
.y(), req
.width(), req
.height());
2653 if (cr
->value_mask
& CWStackMode
) {
2654 switch (cr
->detail
) {
2657 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2663 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2670 void BlackboxWindow::buttonPressEvent(const XButtonEvent
*be
) {
2671 if (frame
.maximize_button
== be
->window
) {
2672 redrawMaximizeButton(True
);
2673 } else if (be
->button
== 1 || (be
->button
== 3 && be
->state
== Mod1Mask
)) {
2674 if (! flags
.focused
)
2677 if (frame
.iconify_button
== be
->window
) {
2678 redrawIconifyButton(True
);
2679 } else if (frame
.close_button
== be
->window
) {
2680 redrawCloseButton(True
);
2681 } else if (frame
.plate
== be
->window
) {
2682 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2684 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2686 XAllowEvents(blackbox
->getXDisplay(), ReplayPointer
, be
->time
);
2688 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
2689 if (((be
->time
- lastButtonPressTime
) <=
2690 blackbox
->getDoubleClickInterval()) ||
2691 (be
->state
& ControlMask
)) {
2692 lastButtonPressTime
= 0;
2695 lastButtonPressTime
= be
->time
;
2699 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2701 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2703 } else if (be
->button
== 2 && (be
->window
!= frame
.iconify_button
) &&
2704 (be
->window
!= frame
.close_button
)) {
2705 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2706 } else if (windowmenu
&& be
->button
== 3 &&
2707 (frame
.title
== be
->window
|| frame
.label
== be
->window
||
2708 frame
.handle
== be
->window
|| frame
.window
== be
->window
)) {
2711 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
2712 mx
= be
->x_root
- (windowmenu
->getWidth() / 2);
2713 my
= frame
.rect
.y() + frame
.title_h
+ frame
.border_w
;
2714 } else if (frame
.handle
== be
->window
) {
2715 mx
= be
->x_root
- (windowmenu
->getWidth() / 2);
2716 my
= frame
.rect
.bottom() - frame
.handle_h
- (frame
.border_w
* 3) -
2717 windowmenu
->getHeight();
2719 mx
= be
->x_root
- (windowmenu
->getWidth() / 2);
2721 if (be
->y
<= static_cast<signed>(frame
.bevel_w
))
2722 my
= frame
.rect
.y() + frame
.title_h
;
2724 my
= be
->y_root
- (windowmenu
->getHeight() / 2);
2727 // snap the window menu into a corner if necessary - we check the
2728 // position of the menu with the coordinates of the client to
2729 // make the comparisions easier.
2730 // XXX: this needs some work!
2731 if (mx
> client
.rect
.right() -
2732 static_cast<signed>(windowmenu
->getWidth()))
2733 mx
= frame
.rect
.right() - windowmenu
->getWidth() - frame
.border_w
+ 1;
2734 if (mx
< client
.rect
.left())
2735 mx
= frame
.rect
.x();
2737 if (my
> client
.rect
.bottom() -
2738 static_cast<signed>(windowmenu
->getHeight()))
2739 my
= frame
.rect
.bottom() - windowmenu
->getHeight() - frame
.border_w
+ 1;
2740 if (my
< client
.rect
.top())
2741 my
= frame
.rect
.y() + ((decorations
& Decor_Titlebar
) ?
2745 if (! windowmenu
->isVisible()) {
2746 windowmenu
->move(mx
, my
);
2748 XRaiseWindow(blackbox
->getXDisplay(), windowmenu
->getWindowID());
2749 XRaiseWindow(blackbox
->getXDisplay(),
2750 windowmenu
->getSendToMenu()->getWindowID());
2756 } else if (be
->button
== 4) {
2757 if ((be
->window
== frame
.label
||
2758 be
->window
== frame
.title
) &&
2762 } else if (be
->button
== 5) {
2763 if ((be
->window
== frame
.label
||
2764 be
->window
== frame
.title
) &&
2771 void BlackboxWindow::buttonReleaseEvent(const XButtonEvent
*re
) {
2772 if (re
->window
== frame
.maximize_button
) {
2773 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2774 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2775 maximize(re
->button
);
2777 redrawMaximizeButton(flags
.maximized
);
2779 } else if (re
->window
== frame
.iconify_button
) {
2780 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2781 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2784 redrawIconifyButton(False
);
2786 } else if (re
->window
== frame
.close_button
) {
2787 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2788 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
)))
2790 redrawCloseButton(False
);
2791 } else if (flags
.moving
) {
2793 } else if (flags
.resizing
) {
2795 } else if (re
->window
== frame
.window
) {
2796 if (re
->button
== 2 && re
->state
== Mod1Mask
)
2797 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
2803 void BlackboxWindow::beginMove(int x_root
, int y_root
) {
2804 assert(! (flags
.resizing
|| flags
.moving
));
2807 Only one window can be moved/resized at a time. If another window is already
2808 being moved or resized, then stop it before whating to work with this one.
2810 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
2811 if (changing
&& changing
!= this) {
2812 if (changing
->flags
.moving
)
2813 changing
->endMove();
2814 else // if (changing->flags.resizing)
2815 changing
->endResize();
2818 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
2819 PointerMotionMask
| ButtonReleaseMask
,
2820 GrabModeAsync
, GrabModeAsync
,
2821 None
, blackbox
->getMoveCursor(), CurrentTime
);
2823 if (windowmenu
&& windowmenu
->isVisible())
2826 flags
.moving
= True
;
2827 blackbox
->setChangingWindow(this);
2829 if (! screen
->doOpaqueMove()) {
2830 XGrabServer(blackbox
->getXDisplay());
2832 frame
.changing
= frame
.rect
;
2833 screen
->showPosition(frame
.changing
.x(), frame
.changing
.y());
2835 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2839 frame
.changing
.width() - 1,
2840 frame
.changing
.height() - 1);
2843 frame
.grab_x
= x_root
- frame
.rect
.x() - frame
.border_w
;
2844 frame
.grab_y
= y_root
- frame
.rect
.y() - frame
.border_w
;
2848 void BlackboxWindow::doMove(int x_root
, int y_root
) {
2849 assert(flags
.moving
);
2850 assert(blackbox
->getChangingWindow() == this);
2852 int dx
= x_root
- frame
.grab_x
, dy
= y_root
- frame
.grab_y
;
2853 dx
-= frame
.border_w
;
2854 dy
-= frame
.border_w
;
2856 const int snap_distance
= screen
->getEdgeSnapThreshold();
2858 if (snap_distance
) {
2860 const int wleft
= dx
,
2861 wright
= dx
+ frame
.rect
.width() - 1,
2863 wbottom
= dy
+ frame
.rect
.height() - 1;
2865 if (screen
->getWindowToWindowSnap()) {
2866 Workspace
*w
= screen
->getWorkspace(getWorkspaceNumber());
2869 // try snap to another window
2870 for (unsigned int i
= 0, c
= w
->getCount(); i
< c
; ++i
) {
2871 BlackboxWindow
*snapwin
= w
->getWindow(i
);
2872 if (snapwin
== this)
2873 continue; // don't snap to self
2875 bool snapped
= False
;
2877 const Rect
&winrect
= snapwin
->frameRect();
2878 int dleft
= std::abs(wright
- winrect
.left()),
2879 dright
= std::abs(wleft
- winrect
.right()),
2880 dtop
= std::abs(wbottom
- winrect
.top()),
2881 dbottom
= std::abs(wtop
- winrect
.bottom());
2883 if (wtop
>= (signed)(winrect
.y() - frame
.rect
.height() + 1) &&
2884 wtop
< (signed)(winrect
.y() + winrect
.height() - 1)) {
2886 // snap left of other window?
2887 if (dleft
< snap_distance
&& dleft
<= dright
) {
2888 dx
= winrect
.left() - frame
.rect
.width();
2891 // snap right of other window?
2892 else if (dright
< snap_distance
) {
2893 dx
= winrect
.right() + 1;
2898 if (screen
->getWindowCornerSnap()) {
2899 // try corner-snap to its other sides
2900 dtop
= std::abs(wtop
- winrect
.top());
2901 dbottom
= std::abs(wbottom
- winrect
.bottom());
2902 if (dtop
< snap_distance
&& dtop
<= dbottom
)
2904 else if (dbottom
< snap_distance
)
2905 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
2912 if (wleft
>= (signed)(winrect
.x() - frame
.rect
.width() + 1) &&
2913 wleft
< (signed)(winrect
.x() + winrect
.width() - 1)) {
2915 // snap top of other window?
2916 if (dtop
< snap_distance
&& dtop
<= dbottom
) {
2917 dy
= winrect
.top() - frame
.rect
.height();
2920 // snap bottom of other window?
2921 else if (dbottom
< snap_distance
) {
2922 dy
= winrect
.bottom() + 1;
2927 if (screen
->getWindowCornerSnap()) {
2928 // try corner-snap to its other sides
2929 dleft
= std::abs(wleft
- winrect
.left());
2930 dright
= std::abs(wright
- winrect
.right());
2931 if (dleft
< snap_distance
&& dleft
<= dright
)
2932 dx
= winrect
.left();
2933 else if (dright
< snap_distance
)
2934 dx
= winrect
.right() - frame
.rect
.width() + 1;
2943 // try snap to the screen's available area
2944 Rect srect
= screen
->availableArea();
2946 int dleft
= std::abs(wleft
- srect
.left()),
2947 dright
= std::abs(wright
- srect
.right()),
2948 dtop
= std::abs(wtop
- srect
.top()),
2949 dbottom
= std::abs(wbottom
- srect
.bottom());
2952 if (dleft
< snap_distance
&& dleft
<= dright
)
2955 else if (dright
< snap_distance
)
2956 dx
= srect
.right() - frame
.rect
.width() + 1;
2959 if (dtop
< snap_distance
&& dtop
<= dbottom
)
2962 else if (dbottom
< snap_distance
)
2963 dy
= srect
.bottom() - frame
.rect
.height() + 1;
2965 srect
= screen
->getRect(); // now get the full screen
2967 dleft
= std::abs(wleft
- srect
.left()),
2968 dright
= std::abs(wright
- srect
.right()),
2969 dtop
= std::abs(wtop
- srect
.top()),
2970 dbottom
= std::abs(wbottom
- srect
.bottom());
2973 if (dleft
< snap_distance
&& dleft
<= dright
)
2976 else if (dright
< snap_distance
)
2977 dx
= srect
.right() - frame
.rect
.width() + 1;
2980 if (dtop
< snap_distance
&& dtop
<= dbottom
)
2983 else if (dbottom
< snap_distance
)
2984 dy
= srect
.bottom() - frame
.rect
.height() + 1;
2987 if (screen
->doOpaqueMove()) {
2988 configure(dx
, dy
, frame
.rect
.width(), frame
.rect
.height());
2990 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2994 frame
.changing
.width() - 1,
2995 frame
.changing
.height() - 1);
2997 frame
.changing
.setPos(dx
, dy
);
2999 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3003 frame
.changing
.width() - 1,
3004 frame
.changing
.height() - 1);
3007 screen
->showPosition(dx
, dy
);
3011 void BlackboxWindow::endMove(void) {
3012 assert(flags
.moving
);
3013 assert(blackbox
->getChangingWindow() == this);
3015 flags
.moving
= False
;
3016 blackbox
->setChangingWindow(0);
3018 if (! screen
->doOpaqueMove()) {
3019 /* when drawing the rubber band, we need to make sure we only draw inside
3020 * the frame... frame.changing_* contain the new coords for the window,
3021 * so we need to subtract 1 from changing_w/changing_h every where we
3022 * draw the rubber band (for both moving and resizing)
3024 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3025 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3026 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3027 XUngrabServer(blackbox
->getXDisplay());
3029 configure(frame
.changing
.x(), frame
.changing
.y(),
3030 frame
.changing
.width(), frame
.changing
.height());
3032 configure(frame
.rect
.x(), frame
.rect
.y(),
3033 frame
.rect
.width(), frame
.rect
.height());
3035 screen
->hideGeometry();
3037 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3039 // if there are any left over motions from the move, drop them now
3040 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3042 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3047 void BlackboxWindow::beginResize(int x_root
, int y_root
, Corner dir
) {
3048 assert(! (flags
.resizing
|| flags
.moving
));
3051 Only one window can be moved/resized at a time. If another window is already
3052 being moved or resized, then stop it before whating to work with this one.
3054 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3055 if (changing
&& changing
!= this) {
3056 if (changing
->flags
.moving
)
3057 changing
->endMove();
3058 else // if (changing->flags.resizing)
3059 changing
->endResize();
3067 switch (resize_dir
) {
3070 cursor
= blackbox
->getLowerLeftAngleCursor();
3075 cursor
= blackbox
->getLowerRightAngleCursor();
3079 anchor
= BottomRight
;
3080 cursor
= blackbox
->getUpperLeftAngleCursor();
3084 anchor
= BottomLeft
;
3085 cursor
= blackbox
->getUpperRightAngleCursor();
3089 assert(false); // unhandled Corner
3092 XGrabServer(blackbox
->getXDisplay());
3093 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3094 PointerMotionMask
| ButtonReleaseMask
,
3095 GrabModeAsync
, GrabModeAsync
, None
, cursor
, CurrentTime
);
3097 flags
.resizing
= True
;
3098 blackbox
->setChangingWindow(this);
3101 frame
.changing
= frame
.rect
;
3103 constrain(anchor
, &gw
, &gh
);
3105 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3106 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3107 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3109 screen
->showGeometry(gw
, gh
);
3111 frame
.grab_x
= x_root
;
3112 frame
.grab_y
= y_root
;
3116 void BlackboxWindow::doResize(int x_root
, int y_root
) {
3117 assert(flags
.resizing
);
3118 assert(blackbox
->getChangingWindow() == this);
3120 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3121 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3122 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3127 switch (resize_dir
) {
3130 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3131 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3135 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3136 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3139 anchor
= BottomRight
;
3140 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3141 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3144 anchor
= BottomLeft
;
3145 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3146 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3150 assert(false); // unhandled Corner
3153 constrain(anchor
, &gw
, &gh
);
3155 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3156 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3157 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3159 screen
->showGeometry(gw
, gh
);
3163 void BlackboxWindow::endResize(void) {
3164 assert(flags
.resizing
);
3165 assert(blackbox
->getChangingWindow() == this);
3167 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3168 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3169 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3170 XUngrabServer(blackbox
->getXDisplay());
3172 // unset maximized state after resized when fully maximized
3173 if (flags
.maximized
== 1)
3176 flags
.resizing
= False
;
3177 blackbox
->setChangingWindow(0);
3179 configure(frame
.changing
.x(), frame
.changing
.y(),
3180 frame
.changing
.width(), frame
.changing
.height());
3181 screen
->hideGeometry();
3183 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3185 // if there are any left over motions from the resize, drop them now
3186 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3188 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3193 void BlackboxWindow::motionNotifyEvent(const XMotionEvent
*me
) {
3195 doMove(me
->x_root
, me
->y_root
);
3196 } else if (flags
.resizing
) {
3197 doResize(me
->x_root
, me
->y_root
);
3199 if (! flags
.resizing
&& (me
->state
& Button1Mask
) &&
3200 (functions
& Func_Move
) &&
3201 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3202 frame
.handle
== me
->window
|| frame
.window
== me
->window
)) {
3203 beginMove(me
->x_root
, me
->y_root
);
3204 } else if ((functions
& Func_Resize
) &&
3205 (((me
->state
& Button1Mask
) &&
3206 (me
->window
== frame
.right_grip
||
3207 me
->window
== frame
.left_grip
)) ||
3208 (me
->state
& (Mod1Mask
| Button3Mask
) &&
3209 me
->window
== frame
.window
))) {
3210 beginResize(me
->x_root
, me
->y_root
,
3211 (me
->window
== frame
.left_grip
) ? BottomLeft
: BottomRight
);
3218 void BlackboxWindow::shapeEvent(XShapeEvent
*) {
3219 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
3226 bool BlackboxWindow::validateClient(void) const {
3227 XSync(blackbox
->getXDisplay(), False
);
3230 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3231 DestroyNotify
, &e
) ||
3232 XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3234 XPutBackEvent(blackbox
->getXDisplay(), &e
);
3243 void BlackboxWindow::restore(bool remap
) {
3244 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeDelete
);
3245 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
3246 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, NoEventMask
);
3248 restoreGravity(client
.rect
);
3250 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
3251 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
3253 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, client
.old_bw
);
3256 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3257 ReparentNotify
, &ev
)) {
3260 // according to the ICCCM - if the client doesn't reparent to
3261 // root, then we have to do it for them
3262 XReparentWindow(blackbox
->getXDisplay(), client
.window
,
3263 screen
->getRootWindow(),
3264 client
.rect
.x(), client
.rect
.y());
3267 if (remap
) XMapWindow(blackbox
->getXDisplay(), client
.window
);
3271 // timer for autoraise
3272 void BlackboxWindow::timeout(void) {
3273 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3277 void BlackboxWindow::changeBlackboxHints(BlackboxHints
*net
) {
3278 if ((net
->flags
& AttribShaded
) &&
3279 ((blackbox_attrib
.attrib
& AttribShaded
) !=
3280 (net
->attrib
& AttribShaded
)))
3283 if (flags
.visible
&& // watch out for requests when we can not be seen
3284 (net
->flags
& (AttribMaxVert
| AttribMaxHoriz
)) &&
3285 ((blackbox_attrib
.attrib
& (AttribMaxVert
| AttribMaxHoriz
)) !=
3286 (net
->attrib
& (AttribMaxVert
| AttribMaxHoriz
)))) {
3287 if (flags
.maximized
) {
3292 if ((net
->flags
& AttribMaxHoriz
) && (net
->flags
& AttribMaxVert
))
3293 button
= ((net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0);
3294 else if (net
->flags
& AttribMaxVert
)
3295 button
= ((net
->attrib
& AttribMaxVert
) ? 2 : 0);
3296 else if (net
->flags
& AttribMaxHoriz
)
3297 button
= ((net
->attrib
& AttribMaxHoriz
) ? 3 : 0);
3303 if ((net
->flags
& AttribOmnipresent
) &&
3304 ((blackbox_attrib
.attrib
& AttribOmnipresent
) !=
3305 (net
->attrib
& AttribOmnipresent
)))
3308 if ((net
->flags
& AttribWorkspace
) &&
3309 (blackbox_attrib
.workspace
!= net
->workspace
)) {
3310 screen
->reassociateWindow(this, net
->workspace
, True
);
3312 if (screen
->getCurrentWorkspaceID() != net
->workspace
) {
3316 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3320 if (net
->flags
& AttribDecoration
) {
3321 switch (net
->decoration
) {
3323 // clear all decorations except close
3324 decorations
&= Decor_Close
;
3330 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Iconify
;
3332 decorations
= ((functions
& Func_Resize
) && !isTransient() ?
3333 decorations
| Decor_Handle
:
3334 decorations
&= ~Decor_Handle
);
3335 decorations
= (functions
& Func_Maximize
?
3336 decorations
| Decor_Maximize
:
3337 decorations
&= ~Decor_Maximize
);
3342 decorations
|= Decor_Titlebar
| Decor_Iconify
;
3343 decorations
&= ~(Decor_Border
| Decor_Handle
);
3345 decorations
= (functions
& Func_Maximize
?
3346 decorations
| Decor_Maximize
:
3347 decorations
&= ~Decor_Maximize
);
3352 decorations
|= Decor_Titlebar
;
3353 decorations
&= ~(Decor_Iconify
| Decor_Border
);
3355 decorations
= ((functions
& Func_Resize
) && !isTransient() ?
3356 decorations
| Decor_Handle
:
3357 decorations
&= ~Decor_Handle
);
3358 decorations
= (functions
& Func_Maximize
?
3359 decorations
| Decor_Maximize
:
3360 decorations
&= ~Decor_Maximize
);
3365 // we can not be shaded if we lack a titlebar
3366 if (flags
.shaded
&& ! (decorations
& Decor_Titlebar
))
3369 if (flags
.visible
&& frame
.window
) {
3370 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
3371 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
3375 setState(current_state
);
3381 * Set the sizes of all components of the window frame
3382 * (the window decorations).
3383 * These values are based upon the current style settings and the client
3384 * window's dimensions.
3386 void BlackboxWindow::upsize(void) {
3387 frame
.bevel_w
= screen
->getBevelWidth();
3389 if (decorations
& Decor_Border
) {
3390 frame
.border_w
= screen
->getBorderWidth();
3391 if (! isTransient())
3392 frame
.mwm_border_w
= screen
->getFrameWidth();
3394 frame
.mwm_border_w
= 0;
3396 frame
.mwm_border_w
= frame
.border_w
= 0;
3399 if (decorations
& Decor_Titlebar
) {
3400 // the height of the titlebar is based upon the height of the font being
3401 // used to display the window's title
3402 WindowStyle
*style
= screen
->getWindowStyle();
3403 if (i18n
.multibyte())
3404 frame
.title_h
= (style
->fontset_extents
->max_ink_extent
.height
+
3405 (frame
.bevel_w
* 2) + 2);
3407 frame
.title_h
= (style
->font
->ascent
+ style
->font
->descent
+
3408 (frame
.bevel_w
* 2) + 2);
3410 frame
.label_h
= frame
.title_h
- (frame
.bevel_w
* 2);
3411 frame
.button_w
= (frame
.label_h
- 2);
3413 // set the top frame margin
3414 frame
.margin
.top
= frame
.border_w
+ frame
.title_h
+
3415 frame
.border_w
+ frame
.mwm_border_w
;
3421 // set the top frame margin
3422 frame
.margin
.top
= frame
.border_w
+ frame
.mwm_border_w
;
3425 // set the left/right frame margin
3426 frame
.margin
.left
= frame
.margin
.right
= frame
.border_w
+ frame
.mwm_border_w
;
3428 if (decorations
& Decor_Handle
) {
3429 frame
.grip_w
= frame
.button_w
* 2;
3430 frame
.handle_h
= screen
->getHandleWidth();
3432 // set the bottom frame margin
3433 frame
.margin
.bottom
= frame
.border_w
+ frame
.handle_h
+
3434 frame
.border_w
+ frame
.mwm_border_w
;
3439 // set the bottom frame margin
3440 frame
.margin
.bottom
= frame
.border_w
+ frame
.mwm_border_w
;
3444 We first get the normal dimensions and use this to define the inside_w/h
3445 then we modify the height if shading is in effect.
3446 If the shade state is not considered then frame.rect gets reset to the
3447 normal window size on a reconfigure() call resulting in improper
3448 dimensions appearing in move/resize and other events.
3451 height
= client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
,
3452 width
= client
.rect
.width() + frame
.margin
.left
+ frame
.margin
.right
;
3454 frame
.inside_w
= width
- (frame
.border_w
* 2);
3455 frame
.inside_h
= height
- (frame
.border_w
* 2);
3458 height
= frame
.title_h
+ (frame
.border_w
* 2);
3459 frame
.rect
.setSize(width
, height
);
3464 * Calculate the size of the client window and constrain it to the
3465 * size specified by the size hints of the client window.
3467 * The logical width and height are placed into pw and ph, if they
3468 * are non-zero. Logical size refers to the users perception of
3469 * the window size (for example an xterm resizes in cells, not in pixels).
3471 * The physical geometry is placed into frame.changing_{x,y,width,height}.
3472 * Physical geometry refers to the geometry of the window in pixels.
3474 void BlackboxWindow::constrain(Corner anchor
, int *pw
, int *ph
) {
3475 // frame.changing represents the requested frame size, we need to
3476 // strip the frame margin off and constrain the client size
3477 frame
.changing
.setCoords(frame
.changing
.left() + frame
.margin
.left
,
3478 frame
.changing
.top() + frame
.margin
.top
,
3479 frame
.changing
.right() - frame
.margin
.right
,
3480 frame
.changing
.bottom() - frame
.margin
.bottom
);
3482 int dw
= frame
.changing
.width(), dh
= frame
.changing
.height(),
3483 base_width
= (client
.base_width
) ? client
.base_width
: client
.min_width
,
3484 base_height
= (client
.base_height
) ? client
.base_height
:
3488 if (dw
< static_cast<signed>(client
.min_width
)) dw
= client
.min_width
;
3489 if (dh
< static_cast<signed>(client
.min_height
)) dh
= client
.min_height
;
3490 if (dw
> static_cast<signed>(client
.max_width
)) dw
= client
.max_width
;
3491 if (dh
> static_cast<signed>(client
.max_height
)) dh
= client
.max_height
;
3494 dw
/= client
.width_inc
;
3496 dh
/= client
.height_inc
;
3499 if (client
.width_inc
== 1)
3500 *pw
= dw
+ base_width
;
3505 if (client
.height_inc
== 1)
3506 *ph
= dh
+ base_height
;
3511 dw
*= client
.width_inc
;
3513 dh
*= client
.height_inc
;
3516 frame
.changing
.setSize(dw
, dh
);
3518 // add the frame margin back onto frame.changing
3519 frame
.changing
.setCoords(frame
.changing
.left() - frame
.margin
.left
,
3520 frame
.changing
.top() - frame
.margin
.top
,
3521 frame
.changing
.right() + frame
.margin
.right
,
3522 frame
.changing
.bottom() + frame
.margin
.bottom
);
3524 // move frame.changing to the specified anchor
3532 dx
= frame
.rect
.right() - frame
.changing
.right();
3536 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3540 dx
= frame
.rect
.right() - frame
.changing
.right();
3541 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3545 assert(false); // unhandled corner
3547 frame
.changing
.setPos(frame
.changing
.x() + dx
, frame
.changing
.y() + dy
);
3551 int WindowStyle::doJustify(const char *text
, int &start_pos
,
3552 unsigned int max_length
, unsigned int modifier
,
3553 bool multibyte
) const {
3554 size_t text_len
= strlen(text
);
3555 unsigned int length
;
3559 XRectangle ink
, logical
;
3560 XmbTextExtents(fontset
, text
, text_len
, &ink
, &logical
);
3561 length
= logical
.width
;
3563 length
= XTextWidth(font
, text
, text_len
);
3566 } while (length
> max_length
&& text_len
-- > 0);
3570 start_pos
+= max_length
- length
;
3574 start_pos
+= (max_length
- length
) / 2;
3586 BWindowGroup::BWindowGroup(Blackbox
*b
, Window _group
)
3587 : blackbox(b
), group(_group
) {
3588 XWindowAttributes wattrib
;
3589 if (! XGetWindowAttributes(blackbox
->getXDisplay(), group
, &wattrib
)) {
3590 // group window doesn't seem to exist anymore
3596 watch for destroy notify on the group window (in addition to
3597 any other events we are looking for)
3599 since some managed windows can also be window group controllers,
3600 we need to make sure that we don't clobber the event mask for the
3603 XSelectInput(blackbox
->getXDisplay(), group
,
3604 wattrib
.your_event_mask
| StructureNotifyMask
);
3606 blackbox
->saveGroupSearch(group
, this);
3610 BWindowGroup::~BWindowGroup(void) {
3611 blackbox
->removeGroupSearch(group
);
3616 BWindowGroup::find(BScreen
*screen
, bool allow_transients
) const {
3617 BlackboxWindow
*ret
= blackbox
->getFocusedWindow();
3619 // does the focus window match (or any transient_fors)?
3621 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3622 if (ret
->isTransient() && allow_transients
) break;
3623 else if (! ret
->isTransient()) break;
3626 ret
= ret
->getTransientFor();
3629 if (ret
) return ret
;
3631 // the focus window didn't match, look in the group's window list
3632 BlackboxWindowList::const_iterator it
, end
= windowList
.end();
3633 for (it
= windowList
.begin(); it
!= end
; ++it
) {
3635 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3636 if (ret
->isTransient() && allow_transients
) break;
3637 else if (! ret
->isTransient()) break;