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());
850 // alt+middle lowers the window
851 blackbox
->grabButton(Button2
, Mod1Mask
, frame
.window
, True
,
852 ButtonReleaseMask
, GrabModeAsync
, GrabModeAsync
,
857 void BlackboxWindow::ungrabButtons(void) {
858 if ((! screen
->isSloppyFocus()) || screen
->doClickRaise())
859 blackbox
->ungrabButton(Button1
, 0, frame
.plate
);
861 blackbox
->ungrabButton(Button1
, Mod1Mask
, frame
.window
);
862 blackbox
->ungrabButton(Button2
, Mod1Mask
, frame
.window
);
863 blackbox
->ungrabButton(Button3
, Mod1Mask
, frame
.window
);
867 void BlackboxWindow::positionWindows(void) {
868 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.window
,
869 frame
.rect
.x(), frame
.rect
.y(), frame
.inside_w
,
870 (flags
.shaded
) ? frame
.title_h
: frame
.inside_h
);
871 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.window
,
873 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.plate
,
875 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.plate
,
876 frame
.margin
.left
- frame
.mwm_border_w
- frame
.border_w
,
877 frame
.margin
.top
- frame
.mwm_border_w
- frame
.border_w
,
878 client
.rect
.width(), client
.rect
.height());
879 XMoveResizeWindow(blackbox
->getXDisplay(), client
.window
,
880 0, 0, client
.rect
.width(), client
.rect
.height());
881 // ensure client.rect contains the real location
882 client
.rect
.setCoords(frame
.rect
.left() + frame
.margin
.left
,
883 frame
.rect
.top() + frame
.margin
.top
,
884 frame
.rect
.right() - frame
.margin
.right
,
885 frame
.rect
.bottom() - frame
.margin
.bottom
);
887 if (decorations
& Decor_Titlebar
) {
888 if (frame
.title
== None
) createTitlebar();
890 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.title
,
892 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.title
, -frame
.border_w
,
893 -frame
.border_w
, frame
.inside_w
, frame
.title_h
);
896 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
897 XMapWindow(blackbox
->getXDisplay(), frame
.title
);
898 } else if (frame
.title
) {
901 if (decorations
& Decor_Handle
) {
902 if (frame
.handle
== None
) createHandle();
903 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.handle
,
905 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.left_grip
,
907 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.right_grip
,
910 // use client.rect here so the value is correct even if shaded
911 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.handle
,
913 client
.rect
.height() + frame
.margin
.top
+
914 frame
.mwm_border_w
- frame
.border_w
,
915 frame
.inside_w
, frame
.handle_h
);
916 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.left_grip
,
917 -frame
.border_w
, -frame
.border_w
,
918 frame
.grip_w
, frame
.handle_h
);
919 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.right_grip
,
920 frame
.inside_w
- frame
.grip_w
- frame
.border_w
,
921 -frame
.border_w
, frame
.grip_w
, frame
.handle_h
);
923 XMapSubwindows(blackbox
->getXDisplay(), frame
.handle
);
924 XMapWindow(blackbox
->getXDisplay(), frame
.handle
);
925 } else if (frame
.handle
) {
931 void BlackboxWindow::updateStrut(void) {
932 unsigned long num
= 4;
934 if (! xatom
->getValue(client
.window
, XAtom::net_wm_strut
, XAtom::cardinal
,
939 client
.strut
.left
= data
[0];
940 client
.strut
.right
= data
[1];
941 client
.strut
.top
= data
[2];
942 client
.strut
.bottom
= data
[3];
944 screen
->updateAvailableArea();
951 void BlackboxWindow::getWindowType(void) {
953 if (xatom
->getValue(client
.window
, XAtom::net_wm_window_type
, XAtom::atom
,
955 if (val
== xatom
->getAtom(XAtom::net_wm_window_type_desktop
))
956 window_type
= Type_Desktop
;
957 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_dock
))
958 window_type
= Type_Dock
;
959 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_toolbar
))
960 window_type
= Type_Toolbar
;
961 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_menu
))
962 window_type
= Type_Menu
;
963 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_utility
))
964 window_type
= Type_Utility
;
965 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_splash
))
966 window_type
= Type_Splash
;
967 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_dialog
))
968 window_type
= Type_Dialog
;
969 else //if (val[0] == xatom->getAtom(XAtom::net_wm_window_type_normal))
970 window_type
= Type_Normal
;
975 * the window type hint was not set, which means we either classify ourself
976 * as a normal window or a dialog, depending on if we are a transient.
979 window_type
= Type_Dialog
;
981 window_type
= Type_Normal
;
985 void BlackboxWindow::getWMName(void) {
986 if (xatom
->getValue(client
.window
, XAtom::net_wm_name
,
987 XAtom::utf8
, client
.title
) &&
988 !client
.title
.empty()) {
989 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
992 //fall through to using WM_NAME
993 if (xatom
->getValue(client
.window
, XAtom::wm_name
, XAtom::ansi
, client
.title
)
994 && !client
.title
.empty()) {
995 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
998 // fall back to an internal default
999 client
.title
= i18n(WindowSet
, WindowUnnamed
, "Unnamed");
1000 xatom
->setValue(client
.window
, XAtom::net_wm_visible_name
, XAtom::utf8
,
1005 void BlackboxWindow::getWMIconName(void) {
1006 if (xatom
->getValue(client
.window
, XAtom::net_wm_icon_name
,
1007 XAtom::utf8
, client
.icon_title
) &&
1008 !client
.icon_title
.empty()) {
1009 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1012 //fall through to using WM_ICON_NAME
1013 if (xatom
->getValue(client
.window
, XAtom::wm_icon_name
, XAtom::ansi
,
1014 client
.icon_title
) &&
1015 !client
.icon_title
.empty()) {
1016 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1019 // fall back to using the main name
1020 client
.icon_title
= client
.title
;
1021 xatom
->setValue(client
.window
, XAtom::net_wm_visible_icon_name
, XAtom::utf8
,
1027 * Retrieve which WM Protocols are supported by the client window.
1028 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
1029 * window's decorations and allow the close behavior.
1030 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
1033 void BlackboxWindow::getWMProtocols(void) {
1037 if (XGetWMProtocols(blackbox
->getXDisplay(), client
.window
,
1038 &proto
, &num_return
)) {
1039 for (int i
= 0; i
< num_return
; ++i
) {
1040 if (proto
[i
] == xatom
->getAtom(XAtom::wm_delete_window
)) {
1041 decorations
|= Decor_Close
;
1042 functions
|= Func_Close
;
1043 } else if (proto
[i
] == xatom
->getAtom(XAtom::wm_take_focus
))
1044 flags
.send_focus_message
= True
;
1045 else if (proto
[i
] == xatom
->getAtom(XAtom::blackbox_structure_messages
))
1046 screen
->addNetizen(new Netizen(screen
, client
.window
));
1055 * Gets the value of the WM_HINTS property.
1056 * If the property is not set, then use a set of default values.
1058 void BlackboxWindow::getWMHints(void) {
1059 focus_mode
= F_Passive
;
1060 client
.initial_state
= NormalState
;
1062 // remove from current window group
1063 if (client
.window_group
) {
1064 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1065 if (group
) group
->removeWindow(this);
1067 client
.window_group
= None
;
1069 XWMHints
*wmhint
= XGetWMHints(blackbox
->getXDisplay(), client
.window
);
1074 if (wmhint
->flags
& InputHint
) {
1075 if (wmhint
->input
== True
) {
1076 if (flags
.send_focus_message
)
1077 focus_mode
= F_LocallyActive
;
1079 if (flags
.send_focus_message
)
1080 focus_mode
= F_GloballyActive
;
1082 focus_mode
= F_NoInput
;
1086 if (wmhint
->flags
& StateHint
)
1087 client
.initial_state
= wmhint
->initial_state
;
1089 if (wmhint
->flags
& WindowGroupHint
) {
1090 client
.window_group
= wmhint
->window_group
;
1092 // add window to the appropriate group
1093 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1094 if (! group
) // no group found, create it!
1095 group
= new BWindowGroup(blackbox
, client
.window_group
);
1096 group
->addWindow(this);
1099 client
.wm_hint_flags
= wmhint
->flags
;
1105 * Gets the value of the WM_NORMAL_HINTS property.
1106 * If the property is not set, then use a set of default values.
1108 void BlackboxWindow::getWMNormalHints(void) {
1110 XSizeHints sizehint
;
1112 client
.min_width
= client
.min_height
=
1113 client
.width_inc
= client
.height_inc
= 1;
1114 client
.base_width
= client
.base_height
= 0;
1117 use the full screen, not the strut modified size. otherwise when the
1118 availableArea changes max_width/height will be incorrect and lead to odd
1121 const Rect
& screen_area
= screen
->getRect();
1122 client
.max_width
= screen_area
.width();
1124 client
.max_height
= screen_area
.height();
1125 client
.min_aspect_x
= client
.min_aspect_y
=
1126 client
.max_aspect_x
= client
.max_aspect_y
= 1;
1127 client
.win_gravity
= NorthWestGravity
;
1129 if (! XGetWMNormalHints(blackbox
->getXDisplay(), client
.window
,
1130 &sizehint
, &icccm_mask
))
1133 client
.normal_hint_flags
= sizehint
.flags
;
1135 if (sizehint
.flags
& PMinSize
) {
1136 client
.min_width
= sizehint
.min_width
;
1137 client
.min_height
= sizehint
.min_height
;
1140 if (sizehint
.flags
& PMaxSize
) {
1141 client
.max_width
= sizehint
.max_width
;
1142 client
.max_height
= sizehint
.max_height
;
1145 if (sizehint
.flags
& PResizeInc
) {
1146 client
.width_inc
= sizehint
.width_inc
;
1147 client
.height_inc
= sizehint
.height_inc
;
1150 if (sizehint
.flags
& PAspect
) {
1151 client
.min_aspect_x
= sizehint
.min_aspect
.x
;
1152 client
.min_aspect_y
= sizehint
.min_aspect
.y
;
1153 client
.max_aspect_x
= sizehint
.max_aspect
.x
;
1154 client
.max_aspect_y
= sizehint
.max_aspect
.y
;
1157 if (sizehint
.flags
& PBaseSize
) {
1158 client
.base_width
= sizehint
.base_width
;
1159 client
.base_height
= sizehint
.base_height
;
1162 if (sizehint
.flags
& PWinGravity
)
1163 client
.win_gravity
= sizehint
.win_gravity
;
1168 * Gets the NETWM hints for the class' contained window.
1170 void BlackboxWindow::getNetWMHints(void) {
1171 unsigned long workspace
;
1173 if (xatom
->getValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1175 if (workspace
== 0xffffffff)
1178 blackbox_attrib
.workspace
= workspace
;
1181 unsigned long *state
;
1182 unsigned long num
= (unsigned) -1;
1183 if (xatom
->getValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
1187 for (unsigned long i
= 0; i
< num
; ++i
) {
1188 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
))
1190 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_shaded
))
1191 flags
.shaded
= True
;
1192 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
))
1193 flags
.skip_taskbar
= True
;
1194 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_pager
))
1195 flags
.skip_pager
= True
;
1196 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_fullscreen
))
1197 flags
.fullscreen
= True
;
1198 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_hidden
))
1199 setState(IconicState
);
1200 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_vert
))
1202 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_horz
))
1206 flags
.maximized
= 1;
1208 flags
.maximized
= 2;
1210 flags
.maximized
= 3;
1218 * Gets the MWM hints for the class' contained window.
1219 * This is used while initializing the window to its first state, and not
1221 * Returns: true if the MWM hints are successfully retreived and applied;
1222 * false if they are not.
1224 void BlackboxWindow::getMWMHints(void) {
1228 num
= PropMwmHintsElements
;
1229 if (! xatom
->getValue(client
.window
, XAtom::motif_wm_hints
,
1230 XAtom::motif_wm_hints
, num
,
1231 (unsigned long **)&mwm_hint
))
1233 if (num
< PropMwmHintsElements
) {
1238 if (mwm_hint
->flags
& MwmHintsDecorations
) {
1239 if (mwm_hint
->decorations
& MwmDecorAll
) {
1240 decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
1241 Decor_Iconify
| Decor_Maximize
| Decor_Close
;
1245 if (mwm_hint
->decorations
& MwmDecorBorder
)
1246 decorations
|= Decor_Border
;
1247 if (mwm_hint
->decorations
& MwmDecorHandle
)
1248 decorations
|= Decor_Handle
;
1249 if (mwm_hint
->decorations
& MwmDecorTitle
)
1250 decorations
|= Decor_Titlebar
;
1251 if (mwm_hint
->decorations
& MwmDecorIconify
)
1252 decorations
|= Decor_Iconify
;
1253 if (mwm_hint
->decorations
& MwmDecorMaximize
)
1254 decorations
|= Decor_Maximize
;
1258 if (mwm_hint
->flags
& MwmHintsFunctions
) {
1259 if (mwm_hint
->functions
& MwmFuncAll
) {
1260 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
|
1265 if (mwm_hint
->functions
& MwmFuncResize
)
1266 functions
|= Func_Resize
;
1267 if (mwm_hint
->functions
& MwmFuncMove
)
1268 functions
|= Func_Move
;
1269 if (mwm_hint
->functions
& MwmFuncIconify
)
1270 functions
|= Func_Iconify
;
1271 if (mwm_hint
->functions
& MwmFuncMaximize
)
1272 functions
|= Func_Maximize
;
1273 if (mwm_hint
->functions
& MwmFuncClose
)
1274 functions
|= Func_Close
;
1282 * Gets the blackbox hints from the class' contained window.
1283 * This is used while initializing the window to its first state, and not
1285 * Returns: true if the hints are successfully retreived and applied; false if
1288 bool BlackboxWindow::getBlackboxHints(void) {
1290 BlackboxHints
*blackbox_hint
;
1292 num
= PropBlackboxHintsElements
;
1293 if (! xatom
->getValue(client
.window
, XAtom::blackbox_hints
,
1294 XAtom::blackbox_hints
, num
,
1295 (unsigned long **)&blackbox_hint
))
1297 if (num
< PropBlackboxHintsElements
) {
1298 delete [] blackbox_hint
;
1302 if (blackbox_hint
->flags
& AttribShaded
)
1303 flags
.shaded
= (blackbox_hint
->attrib
& AttribShaded
);
1305 if ((blackbox_hint
->flags
& AttribMaxHoriz
) &&
1306 (blackbox_hint
->flags
& AttribMaxVert
))
1307 flags
.maximized
= (blackbox_hint
->attrib
&
1308 (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1309 else if (blackbox_hint
->flags
& AttribMaxVert
)
1310 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxVert
) ? 2 : 0;
1311 else if (blackbox_hint
->flags
& AttribMaxHoriz
)
1312 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1314 if (blackbox_hint
->flags
& AttribOmnipresent
)
1315 flags
.stuck
= (blackbox_hint
->attrib
& AttribOmnipresent
);
1317 if (blackbox_hint
->flags
& AttribWorkspace
)
1318 blackbox_attrib
.workspace
= blackbox_hint
->workspace
;
1320 // if (blackbox_hint->flags & AttribStack)
1321 // don't yet have always on top/bottom for blackbox yet... working
1324 if (blackbox_hint
->flags
& AttribDecoration
) {
1325 switch (blackbox_hint
->decoration
) {
1327 // clear all decorations except close
1328 decorations
&= Decor_Close
;
1329 // clear all functions except close
1330 functions
&= Func_Close
;
1335 decorations
|= Decor_Titlebar
| Decor_Iconify
;
1336 decorations
&= ~(Decor_Border
| Decor_Handle
| Decor_Maximize
);
1337 functions
|= Func_Move
| Func_Iconify
;
1338 functions
&= ~(Func_Resize
| Func_Maximize
);
1343 decorations
|= Decor_Titlebar
;
1344 decorations
&= ~(Decor_Iconify
| Decor_Border
| Decor_Handle
);
1345 functions
|= Func_Move
;
1346 functions
&= ~(Func_Resize
| Func_Maximize
| Func_Iconify
);
1352 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Handle
|
1353 Decor_Iconify
| Decor_Maximize
;
1354 functions
|= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
1362 delete [] blackbox_hint
;
1368 void BlackboxWindow::getTransientInfo(void) {
1369 if (client
.transient_for
&&
1370 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1371 // the transient for hint was removed, so we need to tell our
1372 // previous transient_for that we are going away
1373 client
.transient_for
->client
.transientList
.remove(this);
1376 // we have no transient_for until we find a new one
1377 client
.transient_for
= 0;
1380 if (! XGetTransientForHint(blackbox
->getXDisplay(), client
.window
,
1382 // transient_for hint not set
1386 if (trans_for
== client
.window
) {
1387 // wierd client... treat this window as a normal window
1391 if (trans_for
== None
|| trans_for
== screen
->getRootWindow()) {
1392 // this is an undocumented interpretation of the ICCCM. a transient
1393 // associated with None/Root/itself is assumed to be a modal root
1394 // transient. we don't support the concept of a global transient,
1395 // so we just associate this transient with nothing, and perhaps
1396 // we will add support later for global modality.
1397 client
.transient_for
= (BlackboxWindow
*) ~0ul;
1402 client
.transient_for
= blackbox
->searchWindow(trans_for
);
1403 if (! client
.transient_for
&&
1404 client
.window_group
&& trans_for
== client
.window_group
) {
1405 // no direct transient_for, perhaps this is a group transient?
1406 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1407 if (group
) client
.transient_for
= group
->find(screen
);
1410 if (! client
.transient_for
|| client
.transient_for
== this) {
1411 // no transient_for found, or we have a wierd client that wants to be
1412 // a transient for itself, so we treat this window as a normal window
1413 client
.transient_for
= (BlackboxWindow
*) 0;
1417 // register ourselves with our new transient_for
1418 client
.transient_for
->client
.transientList
.push_back(this);
1419 flags
.stuck
= client
.transient_for
->flags
.stuck
;
1423 bool BlackboxWindow::isKDESystrayWindow(void) {
1425 if (xatom
->getValue(client
.window
, XAtom::kde_net_wm_system_tray_window_for
,
1426 XAtom::window
, systray
) && systray
)
1432 BlackboxWindow
*BlackboxWindow::getTransientFor(void) const {
1433 if (client
.transient_for
&&
1434 client
.transient_for
!= (BlackboxWindow
*) ~0ul)
1435 return client
.transient_for
;
1441 * This function is responsible for updating both the client and the frame
1443 * According to the ICCCM a client message is not sent for a resize, only a
1446 void BlackboxWindow::configure(int dx
, int dy
,
1447 unsigned int dw
, unsigned int dh
) {
1448 bool send_event
= (frame
.rect
.x() != dx
|| frame
.rect
.y() != dy
);
1450 if (dw
!= frame
.rect
.width() || dh
!= frame
.rect
.height()) {
1451 frame
.rect
.setRect(dx
, dy
, dw
, dh
);
1452 frame
.inside_w
= frame
.rect
.width() - (frame
.border_w
* 2);
1453 frame
.inside_h
= frame
.rect
.height() - (frame
.border_w
* 2);
1455 if (frame
.rect
.right() <= 0 || frame
.rect
.bottom() <= 0)
1456 frame
.rect
.setPos(0, 0);
1458 client
.rect
.setCoords(frame
.rect
.left() + frame
.margin
.left
,
1459 frame
.rect
.top() + frame
.margin
.top
,
1460 frame
.rect
.right() - frame
.margin
.right
,
1461 frame
.rect
.bottom() - frame
.margin
.bottom
);
1464 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
1471 redrawWindowFrame();
1473 frame
.rect
.setPos(dx
, dy
);
1475 XMoveWindow(blackbox
->getXDisplay(), frame
.window
,
1476 frame
.rect
.x(), frame
.rect
.y());
1479 if (send_event
&& ! flags
.moving
) {
1480 // if moving, the update and event will occur when the move finishes
1481 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1482 frame
.rect
.top() + frame
.margin
.top
);
1485 event
.type
= ConfigureNotify
;
1487 event
.xconfigure
.display
= blackbox
->getXDisplay();
1488 event
.xconfigure
.event
= client
.window
;
1489 event
.xconfigure
.window
= client
.window
;
1490 event
.xconfigure
.x
= client
.rect
.x();
1491 event
.xconfigure
.y
= client
.rect
.y();
1492 event
.xconfigure
.width
= client
.rect
.width();
1493 event
.xconfigure
.height
= client
.rect
.height();
1494 event
.xconfigure
.border_width
= client
.old_bw
;
1495 event
.xconfigure
.above
= frame
.window
;
1496 event
.xconfigure
.override_redirect
= False
;
1498 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1499 StructureNotifyMask
, &event
);
1500 screen
->updateNetizenConfigNotify(&event
);
1506 void BlackboxWindow::configureShape(void) {
1507 XShapeCombineShape(blackbox
->getXDisplay(), frame
.window
, ShapeBounding
,
1508 frame
.margin
.left
- frame
.border_w
,
1509 frame
.margin
.top
- frame
.border_w
,
1510 client
.window
, ShapeBounding
, ShapeSet
);
1513 XRectangle xrect
[2];
1515 if (decorations
& Decor_Titlebar
) {
1516 xrect
[0].x
= xrect
[0].y
= -frame
.border_w
;
1517 xrect
[0].width
= frame
.rect
.width();
1518 xrect
[0].height
= frame
.title_h
+ (frame
.border_w
* 2);
1522 if (decorations
& Decor_Handle
) {
1523 xrect
[1].x
= -frame
.border_w
;
1524 xrect
[1].y
= frame
.rect
.height() - frame
.margin
.bottom
+
1525 frame
.mwm_border_w
- frame
.border_w
;
1526 xrect
[1].width
= frame
.rect
.width();
1527 xrect
[1].height
= frame
.handle_h
+ (frame
.border_w
* 2);
1531 XShapeCombineRectangles(blackbox
->getXDisplay(), frame
.window
,
1532 ShapeBounding
, 0, 0, xrect
, num
,
1533 ShapeUnion
, Unsorted
);
1538 bool BlackboxWindow::setInputFocus(void) {
1539 if (flags
.focused
) return True
;
1541 assert(! flags
.iconic
&&
1542 (flags
.stuck
|| // window must be on the current workspace or sticky
1543 blackbox_attrib
.workspace
== screen
->getCurrentWorkspaceID()));
1545 // if the window is not visible, mark the window as wanting focus rather
1546 // than give it focus.
1547 if (! flags
.visible
) {
1548 Workspace
*wkspc
= screen
->getWorkspace(blackbox_attrib
.workspace
);
1549 wkspc
->setLastFocusedWindow(this);
1553 if (! frame
.rect
.intersects(screen
->getRect())) {
1554 // client is outside the screen, move it to the center
1555 configure((screen
->getWidth() - frame
.rect
.width()) / 2,
1556 (screen
->getHeight() - frame
.rect
.height()) / 2,
1557 frame
.rect
.width(), frame
.rect
.height());
1560 if (client
.transientList
.size() > 0) {
1561 // transfer focus to any modal transients
1562 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1563 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1564 if ((*it
)->flags
.modal
) return (*it
)->setInputFocus();
1569 if (focus_mode
== F_LocallyActive
|| focus_mode
== F_Passive
) {
1570 XSetInputFocus(blackbox
->getXDisplay(), client
.window
,
1571 RevertToPointerRoot
, CurrentTime
);
1573 blackbox
->setFocusedWindow(this);
1575 /* we could set the focus to none, since the window doesn't accept focus,
1576 * but we shouldn't set focus to nothing since this would surely make
1582 if (flags
.send_focus_message
) {
1584 ce
.xclient
.type
= ClientMessage
;
1585 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1586 ce
.xclient
.display
= blackbox
->getXDisplay();
1587 ce
.xclient
.window
= client
.window
;
1588 ce
.xclient
.format
= 32;
1589 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_take_focus
);
1590 ce
.xclient
.data
.l
[1] = blackbox
->getLastTime();
1591 ce
.xclient
.data
.l
[2] = 0l;
1592 ce
.xclient
.data
.l
[3] = 0l;
1593 ce
.xclient
.data
.l
[4] = 0l;
1594 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1602 void BlackboxWindow::iconify(void) {
1603 if (flags
.iconic
) return;
1605 // We don't need to worry about resizing because resizing always grabs the X
1606 // server. This should only ever happen if using opaque moving.
1610 if (windowmenu
) windowmenu
->hide();
1613 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1614 * we need to clear the event mask on client.window for a split second.
1615 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1616 * split second, leaving us with a ghost window... so, we need to do this
1617 * while the X server is grabbed
1619 XGrabServer(blackbox
->getXDisplay());
1620 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
1621 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1622 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1623 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
1624 XUngrabServer(blackbox
->getXDisplay());
1626 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1627 flags
.visible
= False
;
1628 flags
.iconic
= True
;
1630 setState(IconicState
);
1632 screen
->getWorkspace(blackbox_attrib
.workspace
)->removeWindow(this);
1634 if (isTransient()) {
1635 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1636 ! client
.transient_for
->flags
.iconic
) {
1637 // iconify our transient_for
1638 client
.transient_for
->iconify();
1642 screen
->addIcon(this);
1644 if (client
.transientList
.size() > 0) {
1645 // iconify all transients
1646 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1647 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1648 if (! (*it
)->flags
.iconic
) (*it
)->iconify();
1654 void BlackboxWindow::show(void) {
1655 flags
.visible
= True
;
1656 flags
.iconic
= False
;
1658 current_state
= (flags
.shaded
) ? IconicState
: NormalState
;
1659 setState(current_state
);
1661 XMapWindow(blackbox
->getXDisplay(), client
.window
);
1662 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
1663 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
1668 XTranslateCoordinates(blackbox
->getXDisplay(), client
.window
,
1669 screen
->getRootWindow(),
1670 0, 0, &real_x
, &real_y
, &child
);
1671 fprintf(stderr
, "%s -- assumed: (%d, %d), real: (%d, %d)\n", getTitle(),
1672 client
.rect
.left(), client
.rect
.top(), real_x
, real_y
);
1673 assert(client
.rect
.left() == real_x
&& client
.rect
.top() == real_y
);
1678 void BlackboxWindow::deiconify(bool reassoc
, bool raise
) {
1679 if (flags
.iconic
|| reassoc
)
1680 screen
->reassociateWindow(this, BSENTINEL
, False
);
1681 else if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID())
1686 // reassociate and deiconify all transients
1687 if (reassoc
&& client
.transientList
.size() > 0) {
1688 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1689 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1690 (*it
)->deiconify(True
, False
);
1695 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1699 void BlackboxWindow::close(void) {
1701 ce
.xclient
.type
= ClientMessage
;
1702 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1703 ce
.xclient
.display
= blackbox
->getXDisplay();
1704 ce
.xclient
.window
= client
.window
;
1705 ce
.xclient
.format
= 32;
1706 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_delete_window
);
1707 ce
.xclient
.data
.l
[1] = CurrentTime
;
1708 ce
.xclient
.data
.l
[2] = 0l;
1709 ce
.xclient
.data
.l
[3] = 0l;
1710 ce
.xclient
.data
.l
[4] = 0l;
1711 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
, NoEventMask
, &ce
);
1715 void BlackboxWindow::withdraw(void) {
1716 // We don't need to worry about resizing because resizing always grabs the X
1717 // server. This should only ever happen if using opaque moving.
1721 flags
.visible
= False
;
1722 flags
.iconic
= False
;
1724 setState(current_state
);
1726 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1728 XGrabServer(blackbox
->getXDisplay());
1730 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
1731 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1732 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1733 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
1735 XUngrabServer(blackbox
->getXDisplay());
1737 if (windowmenu
) windowmenu
->hide();
1741 void BlackboxWindow::maximize(unsigned int button
) {
1742 // We don't need to worry about resizing because resizing always grabs the X
1743 // server. This should only ever happen if using opaque moving.
1747 // handle case where menu is open then the max button is used instead
1748 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
1750 if (flags
.maximized
) {
1751 flags
.maximized
= 0;
1753 blackbox_attrib
.flags
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1754 blackbox_attrib
.attrib
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1757 when a resize finishes, maximize(0) is called to clear any maximization
1758 flags currently set. Otherwise it still thinks it is maximized.
1759 so we do not need to call configure() because resizing will handle it
1761 if (! flags
.resizing
)
1762 configure(blackbox_attrib
.premax_x
, blackbox_attrib
.premax_y
,
1763 blackbox_attrib
.premax_w
, blackbox_attrib
.premax_h
);
1765 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
1766 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
1768 redrawAllButtons(); // in case it is not called in configure()
1769 setState(current_state
);
1773 blackbox_attrib
.premax_x
= frame
.rect
.x();
1774 blackbox_attrib
.premax_y
= frame
.rect
.y();
1775 blackbox_attrib
.premax_w
= frame
.rect
.width();
1776 // use client.rect so that clients can be restored even if shaded
1777 blackbox_attrib
.premax_h
=
1778 client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
;
1780 const Rect
&screen_area
= screen
->availableArea();
1781 frame
.changing
= screen_area
;
1785 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1786 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1790 blackbox_attrib
.flags
|= AttribMaxVert
;
1791 blackbox_attrib
.attrib
|= AttribMaxVert
;
1793 frame
.changing
.setX(frame
.rect
.x());
1794 frame
.changing
.setWidth(frame
.rect
.width());
1798 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1799 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1801 frame
.changing
.setY(frame
.rect
.y());
1802 frame
.changing
.setHeight(frame
.rect
.height());
1809 blackbox_attrib
.flags
^= AttribShaded
;
1810 blackbox_attrib
.attrib
^= AttribShaded
;
1811 flags
.shaded
= False
;
1814 flags
.maximized
= button
;
1816 configure(frame
.changing
.x(), frame
.changing
.y(),
1817 frame
.changing
.width(), frame
.changing
.height());
1819 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1820 redrawAllButtons(); // in case it is not called in configure()
1821 setState(current_state
);
1825 // re-maximizes the window to take into account availableArea changes
1826 void BlackboxWindow::remaximize(void) {
1827 // save the original dimensions because maximize will wipe them out
1828 int premax_x
= blackbox_attrib
.premax_x
,
1829 premax_y
= blackbox_attrib
.premax_y
,
1830 premax_w
= blackbox_attrib
.premax_w
,
1831 premax_h
= blackbox_attrib
.premax_h
;
1833 unsigned int button
= flags
.maximized
;
1834 flags
.maximized
= 0; // trick maximize() into working
1837 // restore saved values
1838 blackbox_attrib
.premax_x
= premax_x
;
1839 blackbox_attrib
.premax_y
= premax_y
;
1840 blackbox_attrib
.premax_w
= premax_w
;
1841 blackbox_attrib
.premax_h
= premax_h
;
1845 void BlackboxWindow::setWorkspace(unsigned int n
) {
1846 blackbox_attrib
.flags
|= AttribWorkspace
;
1847 blackbox_attrib
.workspace
= n
;
1848 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
, n
);
1852 void BlackboxWindow::shade(void) {
1854 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1855 frame
.inside_w
, frame
.inside_h
);
1856 flags
.shaded
= False
;
1857 blackbox_attrib
.flags
^= AttribShaded
;
1858 blackbox_attrib
.attrib
^= AttribShaded
;
1860 setState(NormalState
);
1862 // set the frame rect to the normal size
1863 frame
.rect
.setHeight(client
.rect
.height() + frame
.margin
.top
+
1864 frame
.margin
.bottom
);
1866 if (! (decorations
& Decor_Titlebar
))
1867 return; // can't shade it without a titlebar!
1869 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1870 frame
.inside_w
, frame
.title_h
);
1871 flags
.shaded
= True
;
1872 blackbox_attrib
.flags
|= AttribShaded
;
1873 blackbox_attrib
.attrib
|= AttribShaded
;
1875 setState(IconicState
);
1877 // set the frame rect to the shaded size
1878 frame
.rect
.setHeight(frame
.title_h
+ (frame
.border_w
* 2));
1884 * (Un)Sticks a window and its relatives.
1886 void BlackboxWindow::stick(void) {
1888 blackbox_attrib
.flags
^= AttribOmnipresent
;
1889 blackbox_attrib
.attrib
^= AttribOmnipresent
;
1891 flags
.stuck
= False
;
1894 screen
->reassociateWindow(this, BSENTINEL
, True
);
1896 // temporary fix since sticky windows suck. set the hint to what we
1897 // actually hold in our data.
1898 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1899 blackbox_attrib
.workspace
);
1901 setState(current_state
);
1905 blackbox_attrib
.flags
|= AttribOmnipresent
;
1906 blackbox_attrib
.attrib
|= AttribOmnipresent
;
1908 // temporary fix since sticky windows suck. set the hint to a different
1909 // value than that contained in the class' data.
1910 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1913 setState(current_state
);
1916 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1917 client
.transient_for
->isStuck() != flags
.stuck
)
1918 client
.transient_for
->stick();
1919 // go down the chain
1920 BlackboxWindowList::iterator it
;
1921 const BlackboxWindowList::iterator end
= client
.transientList
.end();
1922 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1923 if ((*it
)->isStuck() != flags
.stuck
)
1928 void BlackboxWindow::redrawWindowFrame(void) const {
1929 if (decorations
& Decor_Titlebar
) {
1930 if (flags
.focused
) {
1932 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1933 frame
.title
, frame
.ftitle
);
1935 XSetWindowBackground(blackbox
->getXDisplay(),
1936 frame
.title
, frame
.ftitle_pixel
);
1939 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1940 frame
.title
, frame
.utitle
);
1942 XSetWindowBackground(blackbox
->getXDisplay(),
1943 frame
.title
, frame
.utitle_pixel
);
1945 XClearWindow(blackbox
->getXDisplay(), frame
.title
);
1951 if (decorations
& Decor_Handle
) {
1952 if (flags
.focused
) {
1954 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1955 frame
.handle
, frame
.fhandle
);
1957 XSetWindowBackground(blackbox
->getXDisplay(),
1958 frame
.handle
, frame
.fhandle_pixel
);
1961 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1962 frame
.left_grip
, frame
.fgrip
);
1963 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1964 frame
.right_grip
, frame
.fgrip
);
1966 XSetWindowBackground(blackbox
->getXDisplay(),
1967 frame
.left_grip
, frame
.fgrip_pixel
);
1968 XSetWindowBackground(blackbox
->getXDisplay(),
1969 frame
.right_grip
, frame
.fgrip_pixel
);
1973 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1974 frame
.handle
, frame
.uhandle
);
1976 XSetWindowBackground(blackbox
->getXDisplay(),
1977 frame
.handle
, frame
.uhandle_pixel
);
1980 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1981 frame
.left_grip
, frame
.ugrip
);
1982 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1983 frame
.right_grip
, frame
.ugrip
);
1985 XSetWindowBackground(blackbox
->getXDisplay(),
1986 frame
.left_grip
, frame
.ugrip_pixel
);
1987 XSetWindowBackground(blackbox
->getXDisplay(),
1988 frame
.right_grip
, frame
.ugrip_pixel
);
1991 XClearWindow(blackbox
->getXDisplay(), frame
.handle
);
1992 XClearWindow(blackbox
->getXDisplay(), frame
.left_grip
);
1993 XClearWindow(blackbox
->getXDisplay(), frame
.right_grip
);
1996 if (decorations
& Decor_Border
) {
1998 XSetWindowBorder(blackbox
->getXDisplay(),
1999 frame
.plate
, frame
.fborder_pixel
);
2001 XSetWindowBorder(blackbox
->getXDisplay(),
2002 frame
.plate
, frame
.uborder_pixel
);
2007 void BlackboxWindow::setFocusFlag(bool focus
) {
2008 // only focus a window if it is visible
2009 if (focus
&& !flags
.visible
)
2012 flags
.focused
= focus
;
2014 redrawWindowFrame();
2016 if (screen
->isSloppyFocus() && screen
->doAutoRaise()) {
2017 if (isFocused()) timer
->start();
2022 blackbox
->setFocusedWindow(this);
2026 void BlackboxWindow::installColormap(bool install
) {
2027 int i
= 0, ncmap
= 0;
2028 Colormap
*cmaps
= XListInstalledColormaps(blackbox
->getXDisplay(),
2029 client
.window
, &ncmap
);
2031 XWindowAttributes wattrib
;
2032 if (XGetWindowAttributes(blackbox
->getXDisplay(),
2033 client
.window
, &wattrib
)) {
2035 // install the window's colormap
2036 for (i
= 0; i
< ncmap
; i
++) {
2037 if (*(cmaps
+ i
) == wattrib
.colormap
)
2038 // this window is using an installed color map... do not install
2041 // otherwise, install the window's colormap
2043 XInstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2045 // uninstall the window's colormap
2046 for (i
= 0; i
< ncmap
; i
++) {
2047 if (*(cmaps
+ i
) == wattrib
.colormap
)
2048 // we found the colormap to uninstall
2049 XUninstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2059 void BlackboxWindow::setAllowedActions(void) {
2063 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_shade
);
2064 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_change_desktop
);
2065 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_close
);
2067 if (functions
& Func_Move
)
2068 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_move
);
2069 if (functions
& Func_Resize
)
2070 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_resize
);
2071 if (functions
& Func_Maximize
) {
2072 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_horz
);
2073 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_vert
);
2076 xatom
->setValue(client
.window
, XAtom::net_wm_allowed_actions
, XAtom::atom
,
2081 void BlackboxWindow::setState(unsigned long new_state
) {
2082 current_state
= new_state
;
2084 unsigned long state
[2];
2085 state
[0] = current_state
;
2087 xatom
->setValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
, state
, 2);
2089 xatom
->setValue(client
.window
, XAtom::blackbox_attributes
,
2090 XAtom::blackbox_attributes
, (unsigned long *)&blackbox_attrib
,
2091 PropBlackboxAttributesElements
);
2096 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_modal
);
2098 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_shaded
);
2100 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_hidden
);
2101 if (flags
.skip_taskbar
)
2102 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
);
2103 if (flags
.skip_pager
)
2104 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_pager
);
2105 if (flags
.fullscreen
)
2106 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_fullscreen
);
2107 if (flags
.maximized
== 1 || flags
.maximized
== 2)
2108 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_vert
);
2109 if (flags
.maximized
== 1 || flags
.maximized
== 3)
2110 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_horz
);
2111 xatom
->setValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
2116 bool BlackboxWindow::getState(void) {
2117 bool ret
= xatom
->getValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
,
2119 if (! ret
) current_state
= 0;
2124 void BlackboxWindow::restoreAttributes(void) {
2125 unsigned long num
= PropBlackboxAttributesElements
;
2126 BlackboxAttributes
*net
;
2127 if (! xatom
->getValue(client
.window
, XAtom::blackbox_attributes
,
2128 XAtom::blackbox_attributes
, num
,
2129 (unsigned long **)&net
))
2131 if (num
< PropBlackboxAttributesElements
) {
2136 if (net
->flags
& AttribShaded
&& net
->attrib
& AttribShaded
) {
2137 flags
.shaded
= False
;
2138 unsigned long orig_state
= current_state
;
2142 At this point in the life of a window, current_state should only be set
2143 to IconicState if the window was an *icon*, not if it was shaded.
2145 if (orig_state
!= IconicState
)
2146 current_state
= WithdrawnState
;
2149 if (net
->workspace
!= screen
->getCurrentWorkspaceID() &&
2150 net
->workspace
< screen
->getWorkspaceCount())
2151 screen
->reassociateWindow(this, net
->workspace
, True
);
2153 if ((blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID()) &&
2154 (blackbox_attrib
.workspace
< screen
->getWorkspaceCount())) {
2155 // set to WithdrawnState so it will be mapped on the new workspace
2156 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2157 } else if (current_state
== WithdrawnState
) {
2158 // the window is on this workspace and is Withdrawn, so it is waiting to
2160 current_state
= NormalState
;
2163 if (net
->flags
& AttribOmnipresent
&& net
->attrib
& AttribOmnipresent
) {
2164 flags
.stuck
= False
;
2167 // if the window was on another workspace, it was going to be hidden. this
2168 // specifies that the window should be mapped since it is sticky.
2169 if (current_state
== WithdrawnState
) current_state
= NormalState
;
2172 if (net
->flags
& AttribMaxHoriz
|| net
->flags
& AttribMaxVert
) {
2173 int x
= net
->premax_x
, y
= net
->premax_y
;
2174 unsigned int w
= net
->premax_w
, h
= net
->premax_h
;
2175 flags
.maximized
= 0;
2178 if ((net
->flags
& AttribMaxHoriz
) &&
2179 (net
->flags
& AttribMaxVert
))
2180 m
= (net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
2181 else if (net
->flags
& AttribMaxVert
)
2182 m
= (net
->attrib
& AttribMaxVert
) ? 2 : 0;
2183 else if (net
->flags
& AttribMaxHoriz
)
2184 m
= (net
->attrib
& AttribMaxHoriz
) ? 3 : 0;
2188 blackbox_attrib
.premax_x
= x
;
2189 blackbox_attrib
.premax_y
= y
;
2190 blackbox_attrib
.premax_w
= w
;
2191 blackbox_attrib
.premax_h
= h
;
2194 // with the state set it will then be the map event's job to read the
2195 // window's state and behave accordingly
2202 * Positions the Rect r according the the client window position and
2205 void BlackboxWindow::applyGravity(Rect
&r
) {
2206 // apply horizontal window gravity
2207 switch (client
.win_gravity
) {
2209 case NorthWestGravity
:
2210 case SouthWestGravity
:
2212 r
.setX(client
.rect
.x());
2218 r
.setX(client
.rect
.x() - (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2221 case NorthEastGravity
:
2222 case SouthEastGravity
:
2224 r
.setX(client
.rect
.x() - frame
.margin
.left
- frame
.margin
.right
+ 2);
2229 r
.setX(client
.rect
.x() - frame
.margin
.left
);
2233 // apply vertical window gravity
2234 switch (client
.win_gravity
) {
2236 case NorthWestGravity
:
2237 case NorthEastGravity
:
2239 r
.setY(client
.rect
.y());
2245 r
.setY(client
.rect
.y() - (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2248 case SouthWestGravity
:
2249 case SouthEastGravity
:
2251 r
.setY(client
.rect
.y() - frame
.margin
.top
- frame
.margin
.bottom
+ 2);
2256 r
.setY(client
.rect
.y() - frame
.margin
.top
);
2263 * The reverse of the applyGravity function.
2265 * Positions the Rect r according to the frame window position and
2268 void BlackboxWindow::restoreGravity(Rect
&r
) {
2269 // restore horizontal window gravity
2270 switch (client
.win_gravity
) {
2272 case NorthWestGravity
:
2273 case SouthWestGravity
:
2275 r
.setX(frame
.rect
.x());
2281 r
.setX(frame
.rect
.x() + (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2284 case NorthEastGravity
:
2285 case SouthEastGravity
:
2287 r
.setX(frame
.rect
.x() + frame
.margin
.left
+ frame
.margin
.right
- 2);
2292 r
.setX(frame
.rect
.x() + frame
.margin
.left
);
2296 // restore vertical window gravity
2297 switch (client
.win_gravity
) {
2299 case NorthWestGravity
:
2300 case NorthEastGravity
:
2302 r
.setY(frame
.rect
.y());
2308 r
.setY(frame
.rect
.y() + (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2311 case SouthWestGravity
:
2312 case SouthEastGravity
:
2314 r
.setY(frame
.rect
.y() + frame
.margin
.top
+ frame
.margin
.bottom
- 2);
2319 r
.setY(frame
.rect
.y() + frame
.margin
.top
);
2325 void BlackboxWindow::redrawLabel(void) const {
2326 if (flags
.focused
) {
2328 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2329 frame
.label
, frame
.flabel
);
2331 XSetWindowBackground(blackbox
->getXDisplay(),
2332 frame
.label
, frame
.flabel_pixel
);
2335 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2336 frame
.label
, frame
.ulabel
);
2338 XSetWindowBackground(blackbox
->getXDisplay(),
2339 frame
.label
, frame
.ulabel_pixel
);
2341 XClearWindow(blackbox
->getXDisplay(), frame
.label
);
2343 WindowStyle
*style
= screen
->getWindowStyle();
2345 int pos
= frame
.bevel_w
* 2;
2346 style
->doJustify(client
.title
.c_str(), pos
, frame
.label_w
, frame
.bevel_w
* 4);
2347 style
->font
->drawString(frame
.label
, pos
, 1,
2348 (flags
.focused
? style
->l_text_focus
:
2349 style
->l_text_unfocus
),
2354 void BlackboxWindow::redrawAllButtons(void) const {
2355 if (frame
.iconify_button
) redrawIconifyButton(False
);
2356 if (frame
.maximize_button
) redrawMaximizeButton(flags
.maximized
);
2357 if (frame
.close_button
) redrawCloseButton(False
);
2361 void BlackboxWindow::redrawIconifyButton(bool pressed
) const {
2363 if (flags
.focused
) {
2365 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2366 frame
.iconify_button
, frame
.fbutton
);
2368 XSetWindowBackground(blackbox
->getXDisplay(),
2369 frame
.iconify_button
, frame
.fbutton_pixel
);
2372 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2373 frame
.iconify_button
, frame
.ubutton
);
2375 XSetWindowBackground(blackbox
->getXDisplay(), frame
.iconify_button
,
2376 frame
.ubutton_pixel
);
2380 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2381 frame
.iconify_button
, frame
.pbutton
);
2383 XSetWindowBackground(blackbox
->getXDisplay(),
2384 frame
.iconify_button
, frame
.pbutton_pixel
);
2386 XClearWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
2388 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2389 screen
->getWindowStyle()->b_pic_unfocus
);
2390 XDrawRectangle(blackbox
->getXDisplay(), frame
.iconify_button
, pen
.gc(),
2391 2, (frame
.button_w
- 5), (frame
.button_w
- 5), 2);
2395 void BlackboxWindow::redrawMaximizeButton(bool pressed
) const {
2397 if (flags
.focused
) {
2399 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2400 frame
.maximize_button
, frame
.fbutton
);
2402 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2403 frame
.fbutton_pixel
);
2406 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2407 frame
.maximize_button
, frame
.ubutton
);
2409 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2410 frame
.ubutton_pixel
);
2414 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2415 frame
.maximize_button
, frame
.pbutton
);
2417 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2418 frame
.pbutton_pixel
);
2420 XClearWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
2422 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2423 screen
->getWindowStyle()->b_pic_unfocus
);
2424 XDrawRectangle(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2425 2, 2, (frame
.button_w
- 5), (frame
.button_w
- 5));
2426 XDrawLine(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2427 2, 3, (frame
.button_w
- 3), 3);
2431 void BlackboxWindow::redrawCloseButton(bool pressed
) const {
2433 if (flags
.focused
) {
2435 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2438 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2439 frame
.fbutton_pixel
);
2442 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2445 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2446 frame
.ubutton_pixel
);
2450 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2451 frame
.close_button
, frame
.pbutton
);
2453 XSetWindowBackground(blackbox
->getXDisplay(),
2454 frame
.close_button
, frame
.pbutton_pixel
);
2456 XClearWindow(blackbox
->getXDisplay(), frame
.close_button
);
2458 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2459 screen
->getWindowStyle()->b_pic_unfocus
);
2460 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2461 2, 2, (frame
.button_w
- 3), (frame
.button_w
- 3));
2462 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2463 2, (frame
.button_w
- 3), (frame
.button_w
- 3), 2);
2467 void BlackboxWindow::mapRequestEvent(const XMapRequestEvent
*re
) {
2468 if (re
->window
!= client
.window
)
2472 fprintf(stderr
, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2476 switch (current_state
) {
2481 case WithdrawnState
:
2490 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2491 if (! blackbox
->isStartup() && (isTransient() || screen
->doFocusNew())) {
2492 XSync(blackbox
->getXDisplay(), False
); // make sure the frame is mapped..
2500 void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent
*ue
) {
2501 if (ue
->window
!= client
.window
)
2505 fprintf(stderr
, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2509 screen
->unmanageWindow(this, False
);
2513 void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent
*de
) {
2514 if (de
->window
!= client
.window
)
2518 fprintf(stderr
, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2522 screen
->unmanageWindow(this, False
);
2526 void BlackboxWindow::reparentNotifyEvent(const XReparentEvent
*re
) {
2527 if (re
->window
!= client
.window
|| re
->parent
== frame
.plate
)
2531 fprintf(stderr
, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2532 "0x%lx.\n", client
.window
, re
->parent
);
2537 XPutBackEvent(blackbox
->getXDisplay(), &ev
);
2538 screen
->unmanageWindow(this, True
);
2542 void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent
*pe
) {
2543 if (pe
->state
== PropertyDelete
)
2547 fprintf(stderr
, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n",
2553 case XA_WM_CLIENT_MACHINE
:
2557 case XA_WM_TRANSIENT_FOR
: {
2558 // determine if this is a transient window
2561 // adjust the window decorations based on transience
2562 if (isTransient()) {
2563 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2564 functions
&= ~Func_Maximize
;
2565 setAllowedActions();
2576 case XA_WM_ICON_NAME
:
2578 if (flags
.iconic
) screen
->propagateWindowName(this);
2581 case XAtom::net_wm_name
:
2585 if (decorations
& Decor_Titlebar
)
2588 screen
->propagateWindowName(this);
2591 case XA_WM_NORMAL_HINTS
: {
2594 if ((client
.normal_hint_flags
& PMinSize
) &&
2595 (client
.normal_hint_flags
& PMaxSize
)) {
2596 // the window now can/can't resize itself, so the buttons need to be
2599 if (client
.max_width
<= client
.min_width
&&
2600 client
.max_height
<= client
.min_height
) {
2601 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2602 functions
&= ~(Func_Resize
| Func_Maximize
);
2604 decorations
|= Decor_Maximize
| Decor_Handle
;
2605 functions
|= Func_Resize
| Func_Maximize
;
2608 setAllowedActions();
2611 Rect old_rect
= frame
.rect
;
2615 if (old_rect
!= frame
.rect
)
2622 if (pe
->atom
== xatom
->getAtom(XAtom::wm_protocols
)) {
2625 if ((decorations
& Decor_Close
) && (! frame
.close_button
)) {
2626 createCloseButton();
2627 if (decorations
& Decor_Titlebar
) {
2628 positionButtons(True
);
2629 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
2631 if (windowmenu
) windowmenu
->reconfigure();
2633 } else if (pe
->atom
== xatom
->getAtom(XAtom::net_wm_strut
)) {
2642 void BlackboxWindow::exposeEvent(const XExposeEvent
*ee
) {
2644 fprintf(stderr
, "BlackboxWindow::exposeEvent() for 0x%lx\n", client
.window
);
2647 if (frame
.label
== ee
->window
&& (decorations
& Decor_Titlebar
))
2649 else if (frame
.close_button
== ee
->window
)
2650 redrawCloseButton(False
);
2651 else if (frame
.maximize_button
== ee
->window
)
2652 redrawMaximizeButton(flags
.maximized
);
2653 else if (frame
.iconify_button
== ee
->window
)
2654 redrawIconifyButton(False
);
2658 void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent
*cr
) {
2659 if (cr
->window
!= client
.window
|| flags
.iconic
)
2662 if (cr
->value_mask
& CWBorderWidth
)
2663 client
.old_bw
= cr
->border_width
;
2665 if (cr
->value_mask
& (CWX
| CWY
| CWWidth
| CWHeight
)) {
2666 Rect req
= frame
.rect
;
2668 if (cr
->value_mask
& (CWX
| CWY
)) {
2669 if (cr
->value_mask
& CWX
)
2670 client
.rect
.setX(cr
->x
);
2671 if (cr
->value_mask
& CWY
)
2672 client
.rect
.setY(cr
->y
);
2677 if (cr
->value_mask
& CWWidth
)
2678 req
.setWidth(cr
->width
+ frame
.margin
.left
+ frame
.margin
.right
);
2680 if (cr
->value_mask
& CWHeight
)
2681 req
.setHeight(cr
->height
+ frame
.margin
.top
+ frame
.margin
.bottom
);
2683 configure(req
.x(), req
.y(), req
.width(), req
.height());
2686 if (cr
->value_mask
& CWStackMode
) {
2687 switch (cr
->detail
) {
2690 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2696 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2703 void BlackboxWindow::buttonPressEvent(const XButtonEvent
*be
) {
2705 fprintf(stderr
, "BlackboxWindow::buttonPressEvent() for 0x%lx\n",
2709 if (frame
.maximize_button
== be
->window
) {
2710 redrawMaximizeButton(True
);
2711 } else if (be
->button
== 1 || (be
->button
== 3 && be
->state
== Mod1Mask
)) {
2712 if (! flags
.focused
)
2715 if (frame
.iconify_button
== be
->window
) {
2716 redrawIconifyButton(True
);
2717 } else if (frame
.close_button
== be
->window
) {
2718 redrawCloseButton(True
);
2719 } else if (frame
.plate
== be
->window
) {
2720 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2722 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2724 XAllowEvents(blackbox
->getXDisplay(), ReplayPointer
, be
->time
);
2726 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
2727 if (((be
->time
- lastButtonPressTime
) <=
2728 blackbox
->getDoubleClickInterval()) ||
2729 (be
->state
& ControlMask
)) {
2730 lastButtonPressTime
= 0;
2733 lastButtonPressTime
= be
->time
;
2737 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2739 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2741 } else if (be
->button
== 2 && (be
->window
!= frame
.iconify_button
) &&
2742 (be
->window
!= frame
.close_button
)) {
2743 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2744 } else if (windowmenu
&& be
->button
== 3 &&
2745 (frame
.title
== be
->window
|| frame
.label
== be
->window
||
2746 frame
.handle
== be
->window
|| frame
.window
== be
->window
)) {
2747 if (windowmenu
->isVisible()) {
2750 int mx
= be
->x_root
- windowmenu
->getWidth() / 2,
2751 my
= be
->y_root
- windowmenu
->getHeight() / 2;
2753 // snap the window menu into a corner/side if necessary
2754 int left_edge
, right_edge
, top_edge
, bottom_edge
;
2757 the " + (frame.border_w * 2) - 1" bits are to get the proper width
2758 and height of the menu, as the sizes returned by it do not include
2761 left_edge
= frame
.rect
.x();
2762 right_edge
= frame
.rect
.right() -
2763 (windowmenu
->getWidth() + (frame
.border_w
* 2) - 1);
2764 top_edge
= client
.rect
.top() - (frame
.border_w
+ frame
.mwm_border_w
);
2765 bottom_edge
= client
.rect
.bottom() -
2766 (windowmenu
->getHeight() + (frame
.border_w
* 2) - 1) +
2767 (frame
.border_w
+ frame
.mwm_border_w
);
2771 if (mx
> right_edge
)
2775 if (my
> bottom_edge
)
2778 windowmenu
->move(mx
, my
);
2780 XRaiseWindow(blackbox
->getXDisplay(), windowmenu
->getWindowID());
2781 XRaiseWindow(blackbox
->getXDisplay(),
2782 windowmenu
->getSendToMenu()->getWindowID());
2785 } else if (be
->button
== 4) {
2786 if ((be
->window
== frame
.label
||
2787 be
->window
== frame
.title
) &&
2791 } else if (be
->button
== 5) {
2792 if ((be
->window
== frame
.label
||
2793 be
->window
== frame
.title
) &&
2800 void BlackboxWindow::buttonReleaseEvent(const XButtonEvent
*re
) {
2802 fprintf(stderr
, "BlackboxWindow::buttonReleaseEvent() for 0x%lx\n",
2806 if (re
->window
== frame
.maximize_button
) {
2807 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2808 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2809 maximize(re
->button
);
2811 redrawMaximizeButton(flags
.maximized
);
2813 } else if (re
->window
== frame
.iconify_button
) {
2814 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2815 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2818 redrawIconifyButton(False
);
2820 } else if (re
->window
== frame
.close_button
) {
2821 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2822 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
)))
2824 redrawCloseButton(False
);
2825 } else if (flags
.moving
) {
2827 } else if (flags
.resizing
) {
2829 } else if (re
->window
== frame
.window
) {
2830 if (re
->button
== 2 && re
->state
== Mod1Mask
)
2831 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
2837 void BlackboxWindow::beginMove(int x_root
, int y_root
) {
2838 assert(! (flags
.resizing
|| flags
.moving
));
2841 Only one window can be moved/resized at a time. If another window is already
2842 being moved or resized, then stop it before whating to work with this one.
2844 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
2845 if (changing
&& changing
!= this) {
2846 if (changing
->flags
.moving
)
2847 changing
->endMove();
2848 else // if (changing->flags.resizing)
2849 changing
->endResize();
2852 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
2853 PointerMotionMask
| ButtonReleaseMask
,
2854 GrabModeAsync
, GrabModeAsync
,
2855 None
, blackbox
->getMoveCursor(), CurrentTime
);
2857 if (windowmenu
&& windowmenu
->isVisible())
2860 flags
.moving
= True
;
2861 blackbox
->setChangingWindow(this);
2863 if (! screen
->doOpaqueMove()) {
2864 XGrabServer(blackbox
->getXDisplay());
2866 frame
.changing
= frame
.rect
;
2867 screen
->showPosition(frame
.changing
.x(), frame
.changing
.y());
2869 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2873 frame
.changing
.width() - 1,
2874 frame
.changing
.height() - 1);
2877 frame
.grab_x
= x_root
- frame
.rect
.x() - frame
.border_w
;
2878 frame
.grab_y
= y_root
- frame
.rect
.y() - frame
.border_w
;
2882 void BlackboxWindow::doMove(int x_root
, int y_root
) {
2883 assert(flags
.moving
);
2884 assert(blackbox
->getChangingWindow() == this);
2886 int dx
= x_root
- frame
.grab_x
, dy
= y_root
- frame
.grab_y
;
2887 dx
-= frame
.border_w
;
2888 dy
-= frame
.border_w
;
2890 const int snap_distance
= screen
->getEdgeSnapThreshold();
2892 if (snap_distance
) {
2894 const int wleft
= dx
,
2895 wright
= dx
+ frame
.rect
.width() - 1,
2897 wbottom
= dy
+ frame
.rect
.height() - 1;
2899 if (screen
->getWindowToWindowSnap()) {
2900 Workspace
*w
= screen
->getWorkspace(getWorkspaceNumber());
2903 // try snap to another window
2904 for (unsigned int i
= 0, c
= w
->getCount(); i
< c
; ++i
) {
2905 BlackboxWindow
*snapwin
= w
->getWindow(i
);
2906 if (snapwin
== this)
2907 continue; // don't snap to self
2909 bool snapped
= False
;
2911 const Rect
&winrect
= snapwin
->frameRect();
2912 int dleft
= std::abs(wright
- winrect
.left()),
2913 dright
= std::abs(wleft
- winrect
.right()),
2914 dtop
= std::abs(wbottom
- winrect
.top()),
2915 dbottom
= std::abs(wtop
- winrect
.bottom());
2917 if (wtop
>= (signed)(winrect
.y() - frame
.rect
.height() + 1) &&
2918 wtop
< (signed)(winrect
.y() + winrect
.height() - 1)) {
2920 // snap left of other window?
2921 if (dleft
< snap_distance
&& dleft
<= dright
) {
2922 dx
= winrect
.left() - frame
.rect
.width();
2925 // snap right of other window?
2926 else if (dright
< snap_distance
) {
2927 dx
= winrect
.right() + 1;
2932 if (screen
->getWindowCornerSnap()) {
2933 // try corner-snap to its other sides
2934 dtop
= std::abs(wtop
- winrect
.top());
2935 dbottom
= std::abs(wbottom
- winrect
.bottom());
2936 if (dtop
< snap_distance
&& dtop
<= dbottom
)
2938 else if (dbottom
< snap_distance
)
2939 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
2946 if (wleft
>= (signed)(winrect
.x() - frame
.rect
.width() + 1) &&
2947 wleft
< (signed)(winrect
.x() + winrect
.width() - 1)) {
2949 // snap top of other window?
2950 if (dtop
< snap_distance
&& dtop
<= dbottom
) {
2951 dy
= winrect
.top() - frame
.rect
.height();
2954 // snap bottom of other window?
2955 else if (dbottom
< snap_distance
) {
2956 dy
= winrect
.bottom() + 1;
2961 if (screen
->getWindowCornerSnap()) {
2962 // try corner-snap to its other sides
2963 dleft
= std::abs(wleft
- winrect
.left());
2964 dright
= std::abs(wright
- winrect
.right());
2965 if (dleft
< snap_distance
&& dleft
<= dright
)
2966 dx
= winrect
.left();
2967 else if (dright
< snap_distance
)
2968 dx
= winrect
.right() - frame
.rect
.width() + 1;
2977 // try snap to the screen's available area
2978 Rect srect
= screen
->availableArea();
2980 int dleft
= std::abs(wleft
- srect
.left()),
2981 dright
= std::abs(wright
- srect
.right()),
2982 dtop
= std::abs(wtop
- srect
.top()),
2983 dbottom
= std::abs(wbottom
- srect
.bottom());
2986 if (dleft
< snap_distance
&& dleft
<= dright
)
2989 else if (dright
< snap_distance
)
2990 dx
= srect
.right() - frame
.rect
.width() + 1;
2993 if (dtop
< snap_distance
&& dtop
<= dbottom
)
2996 else if (dbottom
< snap_distance
)
2997 dy
= srect
.bottom() - frame
.rect
.height() + 1;
2999 srect
= screen
->getRect(); // now get the full screen
3001 dleft
= std::abs(wleft
- srect
.left()),
3002 dright
= std::abs(wright
- srect
.right()),
3003 dtop
= std::abs(wtop
- srect
.top()),
3004 dbottom
= std::abs(wbottom
- srect
.bottom());
3007 if (dleft
< snap_distance
&& dleft
<= dright
)
3010 else if (dright
< snap_distance
)
3011 dx
= srect
.right() - frame
.rect
.width() + 1;
3014 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3017 else if (dbottom
< snap_distance
)
3018 dy
= srect
.bottom() - frame
.rect
.height() + 1;
3021 if (screen
->doOpaqueMove()) {
3022 configure(dx
, dy
, frame
.rect
.width(), frame
.rect
.height());
3024 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3028 frame
.changing
.width() - 1,
3029 frame
.changing
.height() - 1);
3031 frame
.changing
.setPos(dx
, dy
);
3033 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3037 frame
.changing
.width() - 1,
3038 frame
.changing
.height() - 1);
3041 screen
->showPosition(dx
, dy
);
3045 void BlackboxWindow::endMove(void) {
3046 assert(flags
.moving
);
3047 assert(blackbox
->getChangingWindow() == this);
3049 flags
.moving
= False
;
3050 blackbox
->setChangingWindow(0);
3052 if (! screen
->doOpaqueMove()) {
3053 /* when drawing the rubber band, we need to make sure we only draw inside
3054 * the frame... frame.changing_* contain the new coords for the window,
3055 * so we need to subtract 1 from changing_w/changing_h every where we
3056 * draw the rubber band (for both moving and resizing)
3058 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3059 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3060 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3061 XUngrabServer(blackbox
->getXDisplay());
3063 configure(frame
.changing
.x(), frame
.changing
.y(),
3064 frame
.changing
.width(), frame
.changing
.height());
3066 configure(frame
.rect
.x(), frame
.rect
.y(),
3067 frame
.rect
.width(), frame
.rect
.height());
3069 screen
->hideGeometry();
3071 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3073 // if there are any left over motions from the move, drop them now
3074 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3076 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3081 void BlackboxWindow::beginResize(int x_root
, int y_root
, Corner dir
) {
3082 assert(! (flags
.resizing
|| flags
.moving
));
3085 Only one window can be moved/resized at a time. If another window is already
3086 being moved or resized, then stop it before whating to work with this one.
3088 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3089 if (changing
&& changing
!= this) {
3090 if (changing
->flags
.moving
)
3091 changing
->endMove();
3092 else // if (changing->flags.resizing)
3093 changing
->endResize();
3101 switch (resize_dir
) {
3104 cursor
= blackbox
->getLowerLeftAngleCursor();
3109 cursor
= blackbox
->getLowerRightAngleCursor();
3113 anchor
= BottomRight
;
3114 cursor
= blackbox
->getUpperLeftAngleCursor();
3118 anchor
= BottomLeft
;
3119 cursor
= blackbox
->getUpperRightAngleCursor();
3123 assert(false); // unhandled Corner
3124 return; // unreachable, for the compiler
3127 XGrabServer(blackbox
->getXDisplay());
3128 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3129 PointerMotionMask
| ButtonReleaseMask
,
3130 GrabModeAsync
, GrabModeAsync
, None
, cursor
, CurrentTime
);
3132 flags
.resizing
= True
;
3133 blackbox
->setChangingWindow(this);
3136 frame
.changing
= frame
.rect
;
3138 constrain(anchor
, &gw
, &gh
);
3140 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3141 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3142 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3144 screen
->showGeometry(gw
, gh
);
3146 frame
.grab_x
= x_root
;
3147 frame
.grab_y
= y_root
;
3151 void BlackboxWindow::doResize(int x_root
, int y_root
) {
3152 assert(flags
.resizing
);
3153 assert(blackbox
->getChangingWindow() == this);
3155 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3156 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3157 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3162 switch (resize_dir
) {
3165 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3166 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3170 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3171 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3174 anchor
= BottomRight
;
3175 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3176 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3179 anchor
= BottomLeft
;
3180 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3181 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3185 assert(false); // unhandled Corner
3186 return; // unreachable, for the compiler
3189 constrain(anchor
, &gw
, &gh
);
3191 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3192 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3193 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3195 screen
->showGeometry(gw
, gh
);
3199 void BlackboxWindow::endResize(void) {
3200 assert(flags
.resizing
);
3201 assert(blackbox
->getChangingWindow() == this);
3203 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3204 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3205 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3206 XUngrabServer(blackbox
->getXDisplay());
3208 // unset maximized state after resized when fully maximized
3209 if (flags
.maximized
== 1)
3212 flags
.resizing
= False
;
3213 blackbox
->setChangingWindow(0);
3215 configure(frame
.changing
.x(), frame
.changing
.y(),
3216 frame
.changing
.width(), frame
.changing
.height());
3217 screen
->hideGeometry();
3219 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3221 // if there are any left over motions from the resize, drop them now
3222 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3224 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3229 void BlackboxWindow::motionNotifyEvent(const XMotionEvent
*me
) {
3231 fprintf(stderr
, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n",
3236 doMove(me
->x_root
, me
->y_root
);
3237 } else if (flags
.resizing
) {
3238 doResize(me
->x_root
, me
->y_root
);
3240 if (! flags
.resizing
&& (me
->state
& Button1Mask
) &&
3241 (functions
& Func_Move
) &&
3242 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3243 frame
.handle
== me
->window
|| frame
.window
== me
->window
)) {
3244 beginMove(me
->x_root
, me
->y_root
);
3245 } else if ((functions
& Func_Resize
) &&
3246 (((me
->state
& Button1Mask
) &&
3247 (me
->window
== frame
.right_grip
||
3248 me
->window
== frame
.left_grip
)) ||
3249 (me
->state
& (Mod1Mask
| Button3Mask
) &&
3250 me
->window
== frame
.window
))) {
3251 beginResize(me
->x_root
, me
->y_root
,
3252 (me
->window
== frame
.left_grip
) ? BottomLeft
: BottomRight
);
3259 void BlackboxWindow::shapeEvent(XShapeEvent
*) {
3260 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
3267 bool BlackboxWindow::validateClient(void) const {
3268 XSync(blackbox
->getXDisplay(), False
);
3271 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3272 DestroyNotify
, &e
) ||
3273 XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3275 XPutBackEvent(blackbox
->getXDisplay(), &e
);
3284 void BlackboxWindow::restore(bool remap
) {
3285 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeDelete
);
3286 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
3287 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, NoEventMask
);
3289 // do not leave a shaded window as an icon unless it was an icon
3290 if (flags
.shaded
&& ! flags
.iconic
) setState(NormalState
);
3292 restoreGravity(client
.rect
);
3294 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
3295 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
3297 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, client
.old_bw
);
3300 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3301 ReparentNotify
, &ev
)) {
3304 // according to the ICCCM - if the client doesn't reparent to
3305 // root, then we have to do it for them
3306 XReparentWindow(blackbox
->getXDisplay(), client
.window
,
3307 screen
->getRootWindow(),
3308 client
.rect
.x(), client
.rect
.y());
3311 if (remap
) XMapWindow(blackbox
->getXDisplay(), client
.window
);
3315 // timer for autoraise
3316 void BlackboxWindow::timeout(void) {
3317 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3321 void BlackboxWindow::changeBlackboxHints(BlackboxHints
*net
) {
3322 if ((net
->flags
& AttribShaded
) &&
3323 ((blackbox_attrib
.attrib
& AttribShaded
) !=
3324 (net
->attrib
& AttribShaded
)))
3327 if (flags
.visible
&& // watch out for requests when we can not be seen
3328 (net
->flags
& (AttribMaxVert
| AttribMaxHoriz
)) &&
3329 ((blackbox_attrib
.attrib
& (AttribMaxVert
| AttribMaxHoriz
)) !=
3330 (net
->attrib
& (AttribMaxVert
| AttribMaxHoriz
)))) {
3331 if (flags
.maximized
) {
3336 if ((net
->flags
& AttribMaxHoriz
) && (net
->flags
& AttribMaxVert
))
3337 button
= ((net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0);
3338 else if (net
->flags
& AttribMaxVert
)
3339 button
= ((net
->attrib
& AttribMaxVert
) ? 2 : 0);
3340 else if (net
->flags
& AttribMaxHoriz
)
3341 button
= ((net
->attrib
& AttribMaxHoriz
) ? 3 : 0);
3347 if ((net
->flags
& AttribOmnipresent
) &&
3348 ((blackbox_attrib
.attrib
& AttribOmnipresent
) !=
3349 (net
->attrib
& AttribOmnipresent
)))
3352 if ((net
->flags
& AttribWorkspace
) &&
3353 (blackbox_attrib
.workspace
!= net
->workspace
)) {
3354 screen
->reassociateWindow(this, net
->workspace
, True
);
3356 if (screen
->getCurrentWorkspaceID() != net
->workspace
) {
3360 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3364 if (net
->flags
& AttribDecoration
) {
3365 switch (net
->decoration
) {
3367 // clear all decorations except close
3368 decorations
&= Decor_Close
;
3374 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Iconify
;
3376 decorations
= ((functions
& Func_Resize
) && !isTransient() ?
3377 decorations
| Decor_Handle
:
3378 decorations
&= ~Decor_Handle
);
3379 decorations
= (functions
& Func_Maximize
?
3380 decorations
| Decor_Maximize
:
3381 decorations
&= ~Decor_Maximize
);
3386 decorations
|= Decor_Titlebar
| Decor_Iconify
;
3387 decorations
&= ~(Decor_Border
| Decor_Handle
);
3389 decorations
= (functions
& Func_Maximize
?
3390 decorations
| Decor_Maximize
:
3391 decorations
&= ~Decor_Maximize
);
3396 decorations
|= Decor_Titlebar
;
3397 decorations
&= ~(Decor_Iconify
| Decor_Border
);
3399 decorations
= ((functions
& Func_Resize
) && !isTransient() ?
3400 decorations
| Decor_Handle
:
3401 decorations
&= ~Decor_Handle
);
3402 decorations
= (functions
& Func_Maximize
?
3403 decorations
| Decor_Maximize
:
3404 decorations
&= ~Decor_Maximize
);
3409 // we can not be shaded if we lack a titlebar
3410 if (flags
.shaded
&& ! (decorations
& Decor_Titlebar
))
3413 if (flags
.visible
&& frame
.window
) {
3414 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
3415 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
3419 setState(current_state
);
3425 * Set the sizes of all components of the window frame
3426 * (the window decorations).
3427 * These values are based upon the current style settings and the client
3428 * window's dimensions.
3430 void BlackboxWindow::upsize(void) {
3431 frame
.bevel_w
= screen
->getBevelWidth();
3433 if (decorations
& Decor_Border
) {
3434 frame
.border_w
= screen
->getBorderWidth();
3435 if (! isTransient())
3436 frame
.mwm_border_w
= screen
->getFrameWidth();
3438 frame
.mwm_border_w
= 0;
3440 frame
.mwm_border_w
= frame
.border_w
= 0;
3443 if (decorations
& Decor_Titlebar
) {
3444 // the height of the titlebar is based upon the height of the font being
3445 // used to display the window's title
3446 WindowStyle
*style
= screen
->getWindowStyle();
3447 frame
.title_h
= style
->font
->height() + (frame
.bevel_w
* 2) + 2;
3449 frame
.label_h
= frame
.title_h
- (frame
.bevel_w
* 2);
3450 frame
.button_w
= (frame
.label_h
- 2);
3452 // set the top frame margin
3453 frame
.margin
.top
= frame
.border_w
+ frame
.title_h
+
3454 frame
.border_w
+ frame
.mwm_border_w
;
3460 // set the top frame margin
3461 frame
.margin
.top
= frame
.border_w
+ frame
.mwm_border_w
;
3464 // set the left/right frame margin
3465 frame
.margin
.left
= frame
.margin
.right
= frame
.border_w
+ frame
.mwm_border_w
;
3467 if (decorations
& Decor_Handle
) {
3468 frame
.grip_w
= frame
.button_w
* 2;
3469 frame
.handle_h
= screen
->getHandleWidth();
3471 // set the bottom frame margin
3472 frame
.margin
.bottom
= frame
.border_w
+ frame
.handle_h
+
3473 frame
.border_w
+ frame
.mwm_border_w
;
3478 // set the bottom frame margin
3479 frame
.margin
.bottom
= frame
.border_w
+ frame
.mwm_border_w
;
3483 We first get the normal dimensions and use this to define the inside_w/h
3484 then we modify the height if shading is in effect.
3485 If the shade state is not considered then frame.rect gets reset to the
3486 normal window size on a reconfigure() call resulting in improper
3487 dimensions appearing in move/resize and other events.
3490 height
= client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
,
3491 width
= client
.rect
.width() + frame
.margin
.left
+ frame
.margin
.right
;
3493 frame
.inside_w
= width
- (frame
.border_w
* 2);
3494 frame
.inside_h
= height
- (frame
.border_w
* 2);
3497 height
= frame
.title_h
+ (frame
.border_w
* 2);
3498 frame
.rect
.setSize(width
, height
);
3503 * Calculate the size of the client window and constrain it to the
3504 * size specified by the size hints of the client window.
3506 * The logical width and height are placed into pw and ph, if they
3507 * are non-zero. Logical size refers to the users perception of
3508 * the window size (for example an xterm resizes in cells, not in pixels).
3510 * The physical geometry is placed into frame.changing_{x,y,width,height}.
3511 * Physical geometry refers to the geometry of the window in pixels.
3513 void BlackboxWindow::constrain(Corner anchor
, int *pw
, int *ph
) {
3514 // frame.changing represents the requested frame size, we need to
3515 // strip the frame margin off and constrain the client size
3516 frame
.changing
.setCoords(frame
.changing
.left() + frame
.margin
.left
,
3517 frame
.changing
.top() + frame
.margin
.top
,
3518 frame
.changing
.right() - frame
.margin
.right
,
3519 frame
.changing
.bottom() - frame
.margin
.bottom
);
3521 int dw
= frame
.changing
.width(), dh
= frame
.changing
.height(),
3522 base_width
= (client
.base_width
) ? client
.base_width
: client
.min_width
,
3523 base_height
= (client
.base_height
) ? client
.base_height
:
3527 if (dw
< static_cast<signed>(client
.min_width
)) dw
= client
.min_width
;
3528 if (dh
< static_cast<signed>(client
.min_height
)) dh
= client
.min_height
;
3529 if (dw
> static_cast<signed>(client
.max_width
)) dw
= client
.max_width
;
3530 if (dh
> static_cast<signed>(client
.max_height
)) dh
= client
.max_height
;
3533 dw
/= client
.width_inc
;
3535 dh
/= client
.height_inc
;
3538 if (client
.width_inc
== 1)
3539 *pw
= dw
+ base_width
;
3544 if (client
.height_inc
== 1)
3545 *ph
= dh
+ base_height
;
3550 dw
*= client
.width_inc
;
3552 dh
*= client
.height_inc
;
3555 frame
.changing
.setSize(dw
, dh
);
3557 // add the frame margin back onto frame.changing
3558 frame
.changing
.setCoords(frame
.changing
.left() - frame
.margin
.left
,
3559 frame
.changing
.top() - frame
.margin
.top
,
3560 frame
.changing
.right() + frame
.margin
.right
,
3561 frame
.changing
.bottom() + frame
.margin
.bottom
);
3563 // move frame.changing to the specified anchor
3571 dx
= frame
.rect
.right() - frame
.changing
.right();
3575 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3579 dx
= frame
.rect
.right() - frame
.changing
.right();
3580 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3584 assert(false); // unhandled corner
3586 frame
.changing
.setPos(frame
.changing
.x() + dx
, frame
.changing
.y() + dy
);
3590 void WindowStyle::doJustify(const std::string
&text
, int &start_pos
,
3591 unsigned int max_length
,
3592 unsigned int modifier
) const {
3593 size_t text_len
= text
.size();
3594 unsigned int length
;
3597 length
= font
->measureString(string(text
, 0, text_len
)) + modifier
;
3598 } while (length
> max_length
&& text_len
-- > 0);
3602 start_pos
+= max_length
- length
;
3606 start_pos
+= (max_length
- length
) / 2;
3616 BWindowGroup::BWindowGroup(Blackbox
*b
, Window _group
)
3617 : blackbox(b
), group(_group
) {
3618 XWindowAttributes wattrib
;
3619 if (! XGetWindowAttributes(blackbox
->getXDisplay(), group
, &wattrib
)) {
3620 // group window doesn't seem to exist anymore
3626 watch for destroy notify on the group window (in addition to
3627 any other events we are looking for)
3629 since some managed windows can also be window group controllers,
3630 we need to make sure that we don't clobber the event mask for the
3633 XSelectInput(blackbox
->getXDisplay(), group
,
3634 wattrib
.your_event_mask
| StructureNotifyMask
);
3636 blackbox
->saveGroupSearch(group
, this);
3640 BWindowGroup::~BWindowGroup(void) {
3641 blackbox
->removeGroupSearch(group
);
3646 BWindowGroup::find(BScreen
*screen
, bool allow_transients
) const {
3647 BlackboxWindow
*ret
= blackbox
->getFocusedWindow();
3649 // does the focus window match (or any transient_fors)?
3651 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3652 if (ret
->isTransient() && allow_transients
) break;
3653 else if (! ret
->isTransient()) break;
3656 ret
= ret
->getTransientFor();
3659 if (ret
) return ret
;
3661 // the focus window didn't match, look in the group's window list
3662 BlackboxWindowList::const_iterator it
, end
= windowList
.end();
3663 for (it
= windowList
.begin(); it
!= end
; ++it
) {
3665 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3666 if (ret
->isTransient() && allow_transients
) break;
3667 else if (! ret
->isTransient()) break;