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"
49 #include "Iconmenu.hh"
55 #include "Windowmenu.hh"
56 #include "Workspace.hh"
62 * Initializes the class with default values/the window's set initial values.
64 BlackboxWindow::BlackboxWindow(Blackbox
*b
, Window w
, BScreen
*s
) {
65 // fprintf(stderr, "BlackboxWindow size: %d bytes\n",
66 // sizeof(BlackboxWindow));
69 fprintf(stderr
, "BlackboxWindow::BlackboxWindow(): creating 0x%lx\n", w
);
73 set timer to zero... it is initialized properly later, so we check
74 if timer is zero in the destructor, and assume that the window is not
75 fully constructed if timer is zero...
81 xatom
= blackbox
->getXAtom();
83 if (! validateClient()) {
88 // set the eventmask early in the game so that we make sure we get
89 // all the events we are interested in
90 XSetWindowAttributes attrib_set
;
91 attrib_set
.event_mask
= PropertyChangeMask
| FocusChangeMask
|
93 attrib_set
.do_not_propagate_mask
= ButtonPressMask
| ButtonReleaseMask
|
95 XChangeWindowAttributes(blackbox
->getXDisplay(), client
.window
,
96 CWEventMask
|CWDontPropagate
, &attrib_set
);
98 // fetch client size and placement
99 XWindowAttributes wattrib
;
100 if ((! XGetWindowAttributes(blackbox
->getXDisplay(),
101 client
.window
, &wattrib
)) ||
102 (! wattrib
.screen
) || wattrib
.override_redirect
) {
105 "BlackboxWindow::BlackboxWindow(): XGetWindowAttributes failed\n");
112 flags
.moving
= flags
.resizing
= flags
.shaded
= flags
.visible
=
113 flags
.iconic
= flags
.focused
= flags
.stuck
= flags
.modal
=
114 flags
.send_focus_message
= flags
.shaped
= flags
.skip_taskbar
=
115 flags
.skip_pager
= flags
.fullscreen
= False
;
118 blackbox_attrib
.workspace
= window_number
= BSENTINEL
;
120 blackbox_attrib
.flags
= blackbox_attrib
.attrib
= blackbox_attrib
.stack
121 = blackbox_attrib
.decoration
= 0l;
122 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
123 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
126 frame
.window
= frame
.plate
= frame
.title
= frame
.handle
= None
;
127 frame
.close_button
= frame
.iconify_button
= frame
.maximize_button
= None
;
128 frame
.right_grip
= frame
.left_grip
= None
;
130 frame
.ulabel_pixel
= frame
.flabel_pixel
= frame
.utitle_pixel
=
131 frame
.ftitle_pixel
= frame
.uhandle_pixel
= frame
.fhandle_pixel
=
132 frame
.ubutton_pixel
= frame
.fbutton_pixel
= frame
.pbutton_pixel
=
133 frame
.uborder_pixel
= frame
.fborder_pixel
= frame
.ugrip_pixel
=
134 frame
.fgrip_pixel
= 0;
135 frame
.utitle
= frame
.ftitle
= frame
.uhandle
= frame
.fhandle
= None
;
136 frame
.ulabel
= frame
.flabel
= frame
.ubutton
= frame
.fbutton
= None
;
137 frame
.pbutton
= frame
.ugrip
= frame
.fgrip
= None
;
139 decorations
= Decor_Titlebar
| Decor_Border
| Decor_Handle
|
140 Decor_Iconify
| Decor_Maximize
;
141 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
143 client
.wm_hint_flags
= client
.normal_hint_flags
= 0;
144 client
.window_group
= None
;
145 client
.transient_for
= 0;
148 get the initial size and location of client window (relative to the
149 _root window_). This position is the reference point used with the
150 window's gravity to find the window's initial position.
152 client
.rect
.setRect(wattrib
.x
, wattrib
.y
, wattrib
.width
, wattrib
.height
);
153 client
.old_bw
= wattrib
.border_width
;
156 lastButtonPressTime
= 0;
158 timer
= new BTimer(blackbox
, this);
159 timer
->setTimeout(blackbox
->getAutoRaiseDelay());
161 if (! getBlackboxHints()) {
166 // get size, aspect, minimum/maximum size and other hints set by the
172 if (client
.initial_state
== WithdrawnState
) {
173 screen
->getSlit()->addClient(client
.window
);
178 if (isKDESystrayWindow()) {
179 screen
->addSystrayWindow(client
.window
);
184 frame
.window
= createToplevelWindow();
185 frame
.plate
= createChildWindow(frame
.window
);
186 associateClientWindow();
188 blackbox
->saveWindowSearch(frame
.window
, this);
189 blackbox
->saveWindowSearch(frame
.plate
, this);
190 blackbox
->saveWindowSearch(client
.window
, this);
192 // determine if this is a transient window
195 // determine the window's type, so we can decide its decorations and
196 // functionality, or if we should not manage it at all
199 // adjust the window decorations/behavior based on the window type
200 switch (window_type
) {
202 // desktop windows are not managed by us, we just make sure they stay on the
207 // docks (such as kicker) cannot be moved, and appear on all workspaces
208 functions
&= ~(Func_Move
);
213 // these windows have minimal decorations, only a titlebar, and cannot
214 // be resized or iconified
215 decorations
&= ~(Decor_Maximize
| Decor_Handle
| Decor_Border
|
217 functions
&= ~(Func_Resize
| Func_Maximize
| Func_Iconify
);
221 // splash screens have no functionality or decorations, they are left up
222 // to the application which created them
228 // dialogs cannot be maximized, and don't display a handle
229 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
230 functions
&= ~Func_Maximize
;
234 // normal windows retain all of the possible decorations and functionality
238 // further adjeust the window's decorations/behavior based on window sizes
239 if ((client
.normal_hint_flags
& PMinSize
) &&
240 (client
.normal_hint_flags
& PMaxSize
) &&
241 client
.max_width
<= client
.min_width
&&
242 client
.max_height
<= client
.min_height
) {
243 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
244 functions
&= ~(Func_Resize
| Func_Maximize
);
250 bool place_window
= True
;
251 if (blackbox
->isStartup() || isTransient() ||
252 client
.normal_hint_flags
& (PPosition
|USPosition
)) {
253 applyGravity(frame
.rect
);
255 if (blackbox
->isStartup() ||
256 client
.rect
.intersects(screen
->availableArea()))
257 place_window
= False
;
260 // add the window's strut. note this is done *after* placing the window.
261 screen
->addStrut(&client
.strut
);
264 if (decorations
& Decor_Titlebar
)
267 if (decorations
& Decor_Handle
)
271 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
278 windowmenu
= new Windowmenu(this);
280 if (blackbox_attrib
.workspace
>= screen
->getWorkspaceCount())
281 screen
->getCurrentWorkspace()->addWindow(this, place_window
);
283 screen
->getWorkspace(blackbox_attrib
.workspace
)->
284 addWindow(this, place_window
);
286 if (! place_window
) {
287 // don't need to call configure if we are letting the workspace
289 configure(frame
.rect
.x(), frame
.rect
.y(),
290 frame
.rect
.width(), frame
.rect
.height());
293 // preserve the window's initial state on first map, and its current state
296 if (client
.wm_hint_flags
& StateHint
)
297 current_state
= client
.initial_state
;
299 current_state
= NormalState
;
302 // get sticky state from our parent window if we've got one
303 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
304 client
.transient_for
->isStuck() != flags
.stuck
)
308 flags
.shaded
= False
;
309 unsigned long orig_state
= current_state
;
313 At this point in the life of a window, current_state should only be set
314 to IconicState if the window was an *icon*, not if it was shaded.
316 if (orig_state
!= IconicState
)
317 current_state
= NormalState
;
325 if (flags
.maximized
&& (functions
& Func_Maximize
)) {
330 When the window is mapped (and also when its attributes are restored), the
331 current_state that was set here will be used.
332 It is set to Normal if the window is to be mapped or it is set to Iconic
333 if the window is to be iconified.
334 *Note* that for sticky windows, the same rules apply here, they are in
335 fact never set to Iconic since there is no way for us to tell if a sticky
336 window was iconified previously.
342 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
348 BlackboxWindow::~BlackboxWindow(void) {
350 fprintf(stderr
, "BlackboxWindow::~BlackboxWindow: destroying 0x%lx\n",
354 if (! timer
) // window not managed...
357 screen
->removeStrut(&client
.strut
);
358 screen
->updateAvailableArea();
360 // We don't need to worry about resizing because resizing always grabs the X
361 // server. This should only ever happen if using opaque moving.
369 if (client
.window_group
) {
370 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
371 if (group
) group
->removeWindow(this);
374 // remove ourselves from our transient_for
376 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
377 client
.transient_for
->client
.transientList
.remove(this);
379 client
.transient_for
= (BlackboxWindow
*) 0;
382 if (client
.transientList
.size() > 0) {
383 // reset transient_for for all transients
384 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
385 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
386 (*it
)->client
.transient_for
= (BlackboxWindow
*) 0;
397 blackbox
->removeWindowSearch(frame
.plate
);
398 XDestroyWindow(blackbox
->getXDisplay(), frame
.plate
);
402 blackbox
->removeWindowSearch(frame
.window
);
403 XDestroyWindow(blackbox
->getXDisplay(), frame
.window
);
406 blackbox
->removeWindowSearch(client
.window
);
411 * Creates a new top level window, with a given location, size, and border
413 * Returns: the newly created window
415 Window
BlackboxWindow::createToplevelWindow(void) {
416 XSetWindowAttributes attrib_create
;
417 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
| CWColormap
|
418 CWOverrideRedirect
| CWEventMask
;
420 attrib_create
.background_pixmap
= None
;
421 attrib_create
.colormap
= screen
->getColormap();
422 attrib_create
.override_redirect
= True
;
423 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
424 ButtonMotionMask
| EnterWindowMask
;
426 return XCreateWindow(blackbox
->getXDisplay(), screen
->getRootWindow(),
427 -1, -1, 1, 1, frame
.border_w
, screen
->getDepth(),
428 InputOutput
, screen
->getVisual(), create_mask
,
434 * Creates a child window, and optionally associates a given cursor with
437 Window
BlackboxWindow::createChildWindow(Window parent
, Cursor cursor
) {
438 XSetWindowAttributes attrib_create
;
439 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
|
442 attrib_create
.background_pixmap
= None
;
443 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
444 ButtonMotionMask
| ExposureMask
;
447 create_mask
|= CWCursor
;
448 attrib_create
.cursor
= cursor
;
451 return XCreateWindow(blackbox
->getXDisplay(), parent
, 0, 0, 1, 1, 0,
452 screen
->getDepth(), InputOutput
, screen
->getVisual(),
453 create_mask
, &attrib_create
);
457 void BlackboxWindow::associateClientWindow(void) {
458 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, 0);
462 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeInsert
);
464 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, SubstructureRedirectMask
);
466 XGrabServer(blackbox
->getXDisplay());
467 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
468 XReparentWindow(blackbox
->getXDisplay(), client
.window
, frame
.plate
, 0, 0);
469 XSelectInput(blackbox
->getXDisplay(), client
.window
,
470 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
471 XUngrabServer(blackbox
->getXDisplay());
473 XRaiseWindow(blackbox
->getXDisplay(), frame
.plate
);
474 XMapSubwindows(blackbox
->getXDisplay(), frame
.plate
);
478 if (blackbox
->hasShapeExtensions()) {
479 XShapeSelectInput(blackbox
->getXDisplay(), client
.window
,
486 XShapeQueryExtents(blackbox
->getXDisplay(), client
.window
, &shaped
,
487 &foo
, &foo
, &ufoo
, &ufoo
, &foo
, &foo
, &foo
,
489 flags
.shaped
= shaped
;
495 void BlackboxWindow::decorate(void) {
498 texture
= &(screen
->getWindowStyle()->b_focus
);
499 frame
.fbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
502 frame
.fbutton_pixel
= texture
->color().pixel();
504 texture
= &(screen
->getWindowStyle()->b_unfocus
);
505 frame
.ubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
508 frame
.ubutton_pixel
= texture
->color().pixel();
510 texture
= &(screen
->getWindowStyle()->b_pressed
);
511 frame
.pbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
514 frame
.pbutton_pixel
= texture
->color().pixel();
516 if (decorations
& Decor_Titlebar
) {
517 texture
= &(screen
->getWindowStyle()->t_focus
);
518 frame
.ftitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
521 frame
.ftitle_pixel
= texture
->color().pixel();
523 texture
= &(screen
->getWindowStyle()->t_unfocus
);
524 frame
.utitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
527 frame
.utitle_pixel
= texture
->color().pixel();
529 XSetWindowBorder(blackbox
->getXDisplay(), frame
.title
,
530 screen
->getBorderColor()->pixel());
535 if (decorations
& Decor_Border
) {
536 frame
.fborder_pixel
= screen
->getWindowStyle()->f_focus
.pixel();
537 frame
.uborder_pixel
= screen
->getWindowStyle()->f_unfocus
.pixel();
538 blackbox_attrib
.flags
|= AttribDecoration
;
539 blackbox_attrib
.decoration
= DecorNormal
;
541 blackbox_attrib
.flags
|= AttribDecoration
;
542 blackbox_attrib
.decoration
= DecorNone
;
545 if (decorations
& Decor_Handle
) {
546 texture
= &(screen
->getWindowStyle()->h_focus
);
547 frame
.fhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
550 frame
.fhandle_pixel
= texture
->color().pixel();
552 texture
= &(screen
->getWindowStyle()->h_unfocus
);
553 frame
.uhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
556 frame
.uhandle_pixel
= texture
->color().pixel();
558 texture
= &(screen
->getWindowStyle()->g_focus
);
559 frame
.fgrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.fgrip
);
561 frame
.fgrip_pixel
= texture
->color().pixel();
563 texture
= &(screen
->getWindowStyle()->g_unfocus
);
564 frame
.ugrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.ugrip
);
566 frame
.ugrip_pixel
= texture
->color().pixel();
568 XSetWindowBorder(blackbox
->getXDisplay(), frame
.handle
,
569 screen
->getBorderColor()->pixel());
570 XSetWindowBorder(blackbox
->getXDisplay(), frame
.left_grip
,
571 screen
->getBorderColor()->pixel());
572 XSetWindowBorder(blackbox
->getXDisplay(), frame
.right_grip
,
573 screen
->getBorderColor()->pixel());
576 XSetWindowBorder(blackbox
->getXDisplay(), frame
.window
,
577 screen
->getBorderColor()->pixel());
581 void BlackboxWindow::decorateLabel(void) {
584 texture
= &(screen
->getWindowStyle()->l_focus
);
585 frame
.flabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.flabel
);
587 frame
.flabel_pixel
= texture
->color().pixel();
589 texture
= &(screen
->getWindowStyle()->l_unfocus
);
590 frame
.ulabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.ulabel
);
592 frame
.ulabel_pixel
= texture
->color().pixel();
596 void BlackboxWindow::createHandle(void) {
597 frame
.handle
= createChildWindow(frame
.window
);
598 blackbox
->saveWindowSearch(frame
.handle
, this);
601 createChildWindow(frame
.handle
, blackbox
->getLowerLeftAngleCursor());
602 blackbox
->saveWindowSearch(frame
.left_grip
, this);
605 createChildWindow(frame
.handle
, blackbox
->getLowerRightAngleCursor());
606 blackbox
->saveWindowSearch(frame
.right_grip
, this);
610 void BlackboxWindow::destroyHandle(void) {
612 screen
->getImageControl()->removeImage(frame
.fhandle
);
615 screen
->getImageControl()->removeImage(frame
.uhandle
);
618 screen
->getImageControl()->removeImage(frame
.fgrip
);
621 screen
->getImageControl()->removeImage(frame
.ugrip
);
623 blackbox
->removeWindowSearch(frame
.left_grip
);
624 blackbox
->removeWindowSearch(frame
.right_grip
);
626 XDestroyWindow(blackbox
->getXDisplay(), frame
.left_grip
);
627 XDestroyWindow(blackbox
->getXDisplay(), frame
.right_grip
);
628 frame
.left_grip
= frame
.right_grip
= None
;
630 blackbox
->removeWindowSearch(frame
.handle
);
631 XDestroyWindow(blackbox
->getXDisplay(), frame
.handle
);
636 void BlackboxWindow::createTitlebar(void) {
637 frame
.title
= createChildWindow(frame
.window
);
638 frame
.label
= createChildWindow(frame
.title
);
639 blackbox
->saveWindowSearch(frame
.title
, this);
640 blackbox
->saveWindowSearch(frame
.label
, this);
642 if (decorations
& Decor_Iconify
) createIconifyButton();
643 if (decorations
& Decor_Maximize
) createMaximizeButton();
644 if (decorations
& Decor_Close
) createCloseButton();
648 void BlackboxWindow::destroyTitlebar(void) {
649 if (frame
.close_button
)
650 destroyCloseButton();
652 if (frame
.iconify_button
)
653 destroyIconifyButton();
655 if (frame
.maximize_button
)
656 destroyMaximizeButton();
659 screen
->getImageControl()->removeImage(frame
.ftitle
);
662 screen
->getImageControl()->removeImage(frame
.utitle
);
665 screen
->getImageControl()->removeImage(frame
.flabel
);
668 screen
->getImageControl()->removeImage(frame
.ulabel
);
671 screen
->getImageControl()->removeImage(frame
.fbutton
);
674 screen
->getImageControl()->removeImage(frame
.ubutton
);
677 screen
->getImageControl()->removeImage(frame
.pbutton
);
679 blackbox
->removeWindowSearch(frame
.title
);
680 blackbox
->removeWindowSearch(frame
.label
);
682 XDestroyWindow(blackbox
->getXDisplay(), frame
.label
);
683 XDestroyWindow(blackbox
->getXDisplay(), frame
.title
);
684 frame
.title
= frame
.label
= None
;
688 void BlackboxWindow::createCloseButton(void) {
689 if (frame
.title
!= None
) {
690 frame
.close_button
= createChildWindow(frame
.title
);
691 blackbox
->saveWindowSearch(frame
.close_button
, this);
696 void BlackboxWindow::destroyCloseButton(void) {
697 blackbox
->removeWindowSearch(frame
.close_button
);
698 XDestroyWindow(blackbox
->getXDisplay(), frame
.close_button
);
699 frame
.close_button
= None
;
703 void BlackboxWindow::createIconifyButton(void) {
704 if (frame
.title
!= None
) {
705 frame
.iconify_button
= createChildWindow(frame
.title
);
706 blackbox
->saveWindowSearch(frame
.iconify_button
, this);
711 void BlackboxWindow::destroyIconifyButton(void) {
712 blackbox
->removeWindowSearch(frame
.iconify_button
);
713 XDestroyWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
714 frame
.iconify_button
= None
;
718 void BlackboxWindow::createMaximizeButton(void) {
719 if (frame
.title
!= None
) {
720 frame
.maximize_button
= createChildWindow(frame
.title
);
721 blackbox
->saveWindowSearch(frame
.maximize_button
, this);
726 void BlackboxWindow::destroyMaximizeButton(void) {
727 blackbox
->removeWindowSearch(frame
.maximize_button
);
728 XDestroyWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
729 frame
.maximize_button
= None
;
733 void BlackboxWindow::positionButtons(bool redecorate_label
) {
734 string layout
= blackbox
->getTitlebarLayout();
737 bool hasclose
, hasiconify
, hasmaximize
, haslabel
;
738 hasclose
= hasiconify
= hasmaximize
= haslabel
= false;
740 string::const_iterator it
, end
;
741 for (it
= layout
.begin(), end
= layout
.end(); it
!= end
; ++it
) {
744 if (! hasclose
&& (decorations
& Decor_Close
)) {
750 if (! hasiconify
&& (decorations
& Decor_Iconify
)) {
756 if (! hasmaximize
&& (decorations
& Decor_Maximize
)) {
768 if (! hasclose
&& frame
.close_button
)
769 destroyCloseButton();
770 if (! hasiconify
&& frame
.iconify_button
)
771 destroyIconifyButton();
772 if (! hasmaximize
&& frame
.maximize_button
)
773 destroyMaximizeButton();
775 parsed
+= 'L'; // require that the label be in the layout
777 const unsigned int bsep
= frame
.bevel_w
+ 1; // separation between elements
778 const unsigned int by
= frame
.bevel_w
+ 1;
779 const unsigned int ty
= frame
.bevel_w
;
781 frame
.label_w
= frame
.inside_w
- bsep
* 2 -
782 (frame
.button_w
+ bsep
) * (parsed
.size() - 1);
784 unsigned int x
= bsep
;
785 for (it
= parsed
.begin(), end
= parsed
.end(); it
!= end
; ++it
) {
788 if (! frame
.close_button
) createCloseButton();
789 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.close_button
, x
, by
,
790 frame
.button_w
, frame
.button_w
);
791 x
+= frame
.button_w
+ bsep
;
794 if (! frame
.iconify_button
) createIconifyButton();
795 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.iconify_button
, x
, by
,
796 frame
.button_w
, frame
.button_w
);
797 x
+= frame
.button_w
+ bsep
;
800 if (! frame
.maximize_button
) createMaximizeButton();
801 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.maximize_button
, x
, by
,
802 frame
.button_w
, frame
.button_w
);
803 x
+= frame
.button_w
+ bsep
;
806 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.label
, x
, ty
,
807 frame
.label_w
, frame
.label_h
);
808 x
+= frame
.label_w
+ bsep
;
813 if (redecorate_label
) decorateLabel();
819 void BlackboxWindow::reconfigure(void) {
828 windowmenu
->move(windowmenu
->getX(), frame
.rect
.y() + frame
.title_h
);
829 windowmenu
->reconfigure();
834 void BlackboxWindow::grabButtons(void) {
835 if ((! screen
->isSloppyFocus()) || screen
->doClickRaise())
836 // grab button 1 for changing focus/raising
837 blackbox
->grabButton(Button1
, 0, frame
.plate
, True
, ButtonPressMask
,
838 GrabModeSync
, GrabModeSync
, frame
.plate
, None
);
840 if (functions
& Func_Move
)
841 blackbox
->grabButton(Button1
, Mod1Mask
, frame
.window
, True
,
842 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
843 GrabModeAsync
, frame
.window
,
844 blackbox
->getMoveCursor());
845 if (functions
& Func_Resize
)
846 blackbox
->grabButton(Button3
, Mod1Mask
, frame
.window
, True
,
847 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
848 GrabModeAsync
, frame
.window
,
849 blackbox
->getLowerRightAngleCursor());
853 void BlackboxWindow::ungrabButtons(void) {
854 if ((! screen
->isSloppyFocus()) || screen
->doClickRaise())
855 blackbox
->ungrabButton(Button1
, 0, frame
.plate
);
857 blackbox
->ungrabButton(Button1
, Mod1Mask
, frame
.window
);
858 blackbox
->ungrabButton(Button3
, Mod1Mask
, frame
.window
);
862 void BlackboxWindow::positionWindows(void) {
863 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.window
,
864 frame
.rect
.x(), frame
.rect
.y(), frame
.inside_w
,
865 (flags
.shaded
) ? frame
.title_h
: frame
.inside_h
);
866 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.window
,
868 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.plate
,
870 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.plate
,
871 frame
.margin
.left
- frame
.mwm_border_w
- frame
.border_w
,
872 frame
.margin
.top
- frame
.mwm_border_w
- frame
.border_w
,
873 client
.rect
.width(), client
.rect
.height());
874 XMoveResizeWindow(blackbox
->getXDisplay(), client
.window
,
875 0, 0, client
.rect
.width(), client
.rect
.height());
876 // ensure client.rect contains the real location
877 client
.rect
.setCoords(frame
.rect
.left() + frame
.margin
.left
,
878 frame
.rect
.top() + frame
.margin
.top
,
879 frame
.rect
.right() - frame
.margin
.right
,
880 frame
.rect
.bottom() - frame
.margin
.bottom
);
882 if (decorations
& Decor_Titlebar
) {
883 if (frame
.title
== None
) createTitlebar();
885 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.title
,
887 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.title
, -frame
.border_w
,
888 -frame
.border_w
, frame
.inside_w
, frame
.title_h
);
891 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
892 XMapWindow(blackbox
->getXDisplay(), frame
.title
);
893 } else if (frame
.title
) {
896 if (decorations
& Decor_Handle
) {
897 if (frame
.handle
== None
) createHandle();
898 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.handle
,
900 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.left_grip
,
902 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.right_grip
,
905 // use client.rect here so the value is correct even if shaded
906 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.handle
,
908 client
.rect
.height() + frame
.margin
.top
+
909 frame
.mwm_border_w
- frame
.border_w
,
910 frame
.inside_w
, frame
.handle_h
);
911 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.left_grip
,
912 -frame
.border_w
, -frame
.border_w
,
913 frame
.grip_w
, frame
.handle_h
);
914 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.right_grip
,
915 frame
.inside_w
- frame
.grip_w
- frame
.border_w
,
916 -frame
.border_w
, frame
.grip_w
, frame
.handle_h
);
918 XMapSubwindows(blackbox
->getXDisplay(), frame
.handle
);
919 XMapWindow(blackbox
->getXDisplay(), frame
.handle
);
920 } else if (frame
.handle
) {
926 void BlackboxWindow::updateStrut(void) {
927 unsigned long num
= 4;
929 if (! xatom
->getValue(client
.window
, XAtom::net_wm_strut
, XAtom::cardinal
,
934 client
.strut
.left
= data
[0];
935 client
.strut
.right
= data
[1];
936 client
.strut
.top
= data
[2];
937 client
.strut
.bottom
= data
[3];
939 screen
->updateAvailableArea();
946 void BlackboxWindow::getWindowType(void) {
948 if (xatom
->getValue(client
.window
, XAtom::net_wm_window_type
, XAtom::atom
,
950 if (val
== xatom
->getAtom(XAtom::net_wm_window_type_desktop
))
951 window_type
= Type_Desktop
;
952 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_dock
))
953 window_type
= Type_Dock
;
954 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_toolbar
))
955 window_type
= Type_Toolbar
;
956 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_menu
))
957 window_type
= Type_Menu
;
958 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_utility
))
959 window_type
= Type_Utility
;
960 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_splash
))
961 window_type
= Type_Splash
;
962 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_dialog
))
963 window_type
= Type_Dialog
;
964 else //if (val[0] == xatom->getAtom(XAtom::net_wm_window_type_normal))
965 window_type
= Type_Normal
;
970 * the window type hint was not set, which means we either classify ourself
971 * as a normal window or a dialog, depending on if we are a transient.
974 window_type
= Type_Dialog
;
976 window_type
= Type_Normal
;
980 void BlackboxWindow::getWMName(void) {
981 if (xatom
->getValue(client
.window
, XAtom::net_wm_name
,
982 XAtom::utf8
, client
.title
) &&
983 !client
.title
.empty()) {
984 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
987 //fall through to using WM_NAME
988 if (xatom
->getValue(client
.window
, XAtom::wm_name
, XAtom::ansi
, client
.title
)
989 && !client
.title
.empty()) {
990 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
993 // fall back to an internal default
994 client
.title
= i18n(WindowSet
, WindowUnnamed
, "Unnamed");
995 xatom
->setValue(client
.window
, XAtom::net_wm_visible_name
, XAtom::utf8
,
1000 void BlackboxWindow::getWMIconName(void) {
1001 if (xatom
->getValue(client
.window
, XAtom::net_wm_icon_name
,
1002 XAtom::utf8
, client
.icon_title
) &&
1003 !client
.icon_title
.empty()) {
1004 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1007 //fall through to using WM_ICON_NAME
1008 if (xatom
->getValue(client
.window
, XAtom::wm_icon_name
, XAtom::ansi
,
1009 client
.icon_title
) &&
1010 !client
.icon_title
.empty()) {
1011 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1014 // fall back to using the main name
1015 client
.icon_title
= client
.title
;
1016 xatom
->setValue(client
.window
, XAtom::net_wm_visible_icon_name
, XAtom::utf8
,
1022 * Retrieve which WM Protocols are supported by the client window.
1023 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
1024 * window's decorations and allow the close behavior.
1025 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
1028 void BlackboxWindow::getWMProtocols(void) {
1032 if (XGetWMProtocols(blackbox
->getXDisplay(), client
.window
,
1033 &proto
, &num_return
)) {
1034 for (int i
= 0; i
< num_return
; ++i
) {
1035 if (proto
[i
] == xatom
->getAtom(XAtom::wm_delete_window
)) {
1036 decorations
|= Decor_Close
;
1037 functions
|= Func_Close
;
1038 } else if (proto
[i
] == xatom
->getAtom(XAtom::wm_take_focus
))
1039 flags
.send_focus_message
= True
;
1040 else if (proto
[i
] == xatom
->getAtom(XAtom::blackbox_structure_messages
))
1041 screen
->addNetizen(new Netizen(screen
, client
.window
));
1050 * Gets the value of the WM_HINTS property.
1051 * If the property is not set, then use a set of default values.
1053 void BlackboxWindow::getWMHints(void) {
1054 focus_mode
= F_Passive
;
1055 client
.initial_state
= NormalState
;
1057 // remove from current window group
1058 if (client
.window_group
) {
1059 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1060 if (group
) group
->removeWindow(this);
1062 client
.window_group
= None
;
1064 XWMHints
*wmhint
= XGetWMHints(blackbox
->getXDisplay(), client
.window
);
1069 if (wmhint
->flags
& InputHint
) {
1070 if (wmhint
->input
== True
) {
1071 if (flags
.send_focus_message
)
1072 focus_mode
= F_LocallyActive
;
1074 if (flags
.send_focus_message
)
1075 focus_mode
= F_GloballyActive
;
1077 focus_mode
= F_NoInput
;
1081 if (wmhint
->flags
& StateHint
)
1082 client
.initial_state
= wmhint
->initial_state
;
1084 if (wmhint
->flags
& WindowGroupHint
) {
1085 client
.window_group
= wmhint
->window_group
;
1087 // add window to the appropriate group
1088 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1089 if (! group
) // no group found, create it!
1090 group
= new BWindowGroup(blackbox
, client
.window_group
);
1091 group
->addWindow(this);
1094 client
.wm_hint_flags
= wmhint
->flags
;
1100 * Gets the value of the WM_NORMAL_HINTS property.
1101 * If the property is not set, then use a set of default values.
1103 void BlackboxWindow::getWMNormalHints(void) {
1105 XSizeHints sizehint
;
1107 client
.min_width
= client
.min_height
=
1108 client
.width_inc
= client
.height_inc
= 1;
1109 client
.base_width
= client
.base_height
= 0;
1112 use the full screen, not the strut modified size. otherwise when the
1113 availableArea changes max_width/height will be incorrect and lead to odd
1116 const Rect
& screen_area
= screen
->getRect();
1117 client
.max_width
= screen_area
.width();
1119 client
.max_height
= screen_area
.height();
1120 client
.min_aspect_x
= client
.min_aspect_y
=
1121 client
.max_aspect_x
= client
.max_aspect_y
= 1;
1122 client
.win_gravity
= NorthWestGravity
;
1124 if (! XGetWMNormalHints(blackbox
->getXDisplay(), client
.window
,
1125 &sizehint
, &icccm_mask
))
1128 client
.normal_hint_flags
= sizehint
.flags
;
1130 if (sizehint
.flags
& PMinSize
) {
1131 client
.min_width
= sizehint
.min_width
;
1132 client
.min_height
= sizehint
.min_height
;
1135 if (sizehint
.flags
& PMaxSize
) {
1136 client
.max_width
= sizehint
.max_width
;
1137 client
.max_height
= sizehint
.max_height
;
1140 if (sizehint
.flags
& PResizeInc
) {
1141 client
.width_inc
= sizehint
.width_inc
;
1142 client
.height_inc
= sizehint
.height_inc
;
1145 if (sizehint
.flags
& PAspect
) {
1146 client
.min_aspect_x
= sizehint
.min_aspect
.x
;
1147 client
.min_aspect_y
= sizehint
.min_aspect
.y
;
1148 client
.max_aspect_x
= sizehint
.max_aspect
.x
;
1149 client
.max_aspect_y
= sizehint
.max_aspect
.y
;
1152 if (sizehint
.flags
& PBaseSize
) {
1153 client
.base_width
= sizehint
.base_width
;
1154 client
.base_height
= sizehint
.base_height
;
1157 if (sizehint
.flags
& PWinGravity
)
1158 client
.win_gravity
= sizehint
.win_gravity
;
1163 * Gets the NETWM hints for the class' contained window.
1165 void BlackboxWindow::getNetWMHints(void) {
1166 unsigned long workspace
;
1168 if (xatom
->getValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1170 if (workspace
== 0xffffffff)
1173 blackbox_attrib
.workspace
= workspace
;
1176 unsigned long *state
;
1177 unsigned long num
= (unsigned) -1;
1178 if (xatom
->getValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
1182 for (unsigned long i
= 0; i
< num
; ++i
) {
1183 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
))
1185 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_shaded
))
1186 flags
.shaded
= True
;
1187 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
))
1188 flags
.skip_taskbar
= True
;
1189 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_pager
))
1190 flags
.skip_pager
= True
;
1191 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_fullscreen
))
1192 flags
.fullscreen
= True
;
1193 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_hidden
))
1194 setState(IconicState
);
1195 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_vert
))
1197 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_horz
))
1201 flags
.maximized
= 1;
1203 flags
.maximized
= 2;
1205 flags
.maximized
= 3;
1213 * Gets the MWM hints for the class' contained window.
1214 * This is used while initializing the window to its first state, and not
1216 * Returns: true if the MWM hints are successfully retreived and applied;
1217 * false if they are not.
1219 void BlackboxWindow::getMWMHints(void) {
1223 num
= PropMwmHintsElements
;
1224 if (! xatom
->getValue(client
.window
, XAtom::motif_wm_hints
,
1225 XAtom::motif_wm_hints
, num
,
1226 (unsigned long **)&mwm_hint
))
1228 if (num
< PropMwmHintsElements
) {
1233 if (mwm_hint
->flags
& MwmHintsDecorations
) {
1234 if (mwm_hint
->decorations
& MwmDecorAll
) {
1235 decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
1236 Decor_Iconify
| Decor_Maximize
| Decor_Close
;
1240 if (mwm_hint
->decorations
& MwmDecorBorder
)
1241 decorations
|= Decor_Border
;
1242 if (mwm_hint
->decorations
& MwmDecorHandle
)
1243 decorations
|= Decor_Handle
;
1244 if (mwm_hint
->decorations
& MwmDecorTitle
)
1245 decorations
|= Decor_Titlebar
;
1246 if (mwm_hint
->decorations
& MwmDecorIconify
)
1247 decorations
|= Decor_Iconify
;
1248 if (mwm_hint
->decorations
& MwmDecorMaximize
)
1249 decorations
|= Decor_Maximize
;
1253 if (mwm_hint
->flags
& MwmHintsFunctions
) {
1254 if (mwm_hint
->functions
& MwmFuncAll
) {
1255 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
|
1260 if (mwm_hint
->functions
& MwmFuncResize
)
1261 functions
|= Func_Resize
;
1262 if (mwm_hint
->functions
& MwmFuncMove
)
1263 functions
|= Func_Move
;
1264 if (mwm_hint
->functions
& MwmFuncIconify
)
1265 functions
|= Func_Iconify
;
1266 if (mwm_hint
->functions
& MwmFuncMaximize
)
1267 functions
|= Func_Maximize
;
1268 if (mwm_hint
->functions
& MwmFuncClose
)
1269 functions
|= Func_Close
;
1277 * Gets the blackbox hints from the class' contained window.
1278 * This is used while initializing the window to its first state, and not
1280 * Returns: true if the hints are successfully retreived and applied; false if
1283 bool BlackboxWindow::getBlackboxHints(void) {
1285 BlackboxHints
*blackbox_hint
;
1287 num
= PropBlackboxHintsElements
;
1288 if (! xatom
->getValue(client
.window
, XAtom::blackbox_hints
,
1289 XAtom::blackbox_hints
, num
,
1290 (unsigned long **)&blackbox_hint
))
1292 if (num
< PropBlackboxHintsElements
) {
1293 delete [] blackbox_hint
;
1297 if (blackbox_hint
->flags
& AttribShaded
)
1298 flags
.shaded
= (blackbox_hint
->attrib
& AttribShaded
);
1300 if ((blackbox_hint
->flags
& AttribMaxHoriz
) &&
1301 (blackbox_hint
->flags
& AttribMaxVert
))
1302 flags
.maximized
= (blackbox_hint
->attrib
&
1303 (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1304 else if (blackbox_hint
->flags
& AttribMaxVert
)
1305 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxVert
) ? 2 : 0;
1306 else if (blackbox_hint
->flags
& AttribMaxHoriz
)
1307 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1309 if (blackbox_hint
->flags
& AttribOmnipresent
)
1310 flags
.stuck
= (blackbox_hint
->attrib
& AttribOmnipresent
);
1312 if (blackbox_hint
->flags
& AttribWorkspace
)
1313 blackbox_attrib
.workspace
= blackbox_hint
->workspace
;
1315 // if (blackbox_hint->flags & AttribStack)
1316 // don't yet have always on top/bottom for blackbox yet... working
1319 if (blackbox_hint
->flags
& AttribDecoration
) {
1320 switch (blackbox_hint
->decoration
) {
1322 // clear all decorations except close
1323 decorations
&= Decor_Close
;
1324 // clear all functions except close
1325 functions
&= Func_Close
;
1330 decorations
|= Decor_Titlebar
| Decor_Iconify
;
1331 decorations
&= ~(Decor_Border
| Decor_Handle
| Decor_Maximize
);
1332 functions
|= Func_Move
| Func_Iconify
;
1333 functions
&= ~(Func_Resize
| Func_Maximize
);
1338 decorations
|= Decor_Titlebar
;
1339 decorations
&= ~(Decor_Iconify
| Decor_Border
| Decor_Handle
);
1340 functions
|= Func_Move
;
1341 functions
&= ~(Func_Resize
| Func_Maximize
| Func_Iconify
);
1347 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Handle
|
1348 Decor_Iconify
| Decor_Maximize
;
1349 functions
|= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
1357 delete [] blackbox_hint
;
1363 void BlackboxWindow::getTransientInfo(void) {
1364 if (client
.transient_for
&&
1365 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1366 // the transient for hint was removed, so we need to tell our
1367 // previous transient_for that we are going away
1368 client
.transient_for
->client
.transientList
.remove(this);
1371 // we have no transient_for until we find a new one
1372 client
.transient_for
= 0;
1375 if (! XGetTransientForHint(blackbox
->getXDisplay(), client
.window
,
1377 // transient_for hint not set
1381 if (trans_for
== client
.window
) {
1382 // wierd client... treat this window as a normal window
1386 if (trans_for
== None
|| trans_for
== screen
->getRootWindow()) {
1387 // this is an undocumented interpretation of the ICCCM. a transient
1388 // associated with None/Root/itself is assumed to be a modal root
1389 // transient. we don't support the concept of a global transient,
1390 // so we just associate this transient with nothing, and perhaps
1391 // we will add support later for global modality.
1392 client
.transient_for
= (BlackboxWindow
*) ~0ul;
1397 client
.transient_for
= blackbox
->searchWindow(trans_for
);
1398 if (! client
.transient_for
&&
1399 client
.window_group
&& trans_for
== client
.window_group
) {
1400 // no direct transient_for, perhaps this is a group transient?
1401 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1402 if (group
) client
.transient_for
= group
->find(screen
);
1405 if (! client
.transient_for
|| client
.transient_for
== this) {
1406 // no transient_for found, or we have a wierd client that wants to be
1407 // a transient for itself, so we treat this window as a normal window
1408 client
.transient_for
= (BlackboxWindow
*) 0;
1412 // register ourselves with our new transient_for
1413 client
.transient_for
->client
.transientList
.push_back(this);
1414 flags
.stuck
= client
.transient_for
->flags
.stuck
;
1418 bool BlackboxWindow::isKDESystrayWindow(void) {
1420 if (xatom
->getValue(client
.window
, XAtom::kde_net_wm_system_tray_window_for
,
1421 XAtom::window
, systray
) && systray
)
1427 BlackboxWindow
*BlackboxWindow::getTransientFor(void) const {
1428 if (client
.transient_for
&&
1429 client
.transient_for
!= (BlackboxWindow
*) ~0ul)
1430 return client
.transient_for
;
1436 * This function is responsible for updating both the client and the frame
1438 * According to the ICCCM a client message is not sent for a resize, only a
1441 void BlackboxWindow::configure(int dx
, int dy
,
1442 unsigned int dw
, unsigned int dh
) {
1443 bool send_event
= (frame
.rect
.x() != dx
|| frame
.rect
.y() != dy
);
1445 if (dw
!= frame
.rect
.width() || dh
!= frame
.rect
.height()) {
1446 frame
.rect
.setRect(dx
, dy
, dw
, dh
);
1447 frame
.inside_w
= frame
.rect
.width() - (frame
.border_w
* 2);
1448 frame
.inside_h
= frame
.rect
.height() - (frame
.border_w
* 2);
1450 if (frame
.rect
.right() <= 0 || frame
.rect
.bottom() <= 0)
1451 frame
.rect
.setPos(0, 0);
1453 client
.rect
.setCoords(frame
.rect
.left() + frame
.margin
.left
,
1454 frame
.rect
.top() + frame
.margin
.top
,
1455 frame
.rect
.right() - frame
.margin
.right
,
1456 frame
.rect
.bottom() - frame
.margin
.bottom
);
1459 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
1466 redrawWindowFrame();
1468 frame
.rect
.setPos(dx
, dy
);
1470 XMoveWindow(blackbox
->getXDisplay(), frame
.window
,
1471 frame
.rect
.x(), frame
.rect
.y());
1474 if (send_event
&& ! flags
.moving
) {
1475 // if moving, the update and event will occur when the move finishes
1476 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1477 frame
.rect
.top() + frame
.margin
.top
);
1480 event
.type
= ConfigureNotify
;
1482 event
.xconfigure
.display
= blackbox
->getXDisplay();
1483 event
.xconfigure
.event
= client
.window
;
1484 event
.xconfigure
.window
= client
.window
;
1485 event
.xconfigure
.x
= client
.rect
.x();
1486 event
.xconfigure
.y
= client
.rect
.y();
1487 event
.xconfigure
.width
= client
.rect
.width();
1488 event
.xconfigure
.height
= client
.rect
.height();
1489 event
.xconfigure
.border_width
= client
.old_bw
;
1490 event
.xconfigure
.above
= frame
.window
;
1491 event
.xconfigure
.override_redirect
= False
;
1493 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1494 StructureNotifyMask
, &event
);
1495 screen
->updateNetizenConfigNotify(&event
);
1501 void BlackboxWindow::configureShape(void) {
1502 XShapeCombineShape(blackbox
->getXDisplay(), frame
.window
, ShapeBounding
,
1503 frame
.margin
.left
- frame
.border_w
,
1504 frame
.margin
.top
- frame
.border_w
,
1505 client
.window
, ShapeBounding
, ShapeSet
);
1508 XRectangle xrect
[2];
1510 if (decorations
& Decor_Titlebar
) {
1511 xrect
[0].x
= xrect
[0].y
= -frame
.border_w
;
1512 xrect
[0].width
= frame
.rect
.width();
1513 xrect
[0].height
= frame
.title_h
+ (frame
.border_w
* 2);
1517 if (decorations
& Decor_Handle
) {
1518 xrect
[1].x
= -frame
.border_w
;
1519 xrect
[1].y
= frame
.rect
.height() - frame
.margin
.bottom
+
1520 frame
.mwm_border_w
- frame
.border_w
;
1521 xrect
[1].width
= frame
.rect
.width();
1522 xrect
[1].height
= frame
.handle_h
+ (frame
.border_w
* 2);
1526 XShapeCombineRectangles(blackbox
->getXDisplay(), frame
.window
,
1527 ShapeBounding
, 0, 0, xrect
, num
,
1528 ShapeUnion
, Unsorted
);
1533 bool BlackboxWindow::setInputFocus(void) {
1534 if (flags
.focused
) return True
;
1536 assert(! flags
.iconic
&&
1537 (flags
.stuck
|| // window must be on the current workspace or sticky
1538 blackbox_attrib
.workspace
== screen
->getCurrentWorkspaceID()));
1540 // if the window is not visible, mark the window as wanting focus rather
1541 // than give it focus.
1542 if (! flags
.visible
) {
1543 Workspace
*wkspc
= screen
->getWorkspace(blackbox_attrib
.workspace
);
1544 wkspc
->setLastFocusedWindow(this);
1548 if (! frame
.rect
.intersects(screen
->getRect())) {
1549 // client is outside the screen, move it to the center
1550 configure((screen
->getWidth() - frame
.rect
.width()) / 2,
1551 (screen
->getHeight() - frame
.rect
.height()) / 2,
1552 frame
.rect
.width(), frame
.rect
.height());
1555 if (client
.transientList
.size() > 0) {
1556 // transfer focus to any modal transients
1557 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1558 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1559 if ((*it
)->flags
.modal
) return (*it
)->setInputFocus();
1564 if (focus_mode
== F_LocallyActive
|| focus_mode
== F_Passive
) {
1565 XSetInputFocus(blackbox
->getXDisplay(), client
.window
,
1566 RevertToPointerRoot
, CurrentTime
);
1568 blackbox
->setFocusedWindow(this);
1570 /* we could set the focus to none, since the window doesn't accept focus,
1571 * but we shouldn't set focus to nothing since this would surely make
1577 if (flags
.send_focus_message
) {
1579 ce
.xclient
.type
= ClientMessage
;
1580 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1581 ce
.xclient
.display
= blackbox
->getXDisplay();
1582 ce
.xclient
.window
= client
.window
;
1583 ce
.xclient
.format
= 32;
1584 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_take_focus
);
1585 ce
.xclient
.data
.l
[1] = blackbox
->getLastTime();
1586 ce
.xclient
.data
.l
[2] = 0l;
1587 ce
.xclient
.data
.l
[3] = 0l;
1588 ce
.xclient
.data
.l
[4] = 0l;
1589 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1597 void BlackboxWindow::iconify(void) {
1598 if (flags
.iconic
) return;
1600 // We don't need to worry about resizing because resizing always grabs the X
1601 // server. This should only ever happen if using opaque moving.
1605 if (windowmenu
) windowmenu
->hide();
1608 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1609 * we need to clear the event mask on client.window for a split second.
1610 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1611 * split second, leaving us with a ghost window... so, we need to do this
1612 * while the X server is grabbed
1614 XGrabServer(blackbox
->getXDisplay());
1615 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
1616 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1617 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1618 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
1619 XUngrabServer(blackbox
->getXDisplay());
1621 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1622 flags
.visible
= False
;
1623 flags
.iconic
= True
;
1625 setState(IconicState
);
1627 screen
->getWorkspace(blackbox_attrib
.workspace
)->removeWindow(this);
1629 if (isTransient()) {
1630 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1631 ! client
.transient_for
->flags
.iconic
) {
1632 // iconify our transient_for
1633 client
.transient_for
->iconify();
1637 screen
->addIcon(this);
1639 if (client
.transientList
.size() > 0) {
1640 // iconify all transients
1641 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1642 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1643 if (! (*it
)->flags
.iconic
) (*it
)->iconify();
1649 void BlackboxWindow::show(void) {
1650 flags
.visible
= True
;
1651 flags
.iconic
= False
;
1653 current_state
= (flags
.shaded
) ? IconicState
: NormalState
;
1654 setState(current_state
);
1656 XMapWindow(blackbox
->getXDisplay(), client
.window
);
1657 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
1658 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
1663 XTranslateCoordinates(blackbox
->getXDisplay(), client
.window
,
1664 screen
->getRootWindow(),
1665 0, 0, &real_x
, &real_y
, &child
);
1666 fprintf(stderr
, "%s -- assumed: (%d, %d), real: (%d, %d)\n", getTitle(),
1667 client
.rect
.left(), client
.rect
.top(), real_x
, real_y
);
1668 assert(client
.rect
.left() == real_x
&& client
.rect
.top() == real_y
);
1673 void BlackboxWindow::deiconify(bool reassoc
, bool raise
) {
1674 if (flags
.iconic
|| reassoc
)
1675 screen
->reassociateWindow(this, BSENTINEL
, False
);
1676 else if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID())
1681 // reassociate and deiconify all transients
1682 if (reassoc
&& client
.transientList
.size() > 0) {
1683 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1684 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1685 (*it
)->deiconify(True
, False
);
1690 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1694 void BlackboxWindow::close(void) {
1696 ce
.xclient
.type
= ClientMessage
;
1697 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1698 ce
.xclient
.display
= blackbox
->getXDisplay();
1699 ce
.xclient
.window
= client
.window
;
1700 ce
.xclient
.format
= 32;
1701 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_delete_window
);
1702 ce
.xclient
.data
.l
[1] = CurrentTime
;
1703 ce
.xclient
.data
.l
[2] = 0l;
1704 ce
.xclient
.data
.l
[3] = 0l;
1705 ce
.xclient
.data
.l
[4] = 0l;
1706 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
, NoEventMask
, &ce
);
1710 void BlackboxWindow::withdraw(void) {
1711 // We don't need to worry about resizing because resizing always grabs the X
1712 // server. This should only ever happen if using opaque moving.
1716 flags
.visible
= False
;
1717 flags
.iconic
= False
;
1719 setState(current_state
);
1721 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1723 XGrabServer(blackbox
->getXDisplay());
1725 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
1726 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1727 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1728 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
1730 XUngrabServer(blackbox
->getXDisplay());
1732 if (windowmenu
) windowmenu
->hide();
1736 void BlackboxWindow::maximize(unsigned int button
) {
1737 // We don't need to worry about resizing because resizing always grabs the X
1738 // server. This should only ever happen if using opaque moving.
1742 // handle case where menu is open then the max button is used instead
1743 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
1745 if (flags
.maximized
) {
1746 flags
.maximized
= 0;
1748 blackbox_attrib
.flags
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1749 blackbox_attrib
.attrib
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1752 when a resize finishes, maximize(0) is called to clear any maximization
1753 flags currently set. Otherwise it still thinks it is maximized.
1754 so we do not need to call configure() because resizing will handle it
1756 if (! flags
.resizing
)
1757 configure(blackbox_attrib
.premax_x
, blackbox_attrib
.premax_y
,
1758 blackbox_attrib
.premax_w
, blackbox_attrib
.premax_h
);
1760 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
1761 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
1763 redrawAllButtons(); // in case it is not called in configure()
1764 setState(current_state
);
1768 blackbox_attrib
.premax_x
= frame
.rect
.x();
1769 blackbox_attrib
.premax_y
= frame
.rect
.y();
1770 blackbox_attrib
.premax_w
= frame
.rect
.width();
1771 // use client.rect so that clients can be restored even if shaded
1772 blackbox_attrib
.premax_h
=
1773 client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
;
1775 const Rect
&screen_area
= screen
->availableArea();
1776 frame
.changing
= screen_area
;
1780 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1781 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1785 blackbox_attrib
.flags
|= AttribMaxVert
;
1786 blackbox_attrib
.attrib
|= AttribMaxVert
;
1788 frame
.changing
.setX(frame
.rect
.x());
1789 frame
.changing
.setWidth(frame
.rect
.width());
1793 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1794 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1796 frame
.changing
.setY(frame
.rect
.y());
1797 frame
.changing
.setHeight(frame
.rect
.height());
1804 blackbox_attrib
.flags
^= AttribShaded
;
1805 blackbox_attrib
.attrib
^= AttribShaded
;
1806 flags
.shaded
= False
;
1809 flags
.maximized
= button
;
1811 configure(frame
.changing
.x(), frame
.changing
.y(),
1812 frame
.changing
.width(), frame
.changing
.height());
1814 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1815 redrawAllButtons(); // in case it is not called in configure()
1816 setState(current_state
);
1820 // re-maximizes the window to take into account availableArea changes
1821 void BlackboxWindow::remaximize(void) {
1822 // save the original dimensions because maximize will wipe them out
1823 int premax_x
= blackbox_attrib
.premax_x
,
1824 premax_y
= blackbox_attrib
.premax_y
,
1825 premax_w
= blackbox_attrib
.premax_w
,
1826 premax_h
= blackbox_attrib
.premax_h
;
1828 unsigned int button
= flags
.maximized
;
1829 flags
.maximized
= 0; // trick maximize() into working
1832 // restore saved values
1833 blackbox_attrib
.premax_x
= premax_x
;
1834 blackbox_attrib
.premax_y
= premax_y
;
1835 blackbox_attrib
.premax_w
= premax_w
;
1836 blackbox_attrib
.premax_h
= premax_h
;
1840 void BlackboxWindow::setWorkspace(unsigned int n
) {
1841 blackbox_attrib
.flags
|= AttribWorkspace
;
1842 blackbox_attrib
.workspace
= n
;
1843 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
, n
);
1847 void BlackboxWindow::shade(void) {
1849 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1850 frame
.inside_w
, frame
.inside_h
);
1851 flags
.shaded
= False
;
1852 blackbox_attrib
.flags
^= AttribShaded
;
1853 blackbox_attrib
.attrib
^= AttribShaded
;
1855 setState(NormalState
);
1857 // set the frame rect to the normal size
1858 frame
.rect
.setHeight(client
.rect
.height() + frame
.margin
.top
+
1859 frame
.margin
.bottom
);
1861 if (! (decorations
& Decor_Titlebar
))
1862 return; // can't shade it without a titlebar!
1864 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1865 frame
.inside_w
, frame
.title_h
);
1866 flags
.shaded
= True
;
1867 blackbox_attrib
.flags
|= AttribShaded
;
1868 blackbox_attrib
.attrib
|= AttribShaded
;
1870 setState(IconicState
);
1872 // set the frame rect to the shaded size
1873 frame
.rect
.setHeight(frame
.title_h
+ (frame
.border_w
* 2));
1879 * (Un)Sticks a window and its relatives.
1881 void BlackboxWindow::stick(void) {
1883 blackbox_attrib
.flags
^= AttribOmnipresent
;
1884 blackbox_attrib
.attrib
^= AttribOmnipresent
;
1886 flags
.stuck
= False
;
1889 screen
->reassociateWindow(this, BSENTINEL
, True
);
1891 // temporary fix since sticky windows suck. set the hint to what we
1892 // actually hold in our data.
1893 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1894 blackbox_attrib
.workspace
);
1896 setState(current_state
);
1900 blackbox_attrib
.flags
|= AttribOmnipresent
;
1901 blackbox_attrib
.attrib
|= AttribOmnipresent
;
1903 // temporary fix since sticky windows suck. set the hint to a different
1904 // value than that contained in the class' data.
1905 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1908 setState(current_state
);
1911 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1912 client
.transient_for
->isStuck() != flags
.stuck
)
1913 client
.transient_for
->stick();
1914 // go down the chain
1915 BlackboxWindowList::iterator it
;
1916 const BlackboxWindowList::iterator end
= client
.transientList
.end();
1917 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1918 if ((*it
)->isStuck() != flags
.stuck
)
1923 void BlackboxWindow::redrawWindowFrame(void) const {
1924 if (decorations
& Decor_Titlebar
) {
1925 if (flags
.focused
) {
1927 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1928 frame
.title
, frame
.ftitle
);
1930 XSetWindowBackground(blackbox
->getXDisplay(),
1931 frame
.title
, frame
.ftitle_pixel
);
1934 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1935 frame
.title
, frame
.utitle
);
1937 XSetWindowBackground(blackbox
->getXDisplay(),
1938 frame
.title
, frame
.utitle_pixel
);
1940 XClearWindow(blackbox
->getXDisplay(), frame
.title
);
1946 if (decorations
& Decor_Handle
) {
1947 if (flags
.focused
) {
1949 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1950 frame
.handle
, frame
.fhandle
);
1952 XSetWindowBackground(blackbox
->getXDisplay(),
1953 frame
.handle
, frame
.fhandle_pixel
);
1956 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1957 frame
.left_grip
, frame
.fgrip
);
1958 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1959 frame
.right_grip
, frame
.fgrip
);
1961 XSetWindowBackground(blackbox
->getXDisplay(),
1962 frame
.left_grip
, frame
.fgrip_pixel
);
1963 XSetWindowBackground(blackbox
->getXDisplay(),
1964 frame
.right_grip
, frame
.fgrip_pixel
);
1968 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1969 frame
.handle
, frame
.uhandle
);
1971 XSetWindowBackground(blackbox
->getXDisplay(),
1972 frame
.handle
, frame
.uhandle_pixel
);
1975 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1976 frame
.left_grip
, frame
.ugrip
);
1977 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1978 frame
.right_grip
, frame
.ugrip
);
1980 XSetWindowBackground(blackbox
->getXDisplay(),
1981 frame
.left_grip
, frame
.ugrip_pixel
);
1982 XSetWindowBackground(blackbox
->getXDisplay(),
1983 frame
.right_grip
, frame
.ugrip_pixel
);
1986 XClearWindow(blackbox
->getXDisplay(), frame
.handle
);
1987 XClearWindow(blackbox
->getXDisplay(), frame
.left_grip
);
1988 XClearWindow(blackbox
->getXDisplay(), frame
.right_grip
);
1991 if (decorations
& Decor_Border
) {
1993 XSetWindowBorder(blackbox
->getXDisplay(),
1994 frame
.plate
, frame
.fborder_pixel
);
1996 XSetWindowBorder(blackbox
->getXDisplay(),
1997 frame
.plate
, frame
.uborder_pixel
);
2002 void BlackboxWindow::setFocusFlag(bool focus
) {
2003 // only focus a window if it is visible
2004 if (focus
&& !flags
.visible
)
2007 flags
.focused
= focus
;
2009 redrawWindowFrame();
2011 if (screen
->isSloppyFocus() && screen
->doAutoRaise()) {
2012 if (isFocused()) timer
->start();
2017 blackbox
->setFocusedWindow(this);
2021 void BlackboxWindow::installColormap(bool install
) {
2022 int i
= 0, ncmap
= 0;
2023 Colormap
*cmaps
= XListInstalledColormaps(blackbox
->getXDisplay(),
2024 client
.window
, &ncmap
);
2026 XWindowAttributes wattrib
;
2027 if (XGetWindowAttributes(blackbox
->getXDisplay(),
2028 client
.window
, &wattrib
)) {
2030 // install the window's colormap
2031 for (i
= 0; i
< ncmap
; i
++) {
2032 if (*(cmaps
+ i
) == wattrib
.colormap
)
2033 // this window is using an installed color map... do not install
2036 // otherwise, install the window's colormap
2038 XInstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2040 // uninstall the window's colormap
2041 for (i
= 0; i
< ncmap
; i
++) {
2042 if (*(cmaps
+ i
) == wattrib
.colormap
)
2043 // we found the colormap to uninstall
2044 XUninstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2054 void BlackboxWindow::setAllowedActions(void) {
2058 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_shade
);
2059 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_change_desktop
);
2060 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_close
);
2062 if (functions
& Func_Move
)
2063 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_move
);
2064 if (functions
& Func_Resize
)
2065 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_resize
);
2066 if (functions
& Func_Maximize
) {
2067 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_horz
);
2068 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_vert
);
2071 xatom
->setValue(client
.window
, XAtom::net_wm_allowed_actions
, XAtom::atom
,
2076 void BlackboxWindow::setState(unsigned long new_state
) {
2077 current_state
= new_state
;
2079 unsigned long state
[2];
2080 state
[0] = current_state
;
2082 xatom
->setValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
, state
, 2);
2084 xatom
->setValue(client
.window
, XAtom::blackbox_attributes
,
2085 XAtom::blackbox_attributes
, (unsigned long *)&blackbox_attrib
,
2086 PropBlackboxAttributesElements
);
2091 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_modal
);
2093 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_shaded
);
2095 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_hidden
);
2096 if (flags
.skip_taskbar
)
2097 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
);
2098 if (flags
.skip_pager
)
2099 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_pager
);
2100 if (flags
.fullscreen
)
2101 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_fullscreen
);
2102 if (flags
.maximized
== 1 || flags
.maximized
== 2)
2103 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_vert
);
2104 if (flags
.maximized
== 1 || flags
.maximized
== 3)
2105 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_horz
);
2106 xatom
->setValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
2111 bool BlackboxWindow::getState(void) {
2112 bool ret
= xatom
->getValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
,
2114 if (! ret
) current_state
= 0;
2119 void BlackboxWindow::restoreAttributes(void) {
2120 unsigned long num
= PropBlackboxAttributesElements
;
2121 BlackboxAttributes
*net
;
2122 if (! xatom
->getValue(client
.window
, XAtom::blackbox_attributes
,
2123 XAtom::blackbox_attributes
, num
,
2124 (unsigned long **)&net
))
2126 if (num
< PropBlackboxAttributesElements
) {
2131 if (net
->flags
& AttribShaded
&& net
->attrib
& AttribShaded
) {
2132 flags
.shaded
= False
;
2133 unsigned long orig_state
= current_state
;
2137 At this point in the life of a window, current_state should only be set
2138 to IconicState if the window was an *icon*, not if it was shaded.
2140 if (orig_state
!= IconicState
)
2141 current_state
= WithdrawnState
;
2144 if (net
->workspace
!= screen
->getCurrentWorkspaceID() &&
2145 net
->workspace
< screen
->getWorkspaceCount())
2146 screen
->reassociateWindow(this, net
->workspace
, True
);
2148 if ((blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID()) &&
2149 (blackbox_attrib
.workspace
< screen
->getWorkspaceCount())) {
2150 // set to WithdrawnState so it will be mapped on the new workspace
2151 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2152 } else if (current_state
== WithdrawnState
) {
2153 // the window is on this workspace and is Withdrawn, so it is waiting to
2155 current_state
= NormalState
;
2158 if (net
->flags
& AttribOmnipresent
&& net
->attrib
& AttribOmnipresent
) {
2159 flags
.stuck
= False
;
2162 // if the window was on another workspace, it was going to be hidden. this
2163 // specifies that the window should be mapped since it is sticky.
2164 if (current_state
== WithdrawnState
) current_state
= NormalState
;
2167 if (net
->flags
& AttribMaxHoriz
|| net
->flags
& AttribMaxVert
) {
2168 int x
= net
->premax_x
, y
= net
->premax_y
;
2169 unsigned int w
= net
->premax_w
, h
= net
->premax_h
;
2170 flags
.maximized
= 0;
2173 if ((net
->flags
& AttribMaxHoriz
) &&
2174 (net
->flags
& AttribMaxVert
))
2175 m
= (net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
2176 else if (net
->flags
& AttribMaxVert
)
2177 m
= (net
->attrib
& AttribMaxVert
) ? 2 : 0;
2178 else if (net
->flags
& AttribMaxHoriz
)
2179 m
= (net
->attrib
& AttribMaxHoriz
) ? 3 : 0;
2183 blackbox_attrib
.premax_x
= x
;
2184 blackbox_attrib
.premax_y
= y
;
2185 blackbox_attrib
.premax_w
= w
;
2186 blackbox_attrib
.premax_h
= h
;
2189 // with the state set it will then be the map event's job to read the
2190 // window's state and behave accordingly
2197 * Positions the Rect r according the the client window position and
2200 void BlackboxWindow::applyGravity(Rect
&r
) {
2201 // apply horizontal window gravity
2202 switch (client
.win_gravity
) {
2204 case NorthWestGravity
:
2205 case SouthWestGravity
:
2207 r
.setX(client
.rect
.x());
2213 r
.setX(client
.rect
.x() - (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2216 case NorthEastGravity
:
2217 case SouthEastGravity
:
2219 r
.setX(client
.rect
.x() - frame
.margin
.left
- frame
.margin
.right
);
2224 r
.setX(client
.rect
.x() - frame
.margin
.left
);
2228 // apply vertical window gravity
2229 switch (client
.win_gravity
) {
2231 case NorthWestGravity
:
2232 case NorthEastGravity
:
2234 r
.setY(client
.rect
.y());
2240 r
.setY(client
.rect
.y() - (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2243 case SouthWestGravity
:
2244 case SouthEastGravity
:
2246 r
.setY(client
.rect
.y() - frame
.margin
.top
- frame
.margin
.bottom
);
2251 r
.setY(client
.rect
.y() - frame
.margin
.top
);
2258 * The reverse of the applyGravity function.
2260 * Positions the Rect r according to the frame window position and
2263 void BlackboxWindow::restoreGravity(Rect
&r
) {
2264 // restore horizontal window gravity
2265 switch (client
.win_gravity
) {
2267 case NorthWestGravity
:
2268 case SouthWestGravity
:
2270 r
.setX(frame
.rect
.x());
2276 r
.setX(frame
.rect
.x() + (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2279 case NorthEastGravity
:
2280 case SouthEastGravity
:
2282 r
.setX(frame
.rect
.x() + frame
.margin
.left
+ frame
.margin
.right
);
2287 r
.setX(frame
.rect
.x() + frame
.margin
.left
);
2291 // restore vertical window gravity
2292 switch (client
.win_gravity
) {
2294 case NorthWestGravity
:
2295 case NorthEastGravity
:
2297 r
.setY(frame
.rect
.y());
2303 r
.setY(frame
.rect
.y() + (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2306 case SouthWestGravity
:
2307 case SouthEastGravity
:
2309 r
.setY(frame
.rect
.y() + frame
.margin
.top
+ frame
.margin
.bottom
);
2314 r
.setY(frame
.rect
.y() + frame
.margin
.top
);
2320 void BlackboxWindow::redrawLabel(void) const {
2321 if (flags
.focused
) {
2323 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2324 frame
.label
, frame
.flabel
);
2326 XSetWindowBackground(blackbox
->getXDisplay(),
2327 frame
.label
, frame
.flabel_pixel
);
2330 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2331 frame
.label
, frame
.ulabel
);
2333 XSetWindowBackground(blackbox
->getXDisplay(),
2334 frame
.label
, frame
.ulabel_pixel
);
2336 XClearWindow(blackbox
->getXDisplay(), frame
.label
);
2338 WindowStyle
*style
= screen
->getWindowStyle();
2340 int pos
= frame
.bevel_w
* 2;
2341 style
->doJustify(client
.title
.c_str(), pos
, frame
.label_w
, frame
.bevel_w
* 4);
2342 style
->font
->drawString(frame
.label
, pos
, 1,
2343 (flags
.focused
? style
->l_text_focus
:
2344 style
->l_text_unfocus
),
2349 void BlackboxWindow::redrawAllButtons(void) const {
2350 if (frame
.iconify_button
) redrawIconifyButton(False
);
2351 if (frame
.maximize_button
) redrawMaximizeButton(flags
.maximized
);
2352 if (frame
.close_button
) redrawCloseButton(False
);
2356 void BlackboxWindow::redrawIconifyButton(bool pressed
) const {
2358 if (flags
.focused
) {
2360 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2361 frame
.iconify_button
, frame
.fbutton
);
2363 XSetWindowBackground(blackbox
->getXDisplay(),
2364 frame
.iconify_button
, frame
.fbutton_pixel
);
2367 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2368 frame
.iconify_button
, frame
.ubutton
);
2370 XSetWindowBackground(blackbox
->getXDisplay(), frame
.iconify_button
,
2371 frame
.ubutton_pixel
);
2375 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2376 frame
.iconify_button
, frame
.pbutton
);
2378 XSetWindowBackground(blackbox
->getXDisplay(),
2379 frame
.iconify_button
, frame
.pbutton_pixel
);
2381 XClearWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
2383 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2384 screen
->getWindowStyle()->b_pic_unfocus
);
2385 XDrawRectangle(blackbox
->getXDisplay(), frame
.iconify_button
, pen
.gc(),
2386 2, (frame
.button_w
- 5), (frame
.button_w
- 5), 2);
2390 void BlackboxWindow::redrawMaximizeButton(bool pressed
) const {
2392 if (flags
.focused
) {
2394 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2395 frame
.maximize_button
, frame
.fbutton
);
2397 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2398 frame
.fbutton_pixel
);
2401 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2402 frame
.maximize_button
, frame
.ubutton
);
2404 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2405 frame
.ubutton_pixel
);
2409 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2410 frame
.maximize_button
, frame
.pbutton
);
2412 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2413 frame
.pbutton_pixel
);
2415 XClearWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
2417 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2418 screen
->getWindowStyle()->b_pic_unfocus
);
2419 XDrawRectangle(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2420 2, 2, (frame
.button_w
- 5), (frame
.button_w
- 5));
2421 XDrawLine(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2422 2, 3, (frame
.button_w
- 3), 3);
2426 void BlackboxWindow::redrawCloseButton(bool pressed
) const {
2428 if (flags
.focused
) {
2430 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2433 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2434 frame
.fbutton_pixel
);
2437 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2440 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2441 frame
.ubutton_pixel
);
2445 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2446 frame
.close_button
, frame
.pbutton
);
2448 XSetWindowBackground(blackbox
->getXDisplay(),
2449 frame
.close_button
, frame
.pbutton_pixel
);
2451 XClearWindow(blackbox
->getXDisplay(), frame
.close_button
);
2453 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2454 screen
->getWindowStyle()->b_pic_unfocus
);
2455 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2456 2, 2, (frame
.button_w
- 3), (frame
.button_w
- 3));
2457 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2458 2, (frame
.button_w
- 3), (frame
.button_w
- 3), 2);
2462 void BlackboxWindow::mapRequestEvent(const XMapRequestEvent
*re
) {
2463 if (re
->window
!= client
.window
)
2467 fprintf(stderr
, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2471 switch (current_state
) {
2476 case WithdrawnState
:
2485 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2486 if (! blackbox
->isStartup() && (isTransient() || screen
->doFocusNew())) {
2487 XSync(blackbox
->getXDisplay(), False
); // make sure the frame is mapped..
2495 void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent
*ue
) {
2496 if (ue
->window
!= client
.window
)
2500 fprintf(stderr
, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2504 screen
->unmanageWindow(this, False
);
2508 void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent
*de
) {
2509 if (de
->window
!= client
.window
)
2513 fprintf(stderr
, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2517 screen
->unmanageWindow(this, False
);
2521 void BlackboxWindow::reparentNotifyEvent(const XReparentEvent
*re
) {
2522 if (re
->window
!= client
.window
|| re
->parent
== frame
.plate
)
2526 fprintf(stderr
, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2527 "0x%lx.\n", client
.window
, re
->parent
);
2532 XPutBackEvent(blackbox
->getXDisplay(), &ev
);
2533 screen
->unmanageWindow(this, True
);
2537 void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent
*pe
) {
2538 if (pe
->state
== PropertyDelete
)
2542 fprintf(stderr
, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n",
2548 case XA_WM_CLIENT_MACHINE
:
2552 case XA_WM_TRANSIENT_FOR
: {
2553 // determine if this is a transient window
2556 // adjust the window decorations based on transience
2557 if (isTransient()) {
2558 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2559 functions
&= ~Func_Maximize
;
2560 setAllowedActions();
2571 case XA_WM_ICON_NAME
:
2573 if (flags
.iconic
) screen
->propagateWindowName(this);
2576 case XAtom::net_wm_name
:
2580 if (decorations
& Decor_Titlebar
)
2583 screen
->propagateWindowName(this);
2586 case XA_WM_NORMAL_HINTS
: {
2589 if ((client
.normal_hint_flags
& PMinSize
) &&
2590 (client
.normal_hint_flags
& PMaxSize
)) {
2591 // the window now can/can't resize itself, so the buttons need to be
2594 if (client
.max_width
<= client
.min_width
&&
2595 client
.max_height
<= client
.min_height
) {
2596 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2597 functions
&= ~(Func_Resize
| Func_Maximize
);
2599 decorations
|= Decor_Maximize
| Decor_Handle
;
2600 functions
|= Func_Resize
| Func_Maximize
;
2603 setAllowedActions();
2606 Rect old_rect
= frame
.rect
;
2610 if (old_rect
!= frame
.rect
)
2617 if (pe
->atom
== xatom
->getAtom(XAtom::wm_protocols
)) {
2620 if ((decorations
& Decor_Close
) && (! frame
.close_button
)) {
2621 createCloseButton();
2622 if (decorations
& Decor_Titlebar
) {
2623 positionButtons(True
);
2624 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
2626 if (windowmenu
) windowmenu
->reconfigure();
2628 } else if (pe
->atom
== xatom
->getAtom(XAtom::net_wm_strut
)) {
2637 void BlackboxWindow::exposeEvent(const XExposeEvent
*ee
) {
2639 fprintf(stderr
, "BlackboxWindow::exposeEvent() for 0x%lx\n", client
.window
);
2642 if (frame
.label
== ee
->window
&& (decorations
& Decor_Titlebar
))
2644 else if (frame
.close_button
== ee
->window
)
2645 redrawCloseButton(False
);
2646 else if (frame
.maximize_button
== ee
->window
)
2647 redrawMaximizeButton(flags
.maximized
);
2648 else if (frame
.iconify_button
== ee
->window
)
2649 redrawIconifyButton(False
);
2653 void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent
*cr
) {
2654 if (cr
->window
!= client
.window
|| flags
.iconic
)
2657 if (cr
->value_mask
& CWBorderWidth
)
2658 client
.old_bw
= cr
->border_width
;
2660 if (cr
->value_mask
& (CWX
| CWY
| CWWidth
| CWHeight
)) {
2661 Rect req
= frame
.rect
;
2663 if (cr
->value_mask
& (CWX
| CWY
)) {
2664 if (cr
->value_mask
& CWX
)
2665 client
.rect
.setX(cr
->x
);
2666 if (cr
->value_mask
& CWY
)
2667 client
.rect
.setY(cr
->y
);
2672 if (cr
->value_mask
& CWWidth
)
2673 req
.setWidth(cr
->width
+ frame
.margin
.left
+ frame
.margin
.right
);
2675 if (cr
->value_mask
& CWHeight
)
2676 req
.setHeight(cr
->height
+ frame
.margin
.top
+ frame
.margin
.bottom
);
2678 configure(req
.x(), req
.y(), req
.width(), req
.height());
2681 if (cr
->value_mask
& CWStackMode
) {
2682 switch (cr
->detail
) {
2685 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2691 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2698 void BlackboxWindow::buttonPressEvent(const XButtonEvent
*be
) {
2700 fprintf(stderr
, "BlackboxWindow::buttonPressEvent() for 0x%lx\n",
2704 if (frame
.maximize_button
== be
->window
) {
2705 redrawMaximizeButton(True
);
2706 } else if (be
->button
== 1 || (be
->button
== 3 && be
->state
== Mod1Mask
)) {
2707 if (! flags
.focused
)
2710 if (frame
.iconify_button
== be
->window
) {
2711 redrawIconifyButton(True
);
2712 } else if (frame
.close_button
== be
->window
) {
2713 redrawCloseButton(True
);
2714 } else if (frame
.plate
== be
->window
) {
2715 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2717 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2719 XAllowEvents(blackbox
->getXDisplay(), ReplayPointer
, be
->time
);
2721 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
2722 if (((be
->time
- lastButtonPressTime
) <=
2723 blackbox
->getDoubleClickInterval()) ||
2724 (be
->state
& ControlMask
)) {
2725 lastButtonPressTime
= 0;
2728 lastButtonPressTime
= be
->time
;
2732 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2734 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2736 } else if (be
->button
== 2 && (be
->window
!= frame
.iconify_button
) &&
2737 (be
->window
!= frame
.close_button
)) {
2738 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2739 } else if (windowmenu
&& be
->button
== 3 &&
2740 (frame
.title
== be
->window
|| frame
.label
== be
->window
||
2741 frame
.handle
== be
->window
|| frame
.window
== be
->window
)) {
2742 if (windowmenu
->isVisible()) {
2745 int mx
= be
->x_root
- windowmenu
->getWidth() / 2,
2746 my
= be
->y_root
- windowmenu
->getHeight() / 2;
2748 // snap the window menu into a corner/side if necessary
2749 int left_edge
, right_edge
, top_edge
, bottom_edge
;
2752 the " + (frame.border_w * 2) - 1" bits are to get the proper width
2753 and height of the menu, as the sizes returned by it do not include
2756 left_edge
= frame
.rect
.x();
2757 right_edge
= frame
.rect
.right() -
2758 (windowmenu
->getWidth() + (frame
.border_w
* 2) - 1);
2759 top_edge
= client
.rect
.top() - (frame
.border_w
+ frame
.mwm_border_w
);
2760 bottom_edge
= client
.rect
.bottom() -
2761 (windowmenu
->getHeight() + (frame
.border_w
* 2) - 1) +
2762 (frame
.border_w
+ frame
.mwm_border_w
);
2766 if (mx
> right_edge
)
2770 if (my
> bottom_edge
)
2773 windowmenu
->move(mx
, my
);
2775 XRaiseWindow(blackbox
->getXDisplay(), windowmenu
->getWindowID());
2776 XRaiseWindow(blackbox
->getXDisplay(),
2777 windowmenu
->getSendToMenu()->getWindowID());
2780 } else if (be
->button
== 4) {
2781 if ((be
->window
== frame
.label
||
2782 be
->window
== frame
.title
) &&
2786 } else if (be
->button
== 5) {
2787 if ((be
->window
== frame
.label
||
2788 be
->window
== frame
.title
) &&
2795 void BlackboxWindow::buttonReleaseEvent(const XButtonEvent
*re
) {
2797 fprintf(stderr
, "BlackboxWindow::buttonReleaseEvent() for 0x%lx\n",
2801 if (re
->window
== frame
.maximize_button
) {
2802 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2803 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2804 maximize(re
->button
);
2806 redrawMaximizeButton(flags
.maximized
);
2808 } else if (re
->window
== frame
.iconify_button
) {
2809 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2810 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2813 redrawIconifyButton(False
);
2815 } else if (re
->window
== frame
.close_button
) {
2816 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2817 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
)))
2819 redrawCloseButton(False
);
2820 } else if (flags
.moving
) {
2822 } else if (flags
.resizing
) {
2829 void BlackboxWindow::beginMove(int x_root
, int y_root
) {
2830 assert(! (flags
.resizing
|| flags
.moving
));
2833 Only one window can be moved/resized at a time. If another window is already
2834 being moved or resized, then stop it before whating to work with this one.
2836 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
2837 if (changing
&& changing
!= this) {
2838 if (changing
->flags
.moving
)
2839 changing
->endMove();
2840 else // if (changing->flags.resizing)
2841 changing
->endResize();
2844 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
2845 PointerMotionMask
| ButtonReleaseMask
,
2846 GrabModeAsync
, GrabModeAsync
,
2847 None
, blackbox
->getMoveCursor(), CurrentTime
);
2849 if (windowmenu
&& windowmenu
->isVisible())
2852 flags
.moving
= True
;
2853 blackbox
->setChangingWindow(this);
2855 if (! screen
->doOpaqueMove()) {
2856 XGrabServer(blackbox
->getXDisplay());
2858 frame
.changing
= frame
.rect
;
2859 screen
->showPosition(frame
.changing
.x(), frame
.changing
.y());
2861 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2865 frame
.changing
.width() - 1,
2866 frame
.changing
.height() - 1);
2869 frame
.grab_x
= x_root
- frame
.rect
.x() - frame
.border_w
;
2870 frame
.grab_y
= y_root
- frame
.rect
.y() - frame
.border_w
;
2874 void BlackboxWindow::doMove(int x_root
, int y_root
) {
2875 assert(flags
.moving
);
2876 assert(blackbox
->getChangingWindow() == this);
2878 int dx
= x_root
- frame
.grab_x
, dy
= y_root
- frame
.grab_y
;
2879 dx
-= frame
.border_w
;
2880 dy
-= frame
.border_w
;
2882 const int snap_distance
= screen
->getEdgeSnapThreshold();
2884 if (snap_distance
) {
2886 const int wleft
= dx
,
2887 wright
= dx
+ frame
.rect
.width() - 1,
2889 wbottom
= dy
+ frame
.rect
.height() - 1;
2891 if (screen
->getWindowToWindowSnap()) {
2892 Workspace
*w
= screen
->getWorkspace(getWorkspaceNumber());
2895 // try snap to another window
2896 for (unsigned int i
= 0, c
= w
->getCount(); i
< c
; ++i
) {
2897 BlackboxWindow
*snapwin
= w
->getWindow(i
);
2898 if (snapwin
== this)
2899 continue; // don't snap to self
2901 bool snapped
= False
;
2903 const Rect
&winrect
= snapwin
->frameRect();
2904 int dleft
= std::abs(wright
- winrect
.left()),
2905 dright
= std::abs(wleft
- winrect
.right()),
2906 dtop
= std::abs(wbottom
- winrect
.top()),
2907 dbottom
= std::abs(wtop
- winrect
.bottom());
2909 if (wtop
>= (signed)(winrect
.y() - frame
.rect
.height() + 1) &&
2910 wtop
< (signed)(winrect
.y() + winrect
.height() - 1)) {
2912 // snap left of other window?
2913 if (dleft
< snap_distance
&& dleft
<= dright
) {
2914 dx
= winrect
.left() - frame
.rect
.width();
2917 // snap right of other window?
2918 else if (dright
< snap_distance
) {
2919 dx
= winrect
.right() + 1;
2924 if (screen
->getWindowCornerSnap()) {
2925 // try corner-snap to its other sides
2926 dtop
= std::abs(wtop
- winrect
.top());
2927 dbottom
= std::abs(wbottom
- winrect
.bottom());
2928 if (dtop
< snap_distance
&& dtop
<= dbottom
)
2930 else if (dbottom
< snap_distance
)
2931 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
2938 if (wleft
>= (signed)(winrect
.x() - frame
.rect
.width() + 1) &&
2939 wleft
< (signed)(winrect
.x() + winrect
.width() - 1)) {
2941 // snap top of other window?
2942 if (dtop
< snap_distance
&& dtop
<= dbottom
) {
2943 dy
= winrect
.top() - frame
.rect
.height();
2946 // snap bottom of other window?
2947 else if (dbottom
< snap_distance
) {
2948 dy
= winrect
.bottom() + 1;
2953 if (screen
->getWindowCornerSnap()) {
2954 // try corner-snap to its other sides
2955 dleft
= std::abs(wleft
- winrect
.left());
2956 dright
= std::abs(wright
- winrect
.right());
2957 if (dleft
< snap_distance
&& dleft
<= dright
)
2958 dx
= winrect
.left();
2959 else if (dright
< snap_distance
)
2960 dx
= winrect
.right() - frame
.rect
.width() + 1;
2969 // try snap to the screen's available area
2970 Rect srect
= screen
->availableArea();
2972 int dleft
= std::abs(wleft
- srect
.left()),
2973 dright
= std::abs(wright
- srect
.right()),
2974 dtop
= std::abs(wtop
- srect
.top()),
2975 dbottom
= std::abs(wbottom
- srect
.bottom());
2978 if (dleft
< snap_distance
&& dleft
<= dright
)
2981 else if (dright
< snap_distance
)
2982 dx
= srect
.right() - frame
.rect
.width() + 1;
2985 if (dtop
< snap_distance
&& dtop
<= dbottom
)
2988 else if (dbottom
< snap_distance
)
2989 dy
= srect
.bottom() - frame
.rect
.height() + 1;
2991 srect
= screen
->getRect(); // now get the full screen
2993 dleft
= std::abs(wleft
- srect
.left()),
2994 dright
= std::abs(wright
- srect
.right()),
2995 dtop
= std::abs(wtop
- srect
.top()),
2996 dbottom
= std::abs(wbottom
- srect
.bottom());
2999 if (dleft
< snap_distance
&& dleft
<= dright
)
3002 else if (dright
< snap_distance
)
3003 dx
= srect
.right() - frame
.rect
.width() + 1;
3006 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3009 else if (dbottom
< snap_distance
)
3010 dy
= srect
.bottom() - frame
.rect
.height() + 1;
3013 if (screen
->doOpaqueMove()) {
3014 configure(dx
, dy
, frame
.rect
.width(), frame
.rect
.height());
3016 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3020 frame
.changing
.width() - 1,
3021 frame
.changing
.height() - 1);
3023 frame
.changing
.setPos(dx
, dy
);
3025 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3029 frame
.changing
.width() - 1,
3030 frame
.changing
.height() - 1);
3033 screen
->showPosition(dx
, dy
);
3037 void BlackboxWindow::endMove(void) {
3038 assert(flags
.moving
);
3039 assert(blackbox
->getChangingWindow() == this);
3041 flags
.moving
= False
;
3042 blackbox
->setChangingWindow(0);
3044 if (! screen
->doOpaqueMove()) {
3045 /* when drawing the rubber band, we need to make sure we only draw inside
3046 * the frame... frame.changing_* contain the new coords for the window,
3047 * so we need to subtract 1 from changing_w/changing_h every where we
3048 * draw the rubber band (for both moving and resizing)
3050 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3051 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3052 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3053 XUngrabServer(blackbox
->getXDisplay());
3055 configure(frame
.changing
.x(), frame
.changing
.y(),
3056 frame
.changing
.width(), frame
.changing
.height());
3058 configure(frame
.rect
.x(), frame
.rect
.y(),
3059 frame
.rect
.width(), frame
.rect
.height());
3061 screen
->hideGeometry();
3063 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3065 // if there are any left over motions from the move, drop them now
3066 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3068 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3073 void BlackboxWindow::beginResize(int x_root
, int y_root
, Corner dir
) {
3074 assert(! (flags
.resizing
|| flags
.moving
));
3077 Only one window can be moved/resized at a time. If another window is already
3078 being moved or resized, then stop it before whating to work with this one.
3080 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3081 if (changing
&& changing
!= this) {
3082 if (changing
->flags
.moving
)
3083 changing
->endMove();
3084 else // if (changing->flags.resizing)
3085 changing
->endResize();
3093 switch (resize_dir
) {
3096 cursor
= blackbox
->getLowerLeftAngleCursor();
3101 cursor
= blackbox
->getLowerRightAngleCursor();
3105 anchor
= BottomRight
;
3106 cursor
= blackbox
->getUpperLeftAngleCursor();
3110 anchor
= BottomLeft
;
3111 cursor
= blackbox
->getUpperRightAngleCursor();
3115 assert(false); // unhandled Corner
3118 XGrabServer(blackbox
->getXDisplay());
3119 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3120 PointerMotionMask
| ButtonReleaseMask
,
3121 GrabModeAsync
, GrabModeAsync
, None
, cursor
, CurrentTime
);
3123 flags
.resizing
= True
;
3124 blackbox
->setChangingWindow(this);
3127 frame
.changing
= frame
.rect
;
3129 constrain(anchor
, &gw
, &gh
);
3131 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3132 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3133 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3135 screen
->showGeometry(gw
, gh
);
3137 frame
.grab_x
= x_root
;
3138 frame
.grab_y
= y_root
;
3142 void BlackboxWindow::doResize(int x_root
, int y_root
) {
3143 assert(flags
.resizing
);
3144 assert(blackbox
->getChangingWindow() == this);
3146 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3147 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3148 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3153 switch (resize_dir
) {
3156 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3157 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3161 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3162 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3165 anchor
= BottomRight
;
3166 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3167 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3170 anchor
= BottomLeft
;
3171 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3172 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3176 assert(false); // unhandled Corner
3179 constrain(anchor
, &gw
, &gh
);
3181 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3182 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3183 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3185 screen
->showGeometry(gw
, gh
);
3189 void BlackboxWindow::endResize(void) {
3190 assert(flags
.resizing
);
3191 assert(blackbox
->getChangingWindow() == this);
3193 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3194 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3195 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3196 XUngrabServer(blackbox
->getXDisplay());
3198 // unset maximized state after resized when fully maximized
3199 if (flags
.maximized
== 1)
3202 flags
.resizing
= False
;
3203 blackbox
->setChangingWindow(0);
3205 configure(frame
.changing
.x(), frame
.changing
.y(),
3206 frame
.changing
.width(), frame
.changing
.height());
3207 screen
->hideGeometry();
3209 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3211 // if there are any left over motions from the resize, drop them now
3212 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3214 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3219 void BlackboxWindow::motionNotifyEvent(const XMotionEvent
*me
) {
3221 fprintf(stderr
, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n",
3226 doMove(me
->x_root
, me
->y_root
);
3227 } else if (flags
.resizing
) {
3228 doResize(me
->x_root
, me
->y_root
);
3230 if (! flags
.resizing
&& (me
->state
& Button1Mask
) &&
3231 (functions
& Func_Move
) &&
3232 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3233 frame
.handle
== me
->window
|| frame
.window
== me
->window
)) {
3234 beginMove(me
->x_root
, me
->y_root
);
3235 } else if ((functions
& Func_Resize
) &&
3236 (((me
->state
& Button1Mask
) &&
3237 (me
->window
== frame
.right_grip
||
3238 me
->window
== frame
.left_grip
)) ||
3239 (me
->state
& (Mod1Mask
| Button3Mask
) &&
3240 me
->window
== frame
.window
))) {
3241 beginResize(me
->x_root
, me
->y_root
,
3242 (me
->window
== frame
.left_grip
) ? BottomLeft
: BottomRight
);
3249 void BlackboxWindow::shapeEvent(XShapeEvent
*) {
3250 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
3257 bool BlackboxWindow::validateClient(void) const {
3258 XSync(blackbox
->getXDisplay(), False
);
3261 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3262 DestroyNotify
, &e
) ||
3263 XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3265 XPutBackEvent(blackbox
->getXDisplay(), &e
);
3274 void BlackboxWindow::restore(bool remap
) {
3275 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeDelete
);
3276 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
3277 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, NoEventMask
);
3279 // do not leave a shaded window as an icon unless it was an icon
3280 if (flags
.shaded
&& ! flags
.iconic
) setState(NormalState
);
3282 restoreGravity(client
.rect
);
3284 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
3285 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
3287 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, client
.old_bw
);
3290 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3291 ReparentNotify
, &ev
)) {
3294 // according to the ICCCM - if the client doesn't reparent to
3295 // root, then we have to do it for them
3296 XReparentWindow(blackbox
->getXDisplay(), client
.window
,
3297 screen
->getRootWindow(),
3298 client
.rect
.x(), client
.rect
.y());
3301 if (remap
) XMapWindow(blackbox
->getXDisplay(), client
.window
);
3305 // timer for autoraise
3306 void BlackboxWindow::timeout(void) {
3307 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3311 void BlackboxWindow::changeBlackboxHints(BlackboxHints
*net
) {
3312 if ((net
->flags
& AttribShaded
) &&
3313 ((blackbox_attrib
.attrib
& AttribShaded
) !=
3314 (net
->attrib
& AttribShaded
)))
3317 if (flags
.visible
&& // watch out for requests when we can not be seen
3318 (net
->flags
& (AttribMaxVert
| AttribMaxHoriz
)) &&
3319 ((blackbox_attrib
.attrib
& (AttribMaxVert
| AttribMaxHoriz
)) !=
3320 (net
->attrib
& (AttribMaxVert
| AttribMaxHoriz
)))) {
3321 if (flags
.maximized
) {
3326 if ((net
->flags
& AttribMaxHoriz
) && (net
->flags
& AttribMaxVert
))
3327 button
= ((net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0);
3328 else if (net
->flags
& AttribMaxVert
)
3329 button
= ((net
->attrib
& AttribMaxVert
) ? 2 : 0);
3330 else if (net
->flags
& AttribMaxHoriz
)
3331 button
= ((net
->attrib
& AttribMaxHoriz
) ? 3 : 0);
3337 if ((net
->flags
& AttribOmnipresent
) &&
3338 ((blackbox_attrib
.attrib
& AttribOmnipresent
) !=
3339 (net
->attrib
& AttribOmnipresent
)))
3342 if ((net
->flags
& AttribWorkspace
) &&
3343 (blackbox_attrib
.workspace
!= net
->workspace
)) {
3344 screen
->reassociateWindow(this, net
->workspace
, True
);
3346 if (screen
->getCurrentWorkspaceID() != net
->workspace
) {
3350 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3354 if (net
->flags
& AttribDecoration
) {
3355 switch (net
->decoration
) {
3357 // clear all decorations except close
3358 decorations
&= Decor_Close
;
3364 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Iconify
;
3366 decorations
= ((functions
& Func_Resize
) && !isTransient() ?
3367 decorations
| Decor_Handle
:
3368 decorations
&= ~Decor_Handle
);
3369 decorations
= (functions
& Func_Maximize
?
3370 decorations
| Decor_Maximize
:
3371 decorations
&= ~Decor_Maximize
);
3376 decorations
|= Decor_Titlebar
| Decor_Iconify
;
3377 decorations
&= ~(Decor_Border
| Decor_Handle
);
3379 decorations
= (functions
& Func_Maximize
?
3380 decorations
| Decor_Maximize
:
3381 decorations
&= ~Decor_Maximize
);
3386 decorations
|= Decor_Titlebar
;
3387 decorations
&= ~(Decor_Iconify
| Decor_Border
);
3389 decorations
= ((functions
& Func_Resize
) && !isTransient() ?
3390 decorations
| Decor_Handle
:
3391 decorations
&= ~Decor_Handle
);
3392 decorations
= (functions
& Func_Maximize
?
3393 decorations
| Decor_Maximize
:
3394 decorations
&= ~Decor_Maximize
);
3399 // we can not be shaded if we lack a titlebar
3400 if (flags
.shaded
&& ! (decorations
& Decor_Titlebar
))
3403 if (flags
.visible
&& frame
.window
) {
3404 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
3405 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
3409 setState(current_state
);
3415 * Set the sizes of all components of the window frame
3416 * (the window decorations).
3417 * These values are based upon the current style settings and the client
3418 * window's dimensions.
3420 void BlackboxWindow::upsize(void) {
3421 frame
.bevel_w
= screen
->getBevelWidth();
3423 if (decorations
& Decor_Border
) {
3424 frame
.border_w
= screen
->getBorderWidth();
3425 if (! isTransient())
3426 frame
.mwm_border_w
= screen
->getFrameWidth();
3428 frame
.mwm_border_w
= 0;
3430 frame
.mwm_border_w
= frame
.border_w
= 0;
3433 if (decorations
& Decor_Titlebar
) {
3434 // the height of the titlebar is based upon the height of the font being
3435 // used to display the window's title
3436 WindowStyle
*style
= screen
->getWindowStyle();
3437 frame
.title_h
= style
->font
->height() + (frame
.bevel_w
* 2) + 2;
3439 frame
.label_h
= frame
.title_h
- (frame
.bevel_w
* 2);
3440 frame
.button_w
= (frame
.label_h
- 2);
3442 // set the top frame margin
3443 frame
.margin
.top
= frame
.border_w
+ frame
.title_h
+
3444 frame
.border_w
+ frame
.mwm_border_w
;
3450 // set the top frame margin
3451 frame
.margin
.top
= frame
.border_w
+ frame
.mwm_border_w
;
3454 // set the left/right frame margin
3455 frame
.margin
.left
= frame
.margin
.right
= frame
.border_w
+ frame
.mwm_border_w
;
3457 if (decorations
& Decor_Handle
) {
3458 frame
.grip_w
= frame
.button_w
* 2;
3459 frame
.handle_h
= screen
->getHandleWidth();
3461 // set the bottom frame margin
3462 frame
.margin
.bottom
= frame
.border_w
+ frame
.handle_h
+
3463 frame
.border_w
+ frame
.mwm_border_w
;
3468 // set the bottom frame margin
3469 frame
.margin
.bottom
= frame
.border_w
+ frame
.mwm_border_w
;
3473 We first get the normal dimensions and use this to define the inside_w/h
3474 then we modify the height if shading is in effect.
3475 If the shade state is not considered then frame.rect gets reset to the
3476 normal window size on a reconfigure() call resulting in improper
3477 dimensions appearing in move/resize and other events.
3480 height
= client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
,
3481 width
= client
.rect
.width() + frame
.margin
.left
+ frame
.margin
.right
;
3483 frame
.inside_w
= width
- (frame
.border_w
* 2);
3484 frame
.inside_h
= height
- (frame
.border_w
* 2);
3487 height
= frame
.title_h
+ (frame
.border_w
* 2);
3488 frame
.rect
.setSize(width
, height
);
3493 * Calculate the size of the client window and constrain it to the
3494 * size specified by the size hints of the client window.
3496 * The logical width and height are placed into pw and ph, if they
3497 * are non-zero. Logical size refers to the users perception of
3498 * the window size (for example an xterm resizes in cells, not in pixels).
3500 * The physical geometry is placed into frame.changing_{x,y,width,height}.
3501 * Physical geometry refers to the geometry of the window in pixels.
3503 void BlackboxWindow::constrain(Corner anchor
, int *pw
, int *ph
) {
3504 // frame.changing represents the requested frame size, we need to
3505 // strip the frame margin off and constrain the client size
3506 frame
.changing
.setCoords(frame
.changing
.left() + frame
.margin
.left
,
3507 frame
.changing
.top() + frame
.margin
.top
,
3508 frame
.changing
.right() - frame
.margin
.right
,
3509 frame
.changing
.bottom() - frame
.margin
.bottom
);
3511 int dw
= frame
.changing
.width(), dh
= frame
.changing
.height(),
3512 base_width
= (client
.base_width
) ? client
.base_width
: client
.min_width
,
3513 base_height
= (client
.base_height
) ? client
.base_height
:
3517 if (dw
< static_cast<signed>(client
.min_width
)) dw
= client
.min_width
;
3518 if (dh
< static_cast<signed>(client
.min_height
)) dh
= client
.min_height
;
3519 if (dw
> static_cast<signed>(client
.max_width
)) dw
= client
.max_width
;
3520 if (dh
> static_cast<signed>(client
.max_height
)) dh
= client
.max_height
;
3523 dw
/= client
.width_inc
;
3525 dh
/= client
.height_inc
;
3528 if (client
.width_inc
== 1)
3529 *pw
= dw
+ base_width
;
3534 if (client
.height_inc
== 1)
3535 *ph
= dh
+ base_height
;
3540 dw
*= client
.width_inc
;
3542 dh
*= client
.height_inc
;
3545 frame
.changing
.setSize(dw
, dh
);
3547 // add the frame margin back onto frame.changing
3548 frame
.changing
.setCoords(frame
.changing
.left() - frame
.margin
.left
,
3549 frame
.changing
.top() - frame
.margin
.top
,
3550 frame
.changing
.right() + frame
.margin
.right
,
3551 frame
.changing
.bottom() + frame
.margin
.bottom
);
3553 // move frame.changing to the specified anchor
3561 dx
= frame
.rect
.right() - frame
.changing
.right();
3565 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3569 dx
= frame
.rect
.right() - frame
.changing
.right();
3570 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3574 assert(false); // unhandled corner
3576 frame
.changing
.setPos(frame
.changing
.x() + dx
, frame
.changing
.y() + dy
);
3580 void WindowStyle::doJustify(const std::string
&text
, int &start_pos
,
3581 unsigned int max_length
,
3582 unsigned int modifier
) const {
3583 size_t text_len
= text
.size();
3584 unsigned int length
;
3587 length
= font
->measureString(string(text
, 0, text_len
)) + modifier
;
3588 } while (length
> max_length
&& text_len
-- > 0);
3592 start_pos
+= max_length
- length
;
3596 start_pos
+= (max_length
- length
) / 2;
3606 BWindowGroup::BWindowGroup(Blackbox
*b
, Window _group
)
3607 : blackbox(b
), group(_group
) {
3608 XWindowAttributes wattrib
;
3609 if (! XGetWindowAttributes(blackbox
->getXDisplay(), group
, &wattrib
)) {
3610 // group window doesn't seem to exist anymore
3616 watch for destroy notify on the group window (in addition to
3617 any other events we are looking for)
3619 since some managed windows can also be window group controllers,
3620 we need to make sure that we don't clobber the event mask for the
3623 XSelectInput(blackbox
->getXDisplay(), group
,
3624 wattrib
.your_event_mask
| StructureNotifyMask
);
3626 blackbox
->saveGroupSearch(group
, this);
3630 BWindowGroup::~BWindowGroup(void) {
3631 blackbox
->removeGroupSearch(group
);
3636 BWindowGroup::find(BScreen
*screen
, bool allow_transients
) const {
3637 BlackboxWindow
*ret
= blackbox
->getFocusedWindow();
3639 // does the focus window match (or any transient_fors)?
3641 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3642 if (ret
->isTransient() && allow_transients
) break;
3643 else if (! ret
->isTransient()) break;
3646 ret
= ret
->getTransientFor();
3649 if (ret
) return ret
;
3651 // the focus window didn't match, look in the group's window list
3652 BlackboxWindowList::const_iterator it
, end
= windowList
.end();
3653 for (it
= windowList
.begin(); it
!= end
; ++it
) {
3655 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3656 if (ret
->isTransient() && allow_transients
) break;
3657 else if (! ret
->isTransient()) break;