1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2 // Window.cc for Blackbox - an X11 Window manager
3 // Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry <shaleh at debian.org>
4 // Copyright (c) 1997 - 2000, 2002 Brad Hughes <bhughes at trolltech.com>
6 // Permission is hereby granted, free of charge, to any person obtaining a
7 // copy of this software and associated documentation files (the "Software"),
8 // to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 // and/or sell copies of the Software, and to permit persons to whom the
11 // Software is furnished to do so, subject to the following conditions:
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 // DEALINGS IN THE SOFTWARE.
25 # include "../config.h"
26 #endif // HAVE_CONFIG_H
29 #include <X11/Xatom.h>
30 #include <X11/keysym.h>
34 #endif // HAVE_STRING_H
39 # endif // HAVE_STDIO_H
46 #include "blackbox.hh"
48 #include "Iconmenu.hh"
54 #include "Windowmenu.hh"
55 #include "Workspace.hh"
63 * Initializes the class with default values/the window's set initial values.
65 BlackboxWindow::BlackboxWindow(Blackbox
*b
, Window w
, BScreen
*s
) {
66 // fprintf(stderr, "BlackboxWindow size: %d bytes\n",
67 // sizeof(BlackboxWindow));
70 fprintf(stderr
, "BlackboxWindow::BlackboxWindow(): creating 0x%lx\n", w
);
74 set timer to zero... it is initialized properly later, so we check
75 if timer is zero in the destructor, and assume that the window is not
76 fully constructed if timer is zero...
82 xatom
= blackbox
->getXAtom();
83 input
= blackbox
->getInput();
85 if (! validateClient()) {
90 // set the eventmask early in the game so that we make sure we get
91 // all the events we are interested in
92 XSetWindowAttributes attrib_set
;
93 attrib_set
.event_mask
= PropertyChangeMask
| FocusChangeMask
|
95 attrib_set
.do_not_propagate_mask
= ButtonPressMask
| ButtonReleaseMask
|
97 XChangeWindowAttributes(blackbox
->getXDisplay(), client
.window
,
98 CWEventMask
|CWDontPropagate
, &attrib_set
);
100 // fetch client size and placement
101 XWindowAttributes wattrib
;
102 if ((! XGetWindowAttributes(blackbox
->getXDisplay(),
103 client
.window
, &wattrib
)) ||
104 (! wattrib
.screen
) || wattrib
.override_redirect
) {
107 "BlackboxWindow::BlackboxWindow(): XGetWindowAttributes failed\n");
114 flags
.moving
= flags
.resizing
= flags
.shaded
= flags
.visible
=
115 flags
.iconic
= flags
.focused
= flags
.stuck
= flags
.modal
=
116 flags
.send_focus_message
= flags
.shaped
= flags
.skip_taskbar
=
117 flags
.skip_pager
= flags
.fullscreen
= False
;
120 blackbox_attrib
.workspace
= window_number
= BSENTINEL
;
122 blackbox_attrib
.flags
= blackbox_attrib
.attrib
= blackbox_attrib
.stack
123 = blackbox_attrib
.decoration
= 0l;
124 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
125 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
128 frame
.window
= frame
.plate
= frame
.title
= frame
.handle
= None
;
129 frame
.close_button
= frame
.iconify_button
= frame
.maximize_button
= None
;
130 frame
.right_grip
= frame
.left_grip
= None
;
132 frame
.ulabel_pixel
= frame
.flabel_pixel
= frame
.utitle_pixel
=
133 frame
.ftitle_pixel
= frame
.uhandle_pixel
= frame
.fhandle_pixel
=
134 frame
.ubutton_pixel
= frame
.fbutton_pixel
= frame
.pbutton_pixel
=
135 frame
.uborder_pixel
= frame
.fborder_pixel
= frame
.ugrip_pixel
=
136 frame
.fgrip_pixel
= 0;
137 frame
.utitle
= frame
.ftitle
= frame
.uhandle
= frame
.fhandle
= None
;
138 frame
.ulabel
= frame
.flabel
= frame
.ubutton
= frame
.fbutton
= None
;
139 frame
.pbutton
= frame
.ugrip
= frame
.fgrip
= decorations
;
141 decorations
= Decor_Titlebar
| Decor_Border
| Decor_Handle
|
142 Decor_Iconify
| Decor_Maximize
;
143 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
145 client
.wm_hint_flags
= client
.normal_hint_flags
= 0;
146 client
.transient_for
= 0;
149 get the initial size and location of client window (relative to the
150 _root window_). This position is the reference point used with the
151 window's gravity to find the window's initial position.
153 client
.rect
.setRect(wattrib
.x
, wattrib
.y
, wattrib
.width
, wattrib
.height
);
154 client
.old_bw
= wattrib
.border_width
;
157 lastButtonPressTime
= 0;
159 timer
= new BTimer(blackbox
, this);
160 timer
->setTimeout(blackbox
->getAutoRaiseDelay());
162 if (! getBlackboxHints()) {
167 // get size, aspect, minimum/maximum size and other hints set by the
173 if (client
.initial_state
== WithdrawnState
) {
174 screen
->getSlit()->addClient(client
.window
);
179 if (isKDESystrayWindow()) {
180 screen
->addSystrayWindow(client
.window
);
185 frame
.window
= createToplevelWindow();
186 frame
.plate
= createChildWindow(frame
.window
);
187 associateClientWindow();
189 blackbox
->saveWindowSearch(frame
.window
, this);
190 blackbox
->saveWindowSearch(frame
.plate
, this);
191 blackbox
->saveWindowSearch(client
.window
, this);
193 screen
->addStrut(&client
.strut
);
196 // determine if this is a transient window
199 // determine the window's type, so we can decide its decorations and
200 // functionality, or if we should not manage it at all
203 // adjust the window decorations/behavior based on the window type
204 switch (window_type
) {
206 // desktop windows are not managed by us, we just make sure they stay on the
211 // docks (such as kicker) cannot be moved, and appear on all workspaces
212 functions
&= ~(Func_Move
);
217 // these windows have minimal decorations, only a titlebar, and cannot
218 // be resized or iconified
219 decorations
&= ~(Decor_Maximize
| Decor_Handle
| Decor_Border
|
221 functions
&= ~(Func_Resize
| Func_Maximize
| Func_Iconify
);
225 // splash screens have no functionality or decorations, they are left up
226 // to the application which created them
232 // dialogs cannot be maximized, and don't display a handle
233 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
234 functions
&= ~Func_Maximize
;
238 // normal windows retain all of the possible decorations and functionality
242 // further adjeust the window's decorations/behavior based on window sizes
243 if ((client
.normal_hint_flags
& PMinSize
) &&
244 (client
.normal_hint_flags
& PMaxSize
) &&
245 client
.max_width
<= client
.min_width
&&
246 client
.max_height
<= client
.min_height
) {
247 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
248 functions
&= ~(Func_Resize
| Func_Maximize
);
254 bool place_window
= True
;
255 if (blackbox
->isStartup() || isTransient() ||
256 client
.normal_hint_flags
& (PPosition
|USPosition
)) {
257 applyGravity(frame
.rect
);
259 if (blackbox
->isStartup() ||
260 client
.rect
.intersects(screen
->availableArea()))
261 place_window
= False
;
264 if (decorations
& Decor_Titlebar
)
267 if (decorations
& Decor_Handle
)
271 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
281 if (decorations
& Decor_Titlebar
)
282 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
283 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
285 windowmenu
= new Windowmenu(this);
287 if (blackbox_attrib
.workspace
>= screen
->getWorkspaceCount())
288 screen
->getCurrentWorkspace()->addWindow(this, place_window
);
290 screen
->getWorkspace(blackbox_attrib
.workspace
)->
291 addWindow(this, place_window
);
293 if (! place_window
) {
294 // don't need to call configure if we are letting the workspace
296 configure(frame
.rect
.x(), frame
.rect
.y(),
297 frame
.rect
.width(), frame
.rect
.height());
300 // preserve the window's initial state on first map, and its current state
303 if (client
.wm_hint_flags
& StateHint
)
304 current_state
= client
.initial_state
;
306 current_state
= NormalState
;
309 // get sticky state from our parent window if we've got one
310 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
311 client
.transient_for
->isStuck() != flags
.stuck
)
315 flags
.shaded
= False
;
319 Because the iconic'ness of shaded windows is lost, we need to set the
320 state to NormalState so that shaded windows on other workspaces will not
321 get shown on the first workspace.
322 At this point in the life of a window, current_state should only be set
323 to IconicState if the window was an *icon*, not if it was shaded.
325 current_state
= NormalState
;
333 if (flags
.maximized
&& (functions
& Func_Maximize
)) {
338 When the window is mapped (and also when its attributes are restored), the
339 current_state that was set here will be used.
340 It is set to Normal if the window is to be mapped or it is set to Iconic
341 if the window is to be iconified.
342 *Note* that for sticky windows, the same rules apply here, they are in
343 fact never set to Iconic since there is no way for us to tell if a sticky
344 window was iconified previously.
351 BlackboxWindow::~BlackboxWindow(void) {
353 fprintf(stderr
, "BlackboxWindow::~BlackboxWindow: destroying 0x%lx\n",
357 if (! timer
) // window not managed...
360 screen
->removeStrut(&client
.strut
);
361 screen
->updateAvailableArea();
363 // We don't need to worry about resizing because resizing always grabs the X
364 // server. This should only ever happen if using opaque moving.
372 if (client
.window_group
) {
373 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
374 if (group
) group
->removeWindow(this);
377 // remove ourselves from our transient_for
379 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
380 client
.transient_for
->client
.transientList
.remove(this);
382 client
.transient_for
= (BlackboxWindow
*) 0;
385 if (client
.transientList
.size() > 0) {
386 // reset transient_for for all transients
387 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
388 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
389 (*it
)->client
.transient_for
= (BlackboxWindow
*) 0;
400 blackbox
->removeWindowSearch(frame
.plate
);
401 XDestroyWindow(blackbox
->getXDisplay(), frame
.plate
);
405 blackbox
->removeWindowSearch(frame
.window
);
406 XDestroyWindow(blackbox
->getXDisplay(), frame
.window
);
409 blackbox
->removeWindowSearch(client
.window
);
414 * Creates a new top level window, with a given location, size, and border
416 * Returns: the newly created window
418 Window
BlackboxWindow::createToplevelWindow(void) {
419 XSetWindowAttributes attrib_create
;
420 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
| CWColormap
|
421 CWOverrideRedirect
| CWEventMask
;
423 attrib_create
.background_pixmap
= None
;
424 attrib_create
.colormap
= screen
->getColormap();
425 attrib_create
.override_redirect
= True
;
426 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
427 ButtonMotionMask
| EnterWindowMask
;
429 return XCreateWindow(blackbox
->getXDisplay(), screen
->getRootWindow(),
430 -1, -1, 1, 1, frame
.border_w
, screen
->getDepth(),
431 InputOutput
, screen
->getVisual(), create_mask
,
437 * Creates a child window, and optionally associates a given cursor with
440 Window
BlackboxWindow::createChildWindow(Window parent
, Cursor cursor
) {
441 XSetWindowAttributes attrib_create
;
442 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
|
445 attrib_create
.background_pixmap
= None
;
446 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
447 ButtonMotionMask
| ExposureMask
;
450 create_mask
|= CWCursor
;
451 attrib_create
.cursor
= cursor
;
454 return XCreateWindow(blackbox
->getXDisplay(), parent
, 0, 0, 1, 1, 0,
455 screen
->getDepth(), InputOutput
, screen
->getVisual(),
456 create_mask
, &attrib_create
);
460 void BlackboxWindow::associateClientWindow(void) {
461 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, 0);
465 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeInsert
);
467 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, SubstructureRedirectMask
);
469 XGrabServer(blackbox
->getXDisplay());
470 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
471 XReparentWindow(blackbox
->getXDisplay(), client
.window
, frame
.plate
, 0, 0);
472 XSelectInput(blackbox
->getXDisplay(), client
.window
,
473 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
474 XUngrabServer(blackbox
->getXDisplay());
476 XRaiseWindow(blackbox
->getXDisplay(), frame
.plate
);
477 XMapSubwindows(blackbox
->getXDisplay(), frame
.plate
);
481 if (blackbox
->hasShapeExtensions()) {
482 XShapeSelectInput(blackbox
->getXDisplay(), client
.window
,
489 XShapeQueryExtents(blackbox
->getXDisplay(), client
.window
, &shaped
,
490 &foo
, &foo
, &ufoo
, &ufoo
, &foo
, &foo
, &foo
,
492 flags
.shaped
= shaped
;
498 void BlackboxWindow::decorate(void) {
501 texture
= &(screen
->getWindowStyle()->b_focus
);
502 frame
.fbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
505 frame
.fbutton_pixel
= texture
->color().pixel();
507 texture
= &(screen
->getWindowStyle()->b_unfocus
);
508 frame
.ubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
511 frame
.ubutton_pixel
= texture
->color().pixel();
513 texture
= &(screen
->getWindowStyle()->b_pressed
);
514 frame
.pbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
517 frame
.pbutton_pixel
= texture
->color().pixel();
519 if (decorations
& Decor_Titlebar
) {
520 texture
= &(screen
->getWindowStyle()->t_focus
);
521 frame
.ftitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
524 frame
.ftitle_pixel
= texture
->color().pixel();
526 texture
= &(screen
->getWindowStyle()->t_unfocus
);
527 frame
.utitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
530 frame
.utitle_pixel
= texture
->color().pixel();
532 XSetWindowBorder(blackbox
->getXDisplay(), frame
.title
,
533 screen
->getBorderColor()->pixel());
538 if (decorations
& Decor_Border
) {
539 frame
.fborder_pixel
= screen
->getWindowStyle()->f_focus
.pixel();
540 frame
.uborder_pixel
= screen
->getWindowStyle()->f_unfocus
.pixel();
541 blackbox_attrib
.flags
|= AttribDecoration
;
542 blackbox_attrib
.decoration
= DecorNormal
;
544 blackbox_attrib
.flags
|= AttribDecoration
;
545 blackbox_attrib
.decoration
= DecorNone
;
548 if (decorations
& Decor_Handle
) {
549 texture
= &(screen
->getWindowStyle()->h_focus
);
550 frame
.fhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
553 frame
.fhandle_pixel
= texture
->color().pixel();
555 texture
= &(screen
->getWindowStyle()->h_unfocus
);
556 frame
.uhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
559 frame
.uhandle_pixel
= texture
->color().pixel();
561 texture
= &(screen
->getWindowStyle()->g_focus
);
562 frame
.fgrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.fgrip
);
564 frame
.fgrip_pixel
= texture
->color().pixel();
566 texture
= &(screen
->getWindowStyle()->g_unfocus
);
567 frame
.ugrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.ugrip
);
569 frame
.ugrip_pixel
= texture
->color().pixel();
571 XSetWindowBorder(blackbox
->getXDisplay(), frame
.handle
,
572 screen
->getBorderColor()->pixel());
573 XSetWindowBorder(blackbox
->getXDisplay(), frame
.left_grip
,
574 screen
->getBorderColor()->pixel());
575 XSetWindowBorder(blackbox
->getXDisplay(), frame
.right_grip
,
576 screen
->getBorderColor()->pixel());
579 XSetWindowBorder(blackbox
->getXDisplay(), frame
.window
,
580 screen
->getBorderColor()->pixel());
584 void BlackboxWindow::decorateLabel(void) {
587 texture
= &(screen
->getWindowStyle()->l_focus
);
588 frame
.flabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.flabel
);
590 frame
.flabel_pixel
= texture
->color().pixel();
592 texture
= &(screen
->getWindowStyle()->l_unfocus
);
593 frame
.ulabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.ulabel
);
595 frame
.ulabel_pixel
= texture
->color().pixel();
599 void BlackboxWindow::createHandle(void) {
600 frame
.handle
= createChildWindow(frame
.window
);
601 blackbox
->saveWindowSearch(frame
.handle
, this);
604 createChildWindow(frame
.handle
, blackbox
->getLowerLeftAngleCursor());
605 blackbox
->saveWindowSearch(frame
.left_grip
, this);
608 createChildWindow(frame
.handle
, blackbox
->getLowerRightAngleCursor());
609 blackbox
->saveWindowSearch(frame
.right_grip
, this);
613 void BlackboxWindow::destroyHandle(void) {
615 screen
->getImageControl()->removeImage(frame
.fhandle
);
618 screen
->getImageControl()->removeImage(frame
.uhandle
);
621 screen
->getImageControl()->removeImage(frame
.fgrip
);
624 screen
->getImageControl()->removeImage(frame
.ugrip
);
626 blackbox
->removeWindowSearch(frame
.left_grip
);
627 blackbox
->removeWindowSearch(frame
.right_grip
);
629 XDestroyWindow(blackbox
->getXDisplay(), frame
.left_grip
);
630 XDestroyWindow(blackbox
->getXDisplay(), frame
.right_grip
);
631 frame
.left_grip
= frame
.right_grip
= None
;
633 blackbox
->removeWindowSearch(frame
.handle
);
634 XDestroyWindow(blackbox
->getXDisplay(), frame
.handle
);
639 void BlackboxWindow::createTitlebar(void) {
640 frame
.title
= createChildWindow(frame
.window
);
641 frame
.label
= createChildWindow(frame
.title
);
642 blackbox
->saveWindowSearch(frame
.title
, this);
643 blackbox
->saveWindowSearch(frame
.label
, this);
645 if (decorations
& Decor_Iconify
) createIconifyButton();
646 if (decorations
& Decor_Maximize
) createMaximizeButton();
647 if (decorations
& Decor_Close
) createCloseButton();
651 void BlackboxWindow::destroyTitlebar(void) {
652 if (frame
.close_button
)
653 destroyCloseButton();
655 if (frame
.iconify_button
)
656 destroyIconifyButton();
658 if (frame
.maximize_button
)
659 destroyMaximizeButton();
662 screen
->getImageControl()->removeImage(frame
.ftitle
);
665 screen
->getImageControl()->removeImage(frame
.utitle
);
668 screen
->getImageControl()->removeImage(frame
.flabel
);
671 screen
->getImageControl()->removeImage(frame
.ulabel
);
674 screen
->getImageControl()->removeImage(frame
.fbutton
);
677 screen
->getImageControl()->removeImage(frame
.ubutton
);
680 screen
->getImageControl()->removeImage(frame
.pbutton
);
682 blackbox
->removeWindowSearch(frame
.title
);
683 blackbox
->removeWindowSearch(frame
.label
);
685 XDestroyWindow(blackbox
->getXDisplay(), frame
.label
);
686 XDestroyWindow(blackbox
->getXDisplay(), frame
.title
);
687 frame
.title
= frame
.label
= None
;
691 void BlackboxWindow::createCloseButton(void) {
692 if (frame
.title
!= None
) {
693 frame
.close_button
= createChildWindow(frame
.title
);
694 blackbox
->saveWindowSearch(frame
.close_button
, this);
699 void BlackboxWindow::destroyCloseButton(void) {
700 blackbox
->removeWindowSearch(frame
.close_button
);
701 XDestroyWindow(blackbox
->getXDisplay(), frame
.close_button
);
702 frame
.close_button
= None
;
706 void BlackboxWindow::createIconifyButton(void) {
707 if (frame
.title
!= None
) {
708 frame
.iconify_button
= createChildWindow(frame
.title
);
709 blackbox
->saveWindowSearch(frame
.iconify_button
, this);
714 void BlackboxWindow::destroyIconifyButton(void) {
715 blackbox
->removeWindowSearch(frame
.iconify_button
);
716 XDestroyWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
717 frame
.iconify_button
= None
;
721 void BlackboxWindow::createMaximizeButton(void) {
722 if (frame
.title
!= None
) {
723 frame
.maximize_button
= createChildWindow(frame
.title
);
724 blackbox
->saveWindowSearch(frame
.maximize_button
, this);
729 void BlackboxWindow::destroyMaximizeButton(void) {
730 blackbox
->removeWindowSearch(frame
.maximize_button
);
731 XDestroyWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
732 frame
.maximize_button
= None
;
736 void BlackboxWindow::positionButtons(bool redecorate_label
) {
737 string layout
= blackbox
->getTitlebarLayout();
740 bool hasclose
, hasiconify
, hasmaximize
, haslabel
;
741 hasclose
= hasiconify
= hasmaximize
= haslabel
= false;
743 string::const_iterator it
, end
;
744 for (it
= layout
.begin(), end
= layout
.end(); it
!= end
; ++it
) {
747 if (! hasclose
&& (decorations
& Decor_Close
)) {
753 if (! hasiconify
&& (decorations
& Decor_Iconify
)) {
759 if (! hasmaximize
&& (decorations
& Decor_Maximize
)) {
771 if (! hasclose
&& frame
.close_button
)
772 destroyCloseButton();
773 if (! hasiconify
&& frame
.iconify_button
)
774 destroyIconifyButton();
775 if (! hasmaximize
&& frame
.maximize_button
)
776 destroyMaximizeButton();
778 parsed
+= 'L'; // require that the label be in the layout
780 const unsigned int bsep
= frame
.bevel_w
+ 1; // separation between elements
781 const unsigned int by
= frame
.bevel_w
+ 1;
782 const unsigned int ty
= frame
.bevel_w
;
784 frame
.label_w
= frame
.inside_w
- bsep
* 2 -
785 (frame
.button_w
+ bsep
) * (parsed
.size() - 1);
787 unsigned int x
= bsep
;
788 for (it
= parsed
.begin(), end
= parsed
.end(); it
!= end
; ++it
) {
791 if (! frame
.close_button
) createCloseButton();
792 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.close_button
, x
, by
,
793 frame
.button_w
, frame
.button_w
);
794 x
+= frame
.button_w
+ bsep
;
797 if (! frame
.iconify_button
) createIconifyButton();
798 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.iconify_button
, x
, by
,
799 frame
.button_w
, frame
.button_w
);
800 x
+= frame
.button_w
+ bsep
;
803 if (! frame
.maximize_button
) createMaximizeButton();
804 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.maximize_button
, x
, by
,
805 frame
.button_w
, frame
.button_w
);
806 x
+= frame
.button_w
+ bsep
;
809 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.label
, x
, ty
,
810 frame
.label_w
, frame
.label_h
);
811 x
+= frame
.label_w
+ bsep
;
816 if (redecorate_label
) decorateLabel();
822 void BlackboxWindow::reconfigure(void) {
825 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
826 frame
.rect
.top() + frame
.margin
.top
);
833 configure(frame
.rect
.x(), frame
.rect
.y(),
834 frame
.rect
.width(), frame
.rect
.height());
837 windowmenu
->move(windowmenu
->getX(), frame
.rect
.y() + frame
.title_h
);
838 windowmenu
->reconfigure();
843 void BlackboxWindow::positionWindows(void) {
844 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.window
,
845 frame
.rect
.x(), frame
.rect
.y(), frame
.inside_w
,
846 (flags
.shaded
) ? frame
.title_h
: frame
.inside_h
);
847 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.window
,
849 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.plate
,
851 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.plate
,
852 frame
.margin
.left
- frame
.mwm_border_w
- frame
.border_w
,
853 frame
.margin
.top
- frame
.mwm_border_w
- frame
.border_w
,
854 client
.rect
.width(), client
.rect
.height());
855 XMoveResizeWindow(blackbox
->getXDisplay(), client
.window
,
856 0, 0, client
.rect
.width(), client
.rect
.height());
858 if (decorations
& Decor_Titlebar
) {
859 if (frame
.title
== None
) createTitlebar();
861 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.title
,
863 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.title
, -frame
.border_w
,
864 -frame
.border_w
, frame
.inside_w
, frame
.title_h
);
867 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
868 XMapWindow(blackbox
->getXDisplay(), frame
.title
);
869 } else if (frame
.title
) {
872 if (decorations
& Decor_Handle
) {
873 if (frame
.handle
== None
) createHandle();
874 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.handle
,
876 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.left_grip
,
878 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.right_grip
,
881 // use client.rect here so the value is correct even if shaded
882 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.handle
,
884 client
.rect
.height() + frame
.margin
.top
+
885 frame
.mwm_border_w
- frame
.border_w
,
886 frame
.inside_w
, frame
.handle_h
);
887 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.left_grip
,
888 -frame
.border_w
, -frame
.border_w
,
889 frame
.grip_w
, frame
.handle_h
);
890 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.right_grip
,
891 frame
.inside_w
- frame
.grip_w
- frame
.border_w
,
892 -frame
.border_w
, frame
.grip_w
, frame
.handle_h
);
894 XMapSubwindows(blackbox
->getXDisplay(), frame
.handle
);
895 XMapWindow(blackbox
->getXDisplay(), frame
.handle
);
896 } else if (frame
.handle
) {
902 void BlackboxWindow::updateStrut(void) {
903 unsigned long num
= 4;
905 if (! xatom
->getValue(client
.window
, XAtom::net_wm_strut
, XAtom::cardinal
,
910 client
.strut
.left
= data
[0];
911 client
.strut
.right
= data
[1];
912 client
.strut
.top
= data
[2];
913 client
.strut
.bottom
= data
[3];
915 screen
->updateAvailableArea();
922 void BlackboxWindow::getWindowType(void) {
924 if (xatom
->getValue(client
.window
, XAtom::net_wm_window_type
, XAtom::atom
,
926 if (val
== xatom
->getAtom(XAtom::net_wm_window_type_desktop
))
927 window_type
= Type_Desktop
;
928 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_dock
))
929 window_type
= Type_Dock
;
930 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_toolbar
))
931 window_type
= Type_Toolbar
;
932 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_menu
))
933 window_type
= Type_Menu
;
934 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_utility
))
935 window_type
= Type_Utility
;
936 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_splash
))
937 window_type
= Type_Splash
;
938 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_dialog
))
939 window_type
= Type_Dialog
;
940 else //if (val[0] == xatom->getAtom(XAtom::net_wm_window_type_normal))
941 window_type
= Type_Normal
;
946 * the window type hint was not set, which means we either classify ourself
947 * as a normal window or a dialog, depending on if we are a transient.
950 window_type
= Type_Dialog
;
952 window_type
= Type_Normal
;
956 void BlackboxWindow::getWMName(void) {
957 if (xatom
->getValue(client
.window
, XAtom::net_wm_name
,
958 XAtom::utf8
, client
.title
) &&
959 !client
.title
.empty()) {
960 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
963 //fall through to using WM_NAME
964 if (xatom
->getValue(client
.window
, XAtom::wm_name
, XAtom::ansi
, client
.title
)
965 && !client
.title
.empty()) {
966 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
969 // fall back to an internal default
970 client
.title
= i18n(WindowSet
, WindowUnnamed
, "Unnamed");
971 xatom
->setValue(client
.window
, XAtom::net_wm_visible_name
, XAtom::utf8
,
976 void BlackboxWindow::getWMIconName(void) {
977 if (xatom
->getValue(client
.window
, XAtom::net_wm_icon_name
,
978 XAtom::utf8
, client
.icon_title
) &&
979 !client
.icon_title
.empty()) {
980 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
983 //fall through to using WM_ICON_NAME
984 if (xatom
->getValue(client
.window
, XAtom::wm_icon_name
, XAtom::ansi
,
985 client
.icon_title
) &&
986 !client
.icon_title
.empty()) {
987 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
990 // fall back to using the main name
991 client
.icon_title
= client
.title
;
992 xatom
->setValue(client
.window
, XAtom::net_wm_visible_icon_name
, XAtom::utf8
,
998 * Retrieve which WM Protocols are supported by the client window.
999 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
1000 * window's decorations and allow the close behavior.
1001 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
1004 void BlackboxWindow::getWMProtocols(void) {
1008 if (XGetWMProtocols(blackbox
->getXDisplay(), client
.window
,
1009 &proto
, &num_return
)) {
1010 for (int i
= 0; i
< num_return
; ++i
) {
1011 if (proto
[i
] == xatom
->getAtom(XAtom::wm_delete_window
)) {
1012 decorations
|= Decor_Close
;
1013 functions
|= Func_Close
;
1014 } else if (proto
[i
] == xatom
->getAtom(XAtom::wm_take_focus
))
1015 flags
.send_focus_message
= True
;
1016 else if (proto
[i
] == xatom
->getAtom(XAtom::blackbox_structure_messages
))
1017 screen
->addNetizen(new Netizen(screen
, client
.window
));
1026 * Gets the value of the WM_HINTS property.
1027 * If the property is not set, then use a set of default values.
1029 void BlackboxWindow::getWMHints(void) {
1030 focus_mode
= F_Passive
;
1031 client
.initial_state
= NormalState
;
1033 // remove from current window group
1034 if (client
.window_group
) {
1035 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1036 if (group
) group
->removeWindow(this);
1038 client
.window_group
= None
;
1040 XWMHints
*wmhint
= XGetWMHints(blackbox
->getXDisplay(), client
.window
);
1045 if (wmhint
->flags
& InputHint
) {
1046 if (wmhint
->input
== True
) {
1047 if (flags
.send_focus_message
)
1048 focus_mode
= F_LocallyActive
;
1050 if (flags
.send_focus_message
)
1051 focus_mode
= F_GloballyActive
;
1053 focus_mode
= F_NoInput
;
1057 if (wmhint
->flags
& StateHint
)
1058 client
.initial_state
= wmhint
->initial_state
;
1060 if (wmhint
->flags
& WindowGroupHint
) {
1061 client
.window_group
= wmhint
->window_group
;
1063 // add window to the appropriate group
1064 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1065 if (! group
) // no group found, create it!
1066 group
= new BWindowGroup(blackbox
, client
.window_group
);
1067 group
->addWindow(this);
1070 client
.wm_hint_flags
= wmhint
->flags
;
1076 * Gets the value of the WM_NORMAL_HINTS property.
1077 * If the property is not set, then use a set of default values.
1079 void BlackboxWindow::getWMNormalHints(void) {
1081 XSizeHints sizehint
;
1083 client
.min_width
= client
.min_height
=
1084 client
.width_inc
= client
.height_inc
= 1;
1085 client
.base_width
= client
.base_height
= 0;
1088 use the full screen, not the strut modified size. otherwise when the
1089 availableArea changes max_width/height will be incorrect and lead to odd
1092 const Rect
& screen_area
= screen
->getRect();
1093 client
.max_width
= screen_area
.width();
1095 client
.max_height
= screen_area
.height();
1096 client
.min_aspect_x
= client
.min_aspect_y
=
1097 client
.max_aspect_x
= client
.max_aspect_y
= 1;
1098 client
.win_gravity
= NorthWestGravity
;
1100 if (! XGetWMNormalHints(blackbox
->getXDisplay(), client
.window
,
1101 &sizehint
, &icccm_mask
))
1104 client
.normal_hint_flags
= sizehint
.flags
;
1106 if (sizehint
.flags
& PMinSize
) {
1107 client
.min_width
= sizehint
.min_width
;
1108 client
.min_height
= sizehint
.min_height
;
1111 if (sizehint
.flags
& PMaxSize
) {
1112 client
.max_width
= sizehint
.max_width
;
1113 client
.max_height
= sizehint
.max_height
;
1116 if (sizehint
.flags
& PResizeInc
) {
1117 client
.width_inc
= sizehint
.width_inc
;
1118 client
.height_inc
= sizehint
.height_inc
;
1121 if (sizehint
.flags
& PAspect
) {
1122 client
.min_aspect_x
= sizehint
.min_aspect
.x
;
1123 client
.min_aspect_y
= sizehint
.min_aspect
.y
;
1124 client
.max_aspect_x
= sizehint
.max_aspect
.x
;
1125 client
.max_aspect_y
= sizehint
.max_aspect
.y
;
1128 if (sizehint
.flags
& PBaseSize
) {
1129 client
.base_width
= sizehint
.base_width
;
1130 client
.base_height
= sizehint
.base_height
;
1133 if (sizehint
.flags
& PWinGravity
)
1134 client
.win_gravity
= sizehint
.win_gravity
;
1139 * Gets the NETWM hints for the class' contained window.
1141 void BlackboxWindow::getNetWMHints(void) {
1142 unsigned long workspace
;
1144 if (xatom
->getValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1146 if (workspace
== 0xffffffff)
1149 blackbox_attrib
.workspace
= workspace
;
1152 unsigned long *state
;
1153 unsigned long num
= (unsigned) -1;
1154 if (xatom
->getValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
1158 for (unsigned long i
= 0; i
< num
; ++i
) {
1159 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
))
1161 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_shaded
))
1162 flags
.shaded
= True
;
1163 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
))
1164 flags
.skip_taskbar
= True
;
1165 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_pager
))
1166 flags
.skip_pager
= True
;
1167 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_fullscreen
))
1168 flags
.fullscreen
= True
;
1169 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_hidden
))
1170 setState(IconicState
);
1171 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_vert
))
1173 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_horz
))
1177 flags
.maximized
= 1;
1179 flags
.maximized
= 2;
1181 flags
.maximized
= 3;
1189 * Gets the MWM hints for the class' contained window.
1190 * This is used while initializing the window to its first state, and not
1192 * Returns: true if the MWM hints are successfully retreived and applied;
1193 * false if they are not.
1195 void BlackboxWindow::getMWMHints(void) {
1199 num
= PropMwmHintsElements
;
1200 if (! xatom
->getValue(client
.window
, XAtom::motif_wm_hints
,
1201 XAtom::motif_wm_hints
, num
,
1202 (unsigned long **)&mwm_hint
) ||
1203 num
< PropMwmHintsElements
)
1206 if (mwm_hint
->flags
& MwmHintsDecorations
) {
1207 if (mwm_hint
->decorations
& MwmDecorAll
) {
1208 decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
1209 Decor_Iconify
| Decor_Maximize
| Decor_Close
;
1213 if (mwm_hint
->decorations
& MwmDecorBorder
)
1214 decorations
|= Decor_Border
;
1215 if (mwm_hint
->decorations
& MwmDecorHandle
)
1216 decorations
|= Decor_Handle
;
1217 if (mwm_hint
->decorations
& MwmDecorTitle
)
1218 decorations
|= Decor_Titlebar
;
1219 if (mwm_hint
->decorations
& MwmDecorIconify
)
1220 decorations
|= Decor_Iconify
;
1221 if (mwm_hint
->decorations
& MwmDecorMaximize
)
1222 decorations
|= Decor_Maximize
;
1226 if (mwm_hint
->flags
& MwmHintsFunctions
) {
1227 if (mwm_hint
->functions
& MwmFuncAll
) {
1228 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
|
1233 if (mwm_hint
->functions
& MwmFuncResize
)
1234 functions
|= Func_Resize
;
1235 if (mwm_hint
->functions
& MwmFuncMove
)
1236 functions
|= Func_Move
;
1237 if (mwm_hint
->functions
& MwmFuncIconify
)
1238 functions
|= Func_Iconify
;
1239 if (mwm_hint
->functions
& MwmFuncMaximize
)
1240 functions
|= Func_Maximize
;
1241 if (mwm_hint
->functions
& MwmFuncClose
)
1242 functions
|= Func_Close
;
1250 * Gets the blackbox hints from the class' contained window.
1251 * This is used while initializing the window to its first state, and not
1253 * Returns: true if the hints are successfully retreived and applied; false if
1256 bool BlackboxWindow::getBlackboxHints(void) {
1258 BlackboxHints
*blackbox_hint
;
1260 num
= PropBlackboxHintsElements
;
1261 if (! xatom
->getValue(client
.window
, XAtom::blackbox_hints
,
1262 XAtom::blackbox_hints
, num
,
1263 (unsigned long **)&blackbox_hint
) ||
1264 num
< PropBlackboxHintsElements
)
1267 if (blackbox_hint
->flags
& AttribShaded
)
1268 flags
.shaded
= (blackbox_hint
->attrib
& AttribShaded
);
1270 if ((blackbox_hint
->flags
& AttribMaxHoriz
) &&
1271 (blackbox_hint
->flags
& AttribMaxVert
))
1272 flags
.maximized
= (blackbox_hint
->attrib
&
1273 (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1274 else if (blackbox_hint
->flags
& AttribMaxVert
)
1275 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxVert
) ? 2 : 0;
1276 else if (blackbox_hint
->flags
& AttribMaxHoriz
)
1277 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1279 if (blackbox_hint
->flags
& AttribOmnipresent
)
1280 flags
.stuck
= (blackbox_hint
->attrib
& AttribOmnipresent
);
1282 if (blackbox_hint
->flags
& AttribWorkspace
)
1283 blackbox_attrib
.workspace
= blackbox_hint
->workspace
;
1285 // if (blackbox_hint->flags & AttribStack)
1286 // don't yet have always on top/bottom for blackbox yet... working
1289 if (blackbox_hint
->flags
& AttribDecoration
) {
1290 switch (blackbox_hint
->decoration
) {
1292 // clear all decorations except close
1293 decorations
&= Decor_Close
;
1294 // clear all functions except close
1295 functions
&= Func_Close
;
1300 decorations
|= Decor_Titlebar
| Decor_Iconify
;
1301 decorations
&= ~(Decor_Border
| Decor_Handle
| Decor_Maximize
);
1302 functions
|= Func_Move
| Func_Iconify
;
1303 functions
&= ~(Func_Resize
| Func_Maximize
);
1308 decorations
|= Decor_Titlebar
;
1309 decorations
&= ~(Decor_Iconify
| Decor_Border
| Decor_Handle
);
1310 functions
|= Func_Move
;
1311 functions
&= ~(Func_Resize
| Func_Maximize
| Func_Iconify
);
1317 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Handle
|
1318 Decor_Iconify
| Decor_Maximize
;
1319 functions
|= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
1327 delete blackbox_hint
;
1333 void BlackboxWindow::getTransientInfo(void) {
1334 if (client
.transient_for
&&
1335 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1336 // the transient for hint was removed, so we need to tell our
1337 // previous transient_for that we are going away
1338 client
.transient_for
->client
.transientList
.remove(this);
1341 // we have no transient_for until we find a new one
1342 client
.transient_for
= 0;
1345 if (! XGetTransientForHint(blackbox
->getXDisplay(), client
.window
,
1347 // transient_for hint not set
1351 if (trans_for
== client
.window
) {
1352 // wierd client... treat this window as a normal window
1356 if (trans_for
== None
|| trans_for
== screen
->getRootWindow()) {
1357 // this is an undocumented interpretation of the ICCCM. a transient
1358 // associated with None/Root/itself is assumed to be a modal root
1359 // transient. we don't support the concept of a global transient,
1360 // so we just associate this transient with nothing, and perhaps
1361 // we will add support later for global modality.
1362 client
.transient_for
= (BlackboxWindow
*) ~0ul;
1367 client
.transient_for
= blackbox
->searchWindow(trans_for
);
1368 if (! client
.transient_for
&&
1369 client
.window_group
&& trans_for
== client
.window_group
) {
1370 // no direct transient_for, perhaps this is a group transient?
1371 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1372 if (group
) client
.transient_for
= group
->find(screen
);
1375 if (! client
.transient_for
|| client
.transient_for
== this) {
1376 // no transient_for found, or we have a wierd client that wants to be
1377 // a transient for itself, so we treat this window as a normal window
1378 client
.transient_for
= (BlackboxWindow
*) 0;
1382 // register ourselves with our new transient_for
1383 client
.transient_for
->client
.transientList
.push_back(this);
1384 flags
.stuck
= client
.transient_for
->flags
.stuck
;
1388 bool BlackboxWindow::isKDESystrayWindow(void) {
1390 if (xatom
->getValue(client
.window
, XAtom::kde_net_wm_system_tray_window_for
,
1391 XAtom::window
, systray
) && systray
)
1397 BlackboxWindow
*BlackboxWindow::getTransientFor(void) const {
1398 if (client
.transient_for
&&
1399 client
.transient_for
!= (BlackboxWindow
*) ~0ul)
1400 return client
.transient_for
;
1405 void BlackboxWindow::configure(int dx
, int dy
,
1406 unsigned int dw
, unsigned int dh
) {
1407 bool send_event
= False
;
1409 if (dw
!= frame
.rect
.width() || dh
!= frame
.rect
.height()) {
1410 frame
.rect
.setRect(dx
, dy
, dw
, dh
);
1411 frame
.inside_w
= frame
.rect
.width() - (frame
.border_w
* 2);
1412 frame
.inside_h
= frame
.rect
.height() - (frame
.border_w
* 2);
1414 if (frame
.rect
.right() <= 0 || frame
.rect
.bottom() <= 0)
1415 frame
.rect
.setPos(0, 0);
1417 client
.rect
.setCoords(frame
.rect
.left() + frame
.margin
.left
,
1418 frame
.rect
.top() + frame
.margin
.top
,
1419 frame
.rect
.right() - frame
.margin
.right
,
1420 frame
.rect
.bottom() - frame
.margin
.bottom
);
1423 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
1430 redrawWindowFrame();
1431 } else if (frame
.rect
.x() != dx
|| frame
.rect
.y() != dy
) {
1434 frame
.rect
.setPos(dx
, dy
);
1436 XMoveWindow(blackbox
->getXDisplay(), frame
.window
,
1437 frame
.rect
.x(), frame
.rect
.y());
1440 if (send_event
&& ! flags
.moving
) {
1441 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1442 frame
.rect
.top() + frame
.margin
.top
);
1445 event
.type
= ConfigureNotify
;
1447 event
.xconfigure
.display
= blackbox
->getXDisplay();
1448 event
.xconfigure
.event
= client
.window
;
1449 event
.xconfigure
.window
= client
.window
;
1450 event
.xconfigure
.x
= client
.rect
.x();
1451 event
.xconfigure
.y
= client
.rect
.y();
1452 event
.xconfigure
.width
= client
.rect
.width();
1453 event
.xconfigure
.height
= client
.rect
.height();
1454 event
.xconfigure
.border_width
= client
.old_bw
;
1455 event
.xconfigure
.above
= frame
.window
;
1456 event
.xconfigure
.override_redirect
= False
;
1458 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1459 StructureNotifyMask
, &event
);
1461 screen
->updateNetizenConfigNotify(&event
);
1467 void BlackboxWindow::configureShape(void) {
1468 XShapeCombineShape(blackbox
->getXDisplay(), frame
.window
, ShapeBounding
,
1469 frame
.margin
.left
- frame
.border_w
,
1470 frame
.margin
.top
- frame
.border_w
,
1471 client
.window
, ShapeBounding
, ShapeSet
);
1474 XRectangle xrect
[2];
1476 if (decorations
& Decor_Titlebar
) {
1477 xrect
[0].x
= xrect
[0].y
= -frame
.border_w
;
1478 xrect
[0].width
= frame
.rect
.width();
1479 xrect
[0].height
= frame
.title_h
+ (frame
.border_w
* 2);
1483 if (decorations
& Decor_Handle
) {
1484 xrect
[1].x
= -frame
.border_w
;
1485 xrect
[1].y
= frame
.rect
.height() - frame
.margin
.bottom
+
1486 frame
.mwm_border_w
- frame
.border_w
;
1487 xrect
[1].width
= frame
.rect
.width();
1488 xrect
[1].height
= frame
.handle_h
+ (frame
.border_w
* 2);
1492 XShapeCombineRectangles(blackbox
->getXDisplay(), frame
.window
,
1493 ShapeBounding
, 0, 0, xrect
, num
,
1494 ShapeUnion
, Unsorted
);
1499 bool BlackboxWindow::setInputFocus(void) {
1500 if (flags
.focused
) return True
;
1502 assert(! flags
.iconic
);
1504 // if the window is not visible, mark the window as wanting focus rather
1505 // than give it focus.
1506 if (! flags
.visible
) {
1507 Workspace
*wkspc
= screen
->getWorkspace(blackbox_attrib
.workspace
);
1508 wkspc
->setLastFocusedWindow(this);
1512 if (! frame
.rect
.intersects(screen
->getRect())) {
1513 // client is outside the screen, move it to the center
1514 configure((screen
->getWidth() - frame
.rect
.width()) / 2,
1515 (screen
->getHeight() - frame
.rect
.height()) / 2,
1516 frame
.rect
.width(), frame
.rect
.height());
1519 if (client
.transientList
.size() > 0) {
1520 // transfer focus to any modal transients
1521 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1522 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1523 if ((*it
)->flags
.modal
) return (*it
)->setInputFocus();
1528 if (focus_mode
== F_LocallyActive
|| focus_mode
== F_Passive
) {
1529 XSetInputFocus(blackbox
->getXDisplay(), client
.window
,
1530 RevertToPointerRoot
, CurrentTime
);
1532 blackbox
->setFocusedWindow(this);
1534 /* we could set the focus to none, since the window doesn't accept focus,
1535 * but we shouldn't set focus to nothing since this would surely make
1541 if (flags
.send_focus_message
) {
1543 ce
.xclient
.type
= ClientMessage
;
1544 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1545 ce
.xclient
.display
= blackbox
->getXDisplay();
1546 ce
.xclient
.window
= client
.window
;
1547 ce
.xclient
.format
= 32;
1548 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_take_focus
);
1549 ce
.xclient
.data
.l
[1] = blackbox
->getLastTime();
1550 ce
.xclient
.data
.l
[2] = 0l;
1551 ce
.xclient
.data
.l
[3] = 0l;
1552 ce
.xclient
.data
.l
[4] = 0l;
1553 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1561 void BlackboxWindow::iconify(void) {
1562 if (flags
.iconic
) return;
1564 // We don't need to worry about resizing because resizing always grabs the X
1565 // server. This should only ever happen if using opaque moving.
1569 if (windowmenu
) windowmenu
->hide();
1572 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1573 * we need to clear the event mask on client.window for a split second.
1574 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1575 * split second, leaving us with a ghost window... so, we need to do this
1576 * while the X server is grabbed
1578 XGrabServer(blackbox
->getXDisplay());
1579 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
1580 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1581 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1582 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
1583 XUngrabServer(blackbox
->getXDisplay());
1585 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1586 flags
.visible
= False
;
1587 flags
.iconic
= True
;
1589 setState(IconicState
);
1591 screen
->getWorkspace(blackbox_attrib
.workspace
)->removeWindow(this);
1593 if (isTransient()) {
1594 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1595 ! client
.transient_for
->flags
.iconic
) {
1596 // iconify our transient_for
1597 client
.transient_for
->iconify();
1601 screen
->addIcon(this);
1603 if (client
.transientList
.size() > 0) {
1604 // iconify all transients
1605 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1606 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1607 if (! (*it
)->flags
.iconic
) (*it
)->iconify();
1613 void BlackboxWindow::show(void) {
1614 flags
.visible
= True
;
1615 flags
.iconic
= False
;
1617 current_state
= (flags
.shaded
) ? IconicState
: NormalState
;
1618 setState(current_state
);
1620 XMapWindow(blackbox
->getXDisplay(), client
.window
);
1621 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
1622 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
1626 void BlackboxWindow::deiconify(bool reassoc
, bool doraise
) {
1627 if (flags
.iconic
|| reassoc
)
1628 screen
->reassociateWindow(this, BSENTINEL
, False
);
1629 else if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspace()->getID())
1634 // reassociate and deiconify all transients
1635 if (reassoc
&& client
.transientList
.size() > 0) {
1636 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1637 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1638 (*it
)->deiconify(True
, False
);
1647 void BlackboxWindow::raise(void) {
1648 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1652 void BlackboxWindow::lower(void) {
1653 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
1657 void BlackboxWindow::close(void) {
1659 ce
.xclient
.type
= ClientMessage
;
1660 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1661 ce
.xclient
.display
= blackbox
->getXDisplay();
1662 ce
.xclient
.window
= client
.window
;
1663 ce
.xclient
.format
= 32;
1664 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_delete_window
);
1665 ce
.xclient
.data
.l
[1] = CurrentTime
;
1666 ce
.xclient
.data
.l
[2] = 0l;
1667 ce
.xclient
.data
.l
[3] = 0l;
1668 ce
.xclient
.data
.l
[4] = 0l;
1669 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
, NoEventMask
, &ce
);
1673 void BlackboxWindow::withdraw(void) {
1674 // We don't need to worry about resizing because resizing always grabs the X
1675 // server. This should only ever happen if using opaque moving.
1679 flags
.visible
= False
;
1680 flags
.iconic
= False
;
1682 setState(current_state
);
1684 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1686 XGrabServer(blackbox
->getXDisplay());
1688 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
1689 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1690 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1691 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
1693 XUngrabServer(blackbox
->getXDisplay());
1695 if (windowmenu
) windowmenu
->hide();
1699 void BlackboxWindow::maximize(unsigned int button
) {
1700 // We don't need to worry about resizing because resizing always grabs the X
1701 // server. This should only ever happen if using opaque moving.
1705 // handle case where menu is open then the max button is used instead
1706 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
1708 if (flags
.maximized
) {
1709 flags
.maximized
= 0;
1711 blackbox_attrib
.flags
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1712 blackbox_attrib
.attrib
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1715 when a resize finishes, maximize(0) is called to clear any maximization
1716 flags currently set. Otherwise it still thinks it is maximized.
1717 so we do not need to call configure() because resizing will handle it
1719 if (! flags
.resizing
)
1720 configure(blackbox_attrib
.premax_x
, blackbox_attrib
.premax_y
,
1721 blackbox_attrib
.premax_w
, blackbox_attrib
.premax_h
);
1723 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
1724 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
1726 redrawAllButtons(); // in case it is not called in configure()
1727 setState(current_state
);
1731 blackbox_attrib
.premax_x
= frame
.rect
.x();
1732 blackbox_attrib
.premax_y
= frame
.rect
.y();
1733 blackbox_attrib
.premax_w
= frame
.rect
.width();
1734 // use client.rect so that clients can be restored even if shaded
1735 blackbox_attrib
.premax_h
=
1736 client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
;
1738 const Rect
&screen_area
= screen
->availableArea();
1739 frame
.changing
= screen_area
;
1743 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1744 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1748 blackbox_attrib
.flags
|= AttribMaxVert
;
1749 blackbox_attrib
.attrib
|= AttribMaxVert
;
1751 frame
.changing
.setX(frame
.rect
.x());
1752 frame
.changing
.setWidth(frame
.rect
.width());
1756 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1757 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1759 frame
.changing
.setY(frame
.rect
.y());
1760 frame
.changing
.setHeight(frame
.rect
.height());
1767 blackbox_attrib
.flags
^= AttribShaded
;
1768 blackbox_attrib
.attrib
^= AttribShaded
;
1769 flags
.shaded
= False
;
1772 flags
.maximized
= button
;
1774 configure(frame
.changing
.x(), frame
.changing
.y(),
1775 frame
.changing
.width(), frame
.changing
.height());
1778 redrawAllButtons(); // in case it is not called in configure()
1779 setState(current_state
);
1783 // re-maximizes the window to take into account availableArea changes
1784 void BlackboxWindow::remaximize(void) {
1785 // save the original dimensions because maximize will wipe them out
1786 int premax_x
= blackbox_attrib
.premax_x
,
1787 premax_y
= blackbox_attrib
.premax_y
,
1788 premax_w
= blackbox_attrib
.premax_w
,
1789 premax_h
= blackbox_attrib
.premax_h
;
1791 unsigned int button
= flags
.maximized
;
1792 flags
.maximized
= 0; // trick maximize() into working
1795 // restore saved values
1796 blackbox_attrib
.premax_x
= premax_x
;
1797 blackbox_attrib
.premax_y
= premax_y
;
1798 blackbox_attrib
.premax_w
= premax_w
;
1799 blackbox_attrib
.premax_h
= premax_h
;
1803 void BlackboxWindow::setWorkspace(unsigned int n
) {
1804 blackbox_attrib
.flags
|= AttribWorkspace
;
1805 blackbox_attrib
.workspace
= n
;
1806 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
, n
);
1810 void BlackboxWindow::shade(void) {
1812 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1813 frame
.inside_w
, frame
.inside_h
);
1814 flags
.shaded
= False
;
1815 blackbox_attrib
.flags
^= AttribShaded
;
1816 blackbox_attrib
.attrib
^= AttribShaded
;
1818 setState(NormalState
);
1820 // set the frame rect to the normal size
1821 frame
.rect
.setHeight(client
.rect
.height() + frame
.margin
.top
+
1822 frame
.margin
.bottom
);
1824 if (! (decorations
& Decor_Titlebar
))
1825 return; // can't shade it without a titlebar!
1827 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1828 frame
.inside_w
, frame
.title_h
);
1829 flags
.shaded
= True
;
1830 blackbox_attrib
.flags
|= AttribShaded
;
1831 blackbox_attrib
.attrib
|= AttribShaded
;
1833 setState(IconicState
);
1835 // set the frame rect to the shaded size
1836 frame
.rect
.setHeight(frame
.title_h
+ (frame
.border_w
* 2));
1842 * (Un)Sticks a window and its relatives.
1844 void BlackboxWindow::stick(void) {
1846 blackbox_attrib
.flags
^= AttribOmnipresent
;
1847 blackbox_attrib
.attrib
^= AttribOmnipresent
;
1849 flags
.stuck
= False
;
1852 screen
->reassociateWindow(this, BSENTINEL
, True
);
1854 // temporary fix since sticky windows suck. set the hint to what we
1855 // actually hold in our data.
1856 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1857 blackbox_attrib
.workspace
);
1859 setState(current_state
);
1863 blackbox_attrib
.flags
|= AttribOmnipresent
;
1864 blackbox_attrib
.attrib
|= AttribOmnipresent
;
1866 // temporary fix since sticky windows suck. set the hint to a different
1867 // value than that contained in the class' data.
1868 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1871 setState(current_state
);
1874 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1875 client
.transient_for
->isStuck() != flags
.stuck
)
1876 client
.transient_for
->stick();
1877 // go down the chain
1878 BlackboxWindowList::iterator it
;
1879 const BlackboxWindowList::iterator end
= client
.transientList
.end();
1880 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1881 if ((*it
)->isStuck() != flags
.stuck
)
1886 void BlackboxWindow::redrawWindowFrame(void) const {
1887 if (decorations
& Decor_Titlebar
) {
1888 if (flags
.focused
) {
1890 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1891 frame
.title
, frame
.ftitle
);
1893 XSetWindowBackground(blackbox
->getXDisplay(),
1894 frame
.title
, frame
.ftitle_pixel
);
1897 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1898 frame
.title
, frame
.utitle
);
1900 XSetWindowBackground(blackbox
->getXDisplay(),
1901 frame
.title
, frame
.utitle_pixel
);
1903 XClearWindow(blackbox
->getXDisplay(), frame
.title
);
1909 if (decorations
& Decor_Handle
) {
1910 if (flags
.focused
) {
1912 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1913 frame
.handle
, frame
.fhandle
);
1915 XSetWindowBackground(blackbox
->getXDisplay(),
1916 frame
.handle
, frame
.fhandle_pixel
);
1919 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1920 frame
.left_grip
, frame
.fgrip
);
1921 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1922 frame
.right_grip
, frame
.fgrip
);
1924 XSetWindowBackground(blackbox
->getXDisplay(),
1925 frame
.left_grip
, frame
.fgrip_pixel
);
1926 XSetWindowBackground(blackbox
->getXDisplay(),
1927 frame
.right_grip
, frame
.fgrip_pixel
);
1931 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1932 frame
.handle
, frame
.uhandle
);
1934 XSetWindowBackground(blackbox
->getXDisplay(),
1935 frame
.handle
, frame
.uhandle_pixel
);
1938 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1939 frame
.left_grip
, frame
.ugrip
);
1940 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1941 frame
.right_grip
, frame
.ugrip
);
1943 XSetWindowBackground(blackbox
->getXDisplay(),
1944 frame
.left_grip
, frame
.ugrip_pixel
);
1945 XSetWindowBackground(blackbox
->getXDisplay(),
1946 frame
.right_grip
, frame
.ugrip_pixel
);
1949 XClearWindow(blackbox
->getXDisplay(), frame
.handle
);
1950 XClearWindow(blackbox
->getXDisplay(), frame
.left_grip
);
1951 XClearWindow(blackbox
->getXDisplay(), frame
.right_grip
);
1954 if (decorations
& Decor_Border
) {
1956 XSetWindowBorder(blackbox
->getXDisplay(),
1957 frame
.plate
, frame
.fborder_pixel
);
1959 XSetWindowBorder(blackbox
->getXDisplay(),
1960 frame
.plate
, frame
.uborder_pixel
);
1965 void BlackboxWindow::setFocusFlag(bool focus
) {
1966 // only focus a window if it is visible
1967 if (focus
&& !flags
.visible
)
1970 flags
.focused
= focus
;
1972 redrawWindowFrame();
1974 if (screen
->isSloppyFocus() && screen
->doAutoRaise()) {
1975 if (isFocused()) timer
->start();
1980 blackbox
->setFocusedWindow(this);
1984 void BlackboxWindow::installColormap(bool install
) {
1985 int i
= 0, ncmap
= 0;
1986 Colormap
*cmaps
= XListInstalledColormaps(blackbox
->getXDisplay(),
1987 client
.window
, &ncmap
);
1989 XWindowAttributes wattrib
;
1990 if (XGetWindowAttributes(blackbox
->getXDisplay(),
1991 client
.window
, &wattrib
)) {
1993 // install the window's colormap
1994 for (i
= 0; i
< ncmap
; i
++) {
1995 if (*(cmaps
+ i
) == wattrib
.colormap
)
1996 // this window is using an installed color map... do not install
1999 // otherwise, install the window's colormap
2001 XInstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2003 // uninstall the window's colormap
2004 for (i
= 0; i
< ncmap
; i
++) {
2005 if (*(cmaps
+ i
) == wattrib
.colormap
)
2006 // we found the colormap to uninstall
2007 XUninstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2017 void BlackboxWindow::setAllowedActions(void) {
2021 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_shade
);
2022 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_change_desktop
);
2023 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_close
);
2025 if (functions
& Func_Move
)
2026 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_move
);
2027 if (functions
& Func_Resize
)
2028 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_resize
);
2029 if (functions
& Func_Maximize
) {
2030 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_horz
);
2031 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_vert
);
2034 xatom
->setValue(client
.window
, XAtom::net_wm_allowed_actions
, XAtom::atom
,
2039 void BlackboxWindow::setState(unsigned long new_state
) {
2040 current_state
= new_state
;
2042 unsigned long state
[2];
2043 state
[0] = current_state
;
2045 xatom
->setValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
, state
, 2);
2047 xatom
->setValue(client
.window
, XAtom::blackbox_attributes
,
2048 XAtom::blackbox_attributes
, (unsigned long *)&blackbox_attrib
,
2049 PropBlackboxAttributesElements
);
2054 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_modal
);
2056 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_shaded
);
2058 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_hidden
);
2059 if (flags
.skip_taskbar
)
2060 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
);
2061 if (flags
.skip_pager
)
2062 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_pager
);
2063 if (flags
.fullscreen
)
2064 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_fullscreen
);
2065 if (flags
.maximized
== 1 || flags
.maximized
== 2)
2066 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_vert
);
2067 if (flags
.maximized
== 1 || flags
.maximized
== 3)
2068 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_horz
);
2069 xatom
->setValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
2074 bool BlackboxWindow::getState(void) {
2075 bool ret
= xatom
->getValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
,
2077 if (! ret
) current_state
= 0;
2082 void BlackboxWindow::restoreAttributes(void) {
2083 unsigned long num
= PropBlackboxAttributesElements
;
2084 BlackboxAttributes
*net
;
2085 if (! xatom
->getValue(client
.window
, XAtom::blackbox_attributes
,
2086 XAtom::blackbox_attributes
, num
,
2087 (unsigned long **)&net
))
2089 if (num
< PropBlackboxAttributesElements
) {
2094 if (net
->flags
& AttribShaded
&& net
->attrib
& AttribShaded
) {
2095 flags
.shaded
= False
;
2099 Because the iconic'ness of shaded windows is lost, we need to set the
2100 state to NormalState so that shaded windows on other workspaces will not
2101 get shown on the first workspace.
2102 At this point in the life of a window, current_state should only be set
2103 to IconicState if the window was an *icon*, not if it was shaded.
2105 current_state
= NormalState
;
2108 if ((net
->workspace
!= screen
->getCurrentWorkspaceID()) &&
2109 (net
->workspace
< screen
->getWorkspaceCount()))
2110 screen
->reassociateWindow(this, net
->workspace
, True
);
2112 if ((blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID()) &&
2113 (blackbox_attrib
.workspace
< screen
->getWorkspaceCount())) {
2114 // set to WithdrawnState so it will be mapped on the new workspace
2115 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2116 } else if (current_state
== WithdrawnState
) {
2117 // the window is on this workspace and is Withdrawn, so it is waiting to
2119 current_state
= NormalState
;
2122 if (net
->flags
& AttribOmnipresent
&& net
->attrib
& AttribOmnipresent
) {
2123 flags
.stuck
= False
;
2126 // if the window was on another workspace, it was going to be hidden. this
2127 // specifies that the window should be mapped since it is sticky.
2128 if (current_state
== WithdrawnState
) current_state
= NormalState
;
2131 if (net
->flags
& AttribMaxHoriz
|| net
->flags
& AttribMaxVert
) {
2132 int x
= net
->premax_x
, y
= net
->premax_y
;
2133 unsigned int w
= net
->premax_w
, h
= net
->premax_h
;
2134 flags
.maximized
= 0;
2137 if ((net
->flags
& AttribMaxHoriz
) &&
2138 (net
->flags
& AttribMaxVert
))
2139 m
= (net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
2140 else if (net
->flags
& AttribMaxVert
)
2141 m
= (net
->attrib
& AttribMaxVert
) ? 2 : 0;
2142 else if (net
->flags
& AttribMaxHoriz
)
2143 m
= (net
->attrib
& AttribMaxHoriz
) ? 3 : 0;
2147 blackbox_attrib
.premax_x
= x
;
2148 blackbox_attrib
.premax_y
= y
;
2149 blackbox_attrib
.premax_w
= w
;
2150 blackbox_attrib
.premax_h
= h
;
2153 // with the state set it will then be the map event's job to read the
2154 // window's state and behave accordingly
2161 * Positions the Rect r according the the client window position and
2164 void BlackboxWindow::applyGravity(Rect
&r
) {
2165 // apply horizontal window gravity
2166 switch (client
.win_gravity
) {
2168 case NorthWestGravity
:
2169 case SouthWestGravity
:
2171 r
.setX(client
.rect
.x());
2177 r
.setX(client
.rect
.x() - (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2180 case NorthEastGravity
:
2181 case SouthEastGravity
:
2183 r
.setX(client
.rect
.x() - frame
.margin
.left
- frame
.margin
.right
);
2188 r
.setX(client
.rect
.x() - frame
.margin
.left
);
2192 // apply vertical window gravity
2193 switch (client
.win_gravity
) {
2195 case NorthWestGravity
:
2196 case NorthEastGravity
:
2198 r
.setY(client
.rect
.y());
2204 r
.setY(client
.rect
.y() - (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2207 case SouthWestGravity
:
2208 case SouthEastGravity
:
2210 r
.setY(client
.rect
.y() - frame
.margin
.top
- frame
.margin
.bottom
);
2215 r
.setY(client
.rect
.y() - frame
.margin
.top
);
2222 * The reverse of the applyGravity function.
2224 * Positions the Rect r according to the frame window position and
2227 void BlackboxWindow::restoreGravity(Rect
&r
) {
2228 // restore horizontal window gravity
2229 switch (client
.win_gravity
) {
2231 case NorthWestGravity
:
2232 case SouthWestGravity
:
2234 r
.setX(frame
.rect
.x());
2240 r
.setX(frame
.rect
.x() + (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2243 case NorthEastGravity
:
2244 case SouthEastGravity
:
2246 r
.setX(frame
.rect
.x() + frame
.margin
.left
+ frame
.margin
.right
);
2251 r
.setX(frame
.rect
.x() + frame
.margin
.left
);
2255 // restore vertical window gravity
2256 switch (client
.win_gravity
) {
2258 case NorthWestGravity
:
2259 case NorthEastGravity
:
2261 r
.setY(frame
.rect
.y());
2267 r
.setY(frame
.rect
.y() + (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2270 case SouthWestGravity
:
2271 case SouthEastGravity
:
2273 r
.setY(frame
.rect
.y() + frame
.margin
.top
+ frame
.margin
.bottom
);
2278 r
.setY(frame
.rect
.y() + frame
.margin
.top
);
2284 void BlackboxWindow::redrawLabel(void) const {
2285 if (flags
.focused
) {
2287 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2288 frame
.label
, frame
.flabel
);
2290 XSetWindowBackground(blackbox
->getXDisplay(),
2291 frame
.label
, frame
.flabel_pixel
);
2294 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2295 frame
.label
, frame
.ulabel
);
2297 XSetWindowBackground(blackbox
->getXDisplay(),
2298 frame
.label
, frame
.ulabel_pixel
);
2300 XClearWindow(blackbox
->getXDisplay(), frame
.label
);
2302 WindowStyle
*style
= screen
->getWindowStyle();
2304 int pos
= frame
.bevel_w
* 2,
2305 dlen
= style
->doJustify(client
.title
.c_str(), pos
, frame
.label_w
,
2306 frame
.bevel_w
* 4, i18n
.multibyte());
2308 BPen
pen((flags
.focused
) ? style
->l_text_focus
: style
->l_text_unfocus
,
2310 if (i18n
.multibyte())
2311 XmbDrawString(blackbox
->getXDisplay(), frame
.label
, style
->fontset
,
2313 (1 - style
->fontset_extents
->max_ink_extent
.y
),
2314 client
.title
.c_str(), dlen
);
2316 XDrawString(blackbox
->getXDisplay(), frame
.label
, pen
.gc(), pos
,
2317 (style
->font
->ascent
+ 1), client
.title
.c_str(), dlen
);
2321 void BlackboxWindow::redrawAllButtons(void) const {
2322 if (frame
.iconify_button
) redrawIconifyButton(False
);
2323 if (frame
.maximize_button
) redrawMaximizeButton(flags
.maximized
);
2324 if (frame
.close_button
) redrawCloseButton(False
);
2328 void BlackboxWindow::redrawIconifyButton(bool pressed
) const {
2330 if (flags
.focused
) {
2332 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2333 frame
.iconify_button
, frame
.fbutton
);
2335 XSetWindowBackground(blackbox
->getXDisplay(),
2336 frame
.iconify_button
, frame
.fbutton_pixel
);
2339 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2340 frame
.iconify_button
, frame
.ubutton
);
2342 XSetWindowBackground(blackbox
->getXDisplay(), frame
.iconify_button
,
2343 frame
.ubutton_pixel
);
2347 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2348 frame
.iconify_button
, frame
.pbutton
);
2350 XSetWindowBackground(blackbox
->getXDisplay(),
2351 frame
.iconify_button
, frame
.pbutton_pixel
);
2353 XClearWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
2355 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2356 screen
->getWindowStyle()->b_pic_unfocus
);
2357 XDrawRectangle(blackbox
->getXDisplay(), frame
.iconify_button
, pen
.gc(),
2358 2, (frame
.button_w
- 5), (frame
.button_w
- 5), 2);
2362 void BlackboxWindow::redrawMaximizeButton(bool pressed
) const {
2364 if (flags
.focused
) {
2366 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2367 frame
.maximize_button
, frame
.fbutton
);
2369 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2370 frame
.fbutton_pixel
);
2373 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2374 frame
.maximize_button
, frame
.ubutton
);
2376 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2377 frame
.ubutton_pixel
);
2381 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2382 frame
.maximize_button
, frame
.pbutton
);
2384 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2385 frame
.pbutton_pixel
);
2387 XClearWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
2389 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2390 screen
->getWindowStyle()->b_pic_unfocus
);
2391 XDrawRectangle(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2392 2, 2, (frame
.button_w
- 5), (frame
.button_w
- 5));
2393 XDrawLine(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2394 2, 3, (frame
.button_w
- 3), 3);
2398 void BlackboxWindow::redrawCloseButton(bool pressed
) const {
2400 if (flags
.focused
) {
2402 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2405 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2406 frame
.fbutton_pixel
);
2409 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2412 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2413 frame
.ubutton_pixel
);
2417 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2418 frame
.close_button
, frame
.pbutton
);
2420 XSetWindowBackground(blackbox
->getXDisplay(),
2421 frame
.close_button
, frame
.pbutton_pixel
);
2423 XClearWindow(blackbox
->getXDisplay(), frame
.close_button
);
2425 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2426 screen
->getWindowStyle()->b_pic_unfocus
);
2427 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2428 2, 2, (frame
.button_w
- 3), (frame
.button_w
- 3));
2429 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2430 2, (frame
.button_w
- 3), (frame
.button_w
- 3), 2);
2434 void BlackboxWindow::mapRequestEvent(const XMapRequestEvent
*re
) {
2435 if (re
->window
!= client
.window
)
2439 fprintf(stderr
, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2443 switch (current_state
) {
2448 case WithdrawnState
:
2458 if (! blackbox
->isStartup() && (isTransient() || screen
->doFocusNew())) {
2459 XSync(blackbox
->getXDisplay(), False
); // make sure the frame is mapped..
2467 void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent
*ue
) {
2468 if (ue
->window
!= client
.window
)
2472 fprintf(stderr
, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2476 screen
->unmanageWindow(this, False
);
2480 void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent
*de
) {
2481 if (de
->window
!= client
.window
)
2485 fprintf(stderr
, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2489 screen
->unmanageWindow(this, False
);
2493 void BlackboxWindow::reparentNotifyEvent(const XReparentEvent
*re
) {
2494 if (re
->window
!= client
.window
|| re
->parent
== frame
.plate
)
2498 fprintf(stderr
, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2499 "0x%lx.\n", client
.window
, re
->parent
);
2504 XPutBackEvent(blackbox
->getXDisplay(), &ev
);
2505 screen
->unmanageWindow(this, True
);
2509 void BlackboxWindow::propertyNotifyEvent(Atom atom
) {
2512 case XA_WM_CLIENT_MACHINE
:
2516 case XA_WM_TRANSIENT_FOR
: {
2517 // determine if this is a transient window
2520 // adjust the window decorations based on transience
2521 if (isTransient()) {
2522 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2523 functions
&= ~Func_Maximize
;
2524 setAllowedActions();
2535 case XA_WM_ICON_NAME
:
2537 if (flags
.iconic
) screen
->propagateWindowName(this);
2540 case XAtom::net_wm_name
:
2544 if (decorations
& Decor_Titlebar
)
2547 screen
->propagateWindowName(this);
2550 case XA_WM_NORMAL_HINTS
: {
2553 if ((client
.normal_hint_flags
& PMinSize
) &&
2554 (client
.normal_hint_flags
& PMaxSize
)) {
2555 if (client
.max_width
<= client
.min_width
&&
2556 client
.max_height
<= client
.min_height
) {
2557 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2558 functions
&= ~(Func_Resize
| Func_Maximize
);
2560 decorations
|= Decor_Maximize
| Decor_Handle
;
2561 functions
|= Func_Resize
| Func_Maximize
;
2563 setAllowedActions();
2566 Rect old_rect
= frame
.rect
;
2570 if (old_rect
!= frame
.rect
)
2577 if (atom
== xatom
->getAtom(XAtom::wm_protocols
)) {
2580 if ((decorations
& Decor_Close
) && (! frame
.close_button
)) {
2581 createCloseButton();
2582 if (decorations
& Decor_Titlebar
) {
2583 positionButtons(True
);
2584 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
2586 if (windowmenu
) windowmenu
->reconfigure();
2588 } else if (atom
== xatom
->getAtom(XAtom::net_wm_strut
)) {
2597 void BlackboxWindow::exposeEvent(const XExposeEvent
*ee
) {
2598 if (frame
.label
== ee
->window
&& (decorations
& Decor_Titlebar
))
2600 else if (frame
.close_button
== ee
->window
)
2601 redrawCloseButton(False
);
2602 else if (frame
.maximize_button
== ee
->window
)
2603 redrawMaximizeButton(flags
.maximized
);
2604 else if (frame
.iconify_button
== ee
->window
)
2605 redrawIconifyButton(False
);
2609 void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent
*cr
) {
2610 if (cr
->window
!= client
.window
|| flags
.iconic
)
2613 if (cr
->value_mask
& CWBorderWidth
)
2614 client
.old_bw
= cr
->border_width
;
2616 if (cr
->value_mask
& (CWX
| CWY
| CWWidth
| CWHeight
)) {
2617 Rect req
= frame
.rect
;
2619 if (cr
->value_mask
& (CWX
| CWY
)) {
2620 if (cr
->value_mask
& CWX
)
2621 client
.rect
.setX(cr
->x
);
2622 if (cr
->value_mask
& CWY
)
2623 client
.rect
.setY(cr
->y
);
2628 if (cr
->value_mask
& CWWidth
)
2629 req
.setWidth(cr
->width
+ frame
.margin
.left
+ frame
.margin
.right
);
2631 if (cr
->value_mask
& CWHeight
)
2632 req
.setHeight(cr
->height
+ frame
.margin
.top
+ frame
.margin
.bottom
);
2634 configure(req
.x(), req
.y(), req
.width(), req
.height());
2637 if (cr
->value_mask
& CWStackMode
) {
2638 switch (cr
->detail
) {
2654 void BlackboxWindow::grabButtons(void) {
2655 const BInput::MouseBindingList
&mbindings
= input
->getMouseBindings();
2657 BInput::MouseBindingList::const_iterator mit
= mbindings
.begin();
2658 const BInput::MouseBindingList::const_iterator mend
= mbindings
.end();
2659 for (; mit
!= mend
; ++mit
) {
2660 // dont grab for an action the window can't perform
2661 //if (! (mit->action == BInput::BeginMove && functions & Func_Move) &&
2662 // ! (mit->action == BInput::BeginResize && functions & Func_Resize)) {
2663 switch (mit
->event
) {
2664 case BInput::WindowClientPress
:
2665 blackbox
->grabButton(mit
->button
, mit
->state
, frame
.plate
, True
,
2666 ButtonPressMask
, GrabModeSync
, GrabModeSync
,
2669 case BInput::WindowDrag
:
2670 blackbox
->grabButton(mit
->button
, mit
->state
, frame
.window
, True
,
2671 ButtonMotionMask
, GrabModeAsync
, GrabModeAsync
,
2672 frame
.window
, None
);
2680 void BlackboxWindow::ungrabButtons(void) {
2681 const BInput::MouseBindingList
&mbindings
= input
->getMouseBindings();
2683 BInput::MouseBindingList::const_iterator mit
= mbindings
.begin();
2684 const BInput::MouseBindingList::const_iterator mend
= mbindings
.end();
2685 for (; mit
!= mend
; ++mit
) {
2686 switch (mit
->event
) {
2687 case BInput::WindowClientPress
:
2688 blackbox
->ungrabButton(mit
->button
, mit
->state
, frame
.plate
);
2690 case BInput::WindowDrag
:
2691 blackbox
->ungrabButton(mit
->button
, mit
->state
, frame
.window
);
2699 void BlackboxWindow::buttonPressEvent(const XButtonEvent
*be
) {
2700 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2702 if (frame
.maximize_button
== be
->window
) {
2703 if (input
->hasAction(be
->button
, be
->state
, BInput::MaximizeButtonClick
))
2704 redrawMaximizeButton(True
);
2705 } else if (frame
.iconify_button
== be
->window
) {
2706 if (input
->hasAction(be
->button
, be
->state
, BInput::IconifyButtonClick
))
2707 redrawIconifyButton(True
);
2708 } else if (frame
.close_button
== be
->window
) {
2709 if (input
->hasAction(be
->button
, be
->state
, BInput::CloseButtonClick
))
2710 redrawCloseButton(True
);
2711 } else if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
2712 if (be
->time
- lastButtonPressTime
<= blackbox
->getDoubleClickInterval()) {
2713 lastButtonPressTime
= 0;
2714 input
->doAction(this, be
->button
, be
->state
,
2715 BInput::WindowTitleDoublePress
);
2717 lastButtonPressTime
= be
->time
;
2718 input
->doAction(this, be
->button
, be
->state
,
2719 BInput::WindowTitlePress
);
2721 } else if (frame
.plate
== be
->window
) {
2722 input
->doAction(this, be
->button
, be
->state
, BInput::WindowClientPress
);
2723 // buttons on the client window are grabbed in Sync mode, so we need to let
2724 // events back through again
2725 XAllowEvents(blackbox
->getXDisplay(), ReplayPointer
, be
->time
);
2726 } else if (frame
.window
== be
->window
|| frame
.handle
== be
->window
) {
2727 input
->doAction(this, be
->button
, be
->state
, BInput::WindowFramePress
);
2732 void BlackboxWindow::showWindowMenu(int root_x
, int root_y
) {
2733 if (! windowmenu
|| windowmenu
->isVisible())
2736 root_x
-= windowmenu
->getWidth() / 2;
2737 root_y
-= windowmenu
->getHeight() / 2;
2739 // snap the window menu into a corner/side if necessary
2740 int left_edge
, right_edge
, top_edge
, bottom_edge
;
2742 left_edge
= frame
.rect
.x();
2743 right_edge
= frame
.rect
.right() - windowmenu
->getWidth() - frame
.border_w
- 1;
2744 if (decorations
& Decor_Titlebar
)
2745 top_edge
= frame
.rect
.y() + frame
.title_h
+ frame
.border_w
;
2747 top_edge
= frame
.rect
.y() + frame
.border_w
;
2748 if (decorations
& Decor_Handle
)
2749 bottom_edge
= frame
.rect
.bottom() - frame
.handle_h
- (frame
.border_w
* 3) -
2750 windowmenu
->getHeight();
2752 bottom_edge
= frame
.rect
.bottom() - windowmenu
->getHeight() -
2755 if (root_x
> right_edge
)
2756 root_x
= right_edge
;
2757 if (root_x
< left_edge
)
2760 if (root_y
> bottom_edge
)
2761 root_y
= bottom_edge
;
2762 if (root_y
< top_edge
)
2766 windowmenu
->move(root_x
, root_y
);
2768 XRaiseWindow(blackbox
->getXDisplay(), windowmenu
->getWindowID());
2769 XRaiseWindow(blackbox
->getXDisplay(),
2770 windowmenu
->getSendToMenu()->getWindowID());
2774 void BlackboxWindow::buttonReleaseEvent(const XButtonEvent
*re
) {
2775 // get the proper state, without the button that was released
2777 switch (re
->button
) {
2779 state
= re
->state
& ~Button1Mask
;
2782 state
= re
->state
& ~Button2Mask
;
2785 state
= re
->state
& ~Button3Mask
;
2788 state
= re
->state
& ~Button4Mask
;
2791 state
= re
->state
& ~Button5Mask
;
2794 assert(false); // unhandled button
2797 if (frame
.maximize_button
== re
->window
) {
2798 if ((re
->x
< 0 || re
->x
>= static_cast<signed>(frame
.button_w
)) ||
2799 (re
->y
< 0 || re
->y
>= static_cast<signed>(frame
.button_w
)) ||
2800 ! input
->doAction(this, re
->button
, state
,
2801 BInput::MaximizeButtonClick
))
2802 redrawMaximizeButton(flags
.maximized
);
2803 } else if (frame
.iconify_button
== re
->window
) {
2804 if ((re
->x
< 0 || re
->x
>= static_cast<signed>(frame
.button_w
)) ||
2805 (re
->y
< 0 || re
->y
>= static_cast<signed>(frame
.button_w
)) ||
2806 ! input
->doAction(this, re
->button
, state
,
2807 BInput::IconifyButtonClick
))
2808 redrawIconifyButton(False
);
2809 } else if (frame
.close_button
== re
->window
) {
2810 if (! ((re
->x
< 0 || re
->x
>= static_cast<signed>(frame
.button_w
)) ||
2811 (re
->y
< 0 || re
->y
>= static_cast<signed>(frame
.button_w
))))
2812 input
->doAction(this, re
->button
, state
, BInput::CloseButtonClick
);
2813 redrawCloseButton(False
);
2814 } else if (flags
.moving
) {
2816 } else if (flags
.resizing
) {
2822 void BlackboxWindow::motionNotifyEvent(const XMotionEvent
*me
) {
2823 // get the button that is being used
2824 // get the proper state, without the button that is being used
2825 unsigned int button
;
2827 if (me
->state
& Button1Mask
) {
2829 state
= me
->state
& ~Button1Mask
;
2830 } else if (me
->state
& Button2Mask
) {
2832 state
= me
->state
& ~Button2Mask
;
2833 } else if (me
->state
& Button3Mask
) {
2835 state
= me
->state
& ~Button3Mask
;
2836 } else if (me
->state
& Button4Mask
) {
2838 state
= me
->state
& ~Button4Mask
;
2839 } else if (me
->state
& Button5Mask
) {
2841 state
= me
->state
& ~Button5Mask
;
2847 doMove(me
->x_root
, me
->y_root
);
2848 } else if (flags
.resizing
) {
2849 doResize(me
->x_root
, me
->y_root
);
2851 if (frame
.title
== me
->window
|| frame
.label
== me
->window
)
2852 input
->doAction(this, button
, state
, BInput::WindowTitleDrag
);
2853 else if (frame
.handle
== me
->window
)
2854 input
->doAction(this, button
, state
, BInput::WindowHandleDrag
);
2855 else if (frame
.left_grip
== me
->window
)
2856 input
->doAction(this, button
, state
, BInput::WindowLeftGripDrag
);
2857 else if (frame
.right_grip
== me
->window
)
2858 input
->doAction(this, button
, state
, BInput::WindowRightGripDrag
);
2859 else if (frame
.window
== me
->window
)
2860 input
->doAction(this, button
, state
, BInput::WindowDrag
);
2865 void BlackboxWindow::beginMove(int x_root
, int y_root
) {
2866 assert(! (flags
.resizing
|| flags
.moving
));
2869 Only one window can be moved/resized at a time. If another window is already
2870 being moved or resized, then stop it before whating to work with this one.
2872 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
2873 if (changing
&& changing
!= this) {
2874 if (changing
->flags
.moving
)
2875 changing
->endMove();
2876 else // if (changing->flags.resizing)
2877 changing
->endResize();
2880 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
2881 PointerMotionMask
| ButtonReleaseMask
,
2882 GrabModeAsync
, GrabModeAsync
,
2883 None
, blackbox
->getMoveCursor(), CurrentTime
);
2885 if (windowmenu
&& windowmenu
->isVisible())
2888 flags
.moving
= True
;
2889 blackbox
->setChangingWindow(this);
2891 if (! screen
->doOpaqueMove()) {
2892 XGrabServer(blackbox
->getXDisplay());
2894 frame
.changing
= frame
.rect
;
2895 screen
->showPosition(frame
.changing
.x(), frame
.changing
.y());
2897 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2901 frame
.changing
.width() - 1,
2902 frame
.changing
.height() - 1);
2905 frame
.grab_x
= x_root
- frame
.rect
.x() - frame
.border_w
;
2906 frame
.grab_y
= y_root
- frame
.rect
.y() - frame
.border_w
;
2910 void BlackboxWindow::doMove(int x_root
, int y_root
) {
2911 assert(flags
.moving
);
2912 assert(blackbox
->getChangingWindow() == this);
2914 int dx
= x_root
- frame
.grab_x
, dy
= y_root
- frame
.grab_y
;
2915 dx
-= frame
.border_w
;
2916 dy
-= frame
.border_w
;
2918 const int snap_distance
= screen
->getEdgeSnapThreshold();
2920 if (snap_distance
) {
2922 const int wleft
= dx
,
2923 wright
= dx
+ frame
.rect
.width() - 1,
2925 wbottom
= dy
+ frame
.rect
.height() - 1;
2927 if (screen
->getWindowToWindowSnap()) {
2928 Workspace
*w
= screen
->getWorkspace(getWorkspaceNumber());
2931 // try snap to another window
2932 for (unsigned int i
= 0, c
= w
->getCount(); i
< c
; ++i
) {
2933 BlackboxWindow
*snapwin
= w
->getWindow(i
);
2934 if (snapwin
== this)
2935 continue; // don't snap to self
2937 bool snapped
= False
;
2939 const Rect
&winrect
= snapwin
->frameRect();
2940 int dleft
= std::abs(wright
- winrect
.left()),
2941 dright
= std::abs(wleft
- winrect
.right()),
2942 dtop
= std::abs(wbottom
- winrect
.top()),
2943 dbottom
= std::abs(wtop
- winrect
.bottom());
2945 if (wtop
>= (signed)(winrect
.y() - frame
.rect
.height() + 1) &&
2946 wtop
< (signed)(winrect
.y() + winrect
.height() - 1)) {
2948 // snap left of other window?
2949 if (dleft
< snap_distance
&& dleft
<= dright
) {
2950 dx
= winrect
.left() - frame
.rect
.width();
2953 // snap right of other window?
2954 else if (dright
< snap_distance
) {
2955 dx
= winrect
.right() + 1;
2960 if (screen
->getWindowCornerSnap()) {
2961 // try corner-snap to its other sides
2962 dtop
= std::abs(wtop
- winrect
.top());
2963 dbottom
= std::abs(wbottom
- winrect
.bottom());
2964 if (dtop
< snap_distance
&& dtop
<= dbottom
)
2966 else if (dbottom
< snap_distance
)
2967 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
2974 if (wleft
>= (signed)(winrect
.x() - frame
.rect
.width() + 1) &&
2975 wleft
< (signed)(winrect
.x() + winrect
.width() - 1)) {
2977 // snap top of other window?
2978 if (dtop
< snap_distance
&& dtop
<= dbottom
) {
2979 dy
= winrect
.top() - frame
.rect
.height();
2982 // snap bottom of other window?
2983 else if (dbottom
< snap_distance
) {
2984 dy
= winrect
.bottom() + 1;
2989 if (screen
->getWindowCornerSnap()) {
2990 // try corner-snap to its other sides
2991 dleft
= std::abs(wleft
- winrect
.left());
2992 dright
= std::abs(wright
- winrect
.right());
2993 if (dleft
< snap_distance
&& dleft
<= dright
)
2994 dx
= winrect
.left();
2995 else if (dright
< snap_distance
)
2996 dx
= winrect
.right() - frame
.rect
.width() + 1;
3005 // try snap to the screen's available area
3006 Rect srect
= screen
->availableArea();
3008 int dleft
= std::abs(wleft
- srect
.left()),
3009 dright
= std::abs(wright
- srect
.right()),
3010 dtop
= std::abs(wtop
- srect
.top()),
3011 dbottom
= std::abs(wbottom
- srect
.bottom());
3014 if (dleft
< snap_distance
&& dleft
<= dright
)
3017 else if (dright
< snap_distance
)
3018 dx
= srect
.right() - frame
.rect
.width() + 1;
3021 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3024 else if (dbottom
< snap_distance
)
3025 dy
= srect
.bottom() - frame
.rect
.height() + 1;
3027 srect
= screen
->getRect(); // now get the full screen
3029 dleft
= std::abs(wleft
- srect
.left()),
3030 dright
= std::abs(wright
- srect
.right()),
3031 dtop
= std::abs(wtop
- srect
.top()),
3032 dbottom
= std::abs(wbottom
- srect
.bottom());
3035 if (dleft
< snap_distance
&& dleft
<= dright
)
3038 else if (dright
< snap_distance
)
3039 dx
= srect
.right() - frame
.rect
.width() + 1;
3042 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3045 else if (dbottom
< snap_distance
)
3046 dy
= srect
.bottom() - frame
.rect
.height() + 1;
3049 if (screen
->doOpaqueMove()) {
3050 configure(dx
, dy
, frame
.rect
.width(), frame
.rect
.height());
3052 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3056 frame
.changing
.width() - 1,
3057 frame
.changing
.height() - 1);
3059 frame
.changing
.setPos(dx
, dy
);
3061 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3065 frame
.changing
.width() - 1,
3066 frame
.changing
.height() - 1);
3069 screen
->showPosition(dx
, dy
);
3073 void BlackboxWindow::endMove(void) {
3074 assert(flags
.moving
);
3075 assert(blackbox
->getChangingWindow() == this);
3077 flags
.moving
= False
;
3078 blackbox
->setChangingWindow(0);
3080 if (! screen
->doOpaqueMove()) {
3081 /* when drawing the rubber band, we need to make sure we only draw inside
3082 * the frame... frame.changing_* contain the new coords for the window,
3083 * so we need to subtract 1 from changing_w/changing_h every where we
3084 * draw the rubber band (for both moving and resizing)
3086 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3087 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3088 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3089 XUngrabServer(blackbox
->getXDisplay());
3091 configure(frame
.changing
.x(), frame
.changing
.y(),
3092 frame
.changing
.width(), frame
.changing
.height());
3094 configure(frame
.rect
.x(), frame
.rect
.y(),
3095 frame
.rect
.width(), frame
.rect
.height());
3097 screen
->hideGeometry();
3099 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3101 // if there are any left over motions from the move, drop them now
3102 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3104 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3109 void BlackboxWindow::beginResize(int x_root
, int y_root
, Corner dir
) {
3110 assert(! (flags
.resizing
|| flags
.moving
));
3113 Only one window can be moved/resized at a time. If another window is already
3114 being moved or resized, then stop it before whating to work with this one.
3116 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3117 if (changing
&& changing
!= this) {
3118 if (changing
->flags
.moving
)
3119 changing
->endMove();
3120 else // if (changing->flags.resizing)
3121 changing
->endResize();
3129 switch (resize_dir
) {
3132 cursor
= blackbox
->getLowerLeftAngleCursor();
3137 cursor
= blackbox
->getLowerRightAngleCursor();
3141 anchor
= BottomRight
;
3142 cursor
= blackbox
->getUpperLeftAngleCursor();
3146 anchor
= BottomLeft
;
3147 cursor
= blackbox
->getUpperRightAngleCursor();
3151 assert(false); // unhandled Corner
3154 XGrabServer(blackbox
->getXDisplay());
3155 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3156 PointerMotionMask
| ButtonReleaseMask
,
3157 GrabModeAsync
, GrabModeAsync
, None
, cursor
, CurrentTime
);
3159 flags
.resizing
= True
;
3160 blackbox
->setChangingWindow(this);
3163 frame
.changing
= frame
.rect
;
3165 constrain(anchor
, &gw
, &gh
);
3167 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3168 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3169 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3171 screen
->showGeometry(gw
, gh
);
3173 frame
.grab_x
= x_root
;
3174 frame
.grab_y
= y_root
;
3178 void BlackboxWindow::doResize(int x_root
, int y_root
) {
3179 assert(flags
.resizing
);
3180 assert(blackbox
->getChangingWindow() == this);
3182 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3183 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3184 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3189 switch (resize_dir
) {
3192 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3193 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3197 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3198 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3201 anchor
= BottomRight
;
3202 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3203 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3206 anchor
= BottomLeft
;
3207 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3208 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3212 assert(false); // unhandled Corner
3215 constrain(anchor
, &gw
, &gh
);
3217 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3218 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3219 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3221 screen
->showGeometry(gw
, gh
);
3225 void BlackboxWindow::endResize(void) {
3226 assert(flags
.resizing
);
3227 assert(blackbox
->getChangingWindow() == this);
3229 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3230 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3231 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3232 XUngrabServer(blackbox
->getXDisplay());
3234 // unset maximized state after resized when fully maximized
3235 if (flags
.maximized
== 1)
3238 flags
.resizing
= False
;
3239 blackbox
->setChangingWindow(0);
3241 configure(frame
.changing
.x(), frame
.changing
.y(),
3242 frame
.changing
.width(), frame
.changing
.height());
3243 screen
->hideGeometry();
3245 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3247 // if there are any left over motions from the resize, drop them now
3248 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3250 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3256 void BlackboxWindow::shapeEvent(XShapeEvent
*) {
3257 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
3264 bool BlackboxWindow::validateClient(void) const {
3265 XSync(blackbox
->getXDisplay(), False
);
3268 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3269 DestroyNotify
, &e
) ||
3270 XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3272 XPutBackEvent(blackbox
->getXDisplay(), &e
);
3281 void BlackboxWindow::restore(bool remap
) {
3282 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeDelete
);
3283 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
3284 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, NoEventMask
);
3286 restoreGravity(client
.rect
);
3288 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
3289 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
3291 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, client
.old_bw
);
3294 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3295 ReparentNotify
, &ev
)) {
3298 // according to the ICCCM - if the client doesn't reparent to
3299 // root, then we have to do it for them
3300 XReparentWindow(blackbox
->getXDisplay(), client
.window
,
3301 screen
->getRootWindow(),
3302 client
.rect
.x(), client
.rect
.y());
3305 if (remap
) XMapWindow(blackbox
->getXDisplay(), client
.window
);
3309 // timer for autoraise
3310 void BlackboxWindow::timeout(void) {
3315 void BlackboxWindow::changeBlackboxHints(BlackboxHints
*net
) {
3316 if ((net
->flags
& AttribShaded
) &&
3317 ((blackbox_attrib
.attrib
& AttribShaded
) !=
3318 (net
->attrib
& AttribShaded
)))
3321 if (flags
.visible
&& // watch out for requests when we can not be seen
3322 (net
->flags
& (AttribMaxVert
| AttribMaxHoriz
)) &&
3323 ((blackbox_attrib
.attrib
& (AttribMaxVert
| AttribMaxHoriz
)) !=
3324 (net
->attrib
& (AttribMaxVert
| AttribMaxHoriz
)))) {
3325 if (flags
.maximized
) {
3330 if ((net
->flags
& AttribMaxHoriz
) && (net
->flags
& AttribMaxVert
))
3331 button
= ((net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0);
3332 else if (net
->flags
& AttribMaxVert
)
3333 button
= ((net
->attrib
& AttribMaxVert
) ? 2 : 0);
3334 else if (net
->flags
& AttribMaxHoriz
)
3335 button
= ((net
->attrib
& AttribMaxHoriz
) ? 3 : 0);
3341 if ((net
->flags
& AttribOmnipresent
) &&
3342 ((blackbox_attrib
.attrib
& AttribOmnipresent
) !=
3343 (net
->attrib
& AttribOmnipresent
)))
3346 if ((net
->flags
& AttribWorkspace
) &&
3347 (blackbox_attrib
.workspace
!= net
->workspace
)) {
3348 screen
->reassociateWindow(this, net
->workspace
, True
);
3350 if (screen
->getCurrentWorkspaceID() != net
->workspace
) {
3358 if (net
->flags
& AttribDecoration
) {
3359 switch (net
->decoration
) {
3361 // clear all decorations except close
3362 decorations
&= Decor_Close
;
3368 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Iconify
;
3370 decorations
= ((functions
& Func_Resize
) && !isTransient() ?
3371 decorations
| Decor_Handle
:
3372 decorations
&= ~Decor_Handle
);
3373 decorations
= (functions
& Func_Maximize
?
3374 decorations
| Decor_Maximize
:
3375 decorations
&= ~Decor_Maximize
);
3380 decorations
|= Decor_Titlebar
| Decor_Iconify
;
3381 decorations
&= ~(Decor_Border
| Decor_Handle
);
3383 decorations
= (functions
& Func_Maximize
?
3384 decorations
| Decor_Maximize
:
3385 decorations
&= ~Decor_Maximize
);
3390 decorations
|= Decor_Titlebar
;
3391 decorations
&= ~(Decor_Iconify
| Decor_Border
);
3393 decorations
= ((functions
& Func_Resize
) && !isTransient() ?
3394 decorations
| Decor_Handle
:
3395 decorations
&= ~Decor_Handle
);
3396 decorations
= (functions
& Func_Maximize
?
3397 decorations
| Decor_Maximize
:
3398 decorations
&= ~Decor_Maximize
);
3403 // we can not be shaded if we lack a titlebar
3404 if (flags
.shaded
&& ! (decorations
& Decor_Titlebar
))
3407 if (flags
.visible
&& frame
.window
) {
3408 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
3409 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
3413 setState(current_state
);
3419 * Set the sizes of all components of the window frame
3420 * (the window decorations).
3421 * These values are based upon the current style settings and the client
3422 * window's dimensions.
3424 void BlackboxWindow::upsize(void) {
3425 frame
.bevel_w
= screen
->getBevelWidth();
3427 if (decorations
& Decor_Border
) {
3428 frame
.border_w
= screen
->getBorderWidth();
3429 if (! isTransient())
3430 frame
.mwm_border_w
= screen
->getFrameWidth();
3432 frame
.mwm_border_w
= 0;
3434 frame
.mwm_border_w
= frame
.border_w
= 0;
3437 if (decorations
& Decor_Titlebar
) {
3438 // the height of the titlebar is based upon the height of the font being
3439 // used to display the window's title
3440 WindowStyle
*style
= screen
->getWindowStyle();
3441 if (i18n
.multibyte())
3442 frame
.title_h
= (style
->fontset_extents
->max_ink_extent
.height
+
3443 (frame
.bevel_w
* 2) + 2);
3445 frame
.title_h
= (style
->font
->ascent
+ style
->font
->descent
+
3446 (frame
.bevel_w
* 2) + 2);
3448 frame
.label_h
= frame
.title_h
- (frame
.bevel_w
* 2);
3449 frame
.button_w
= (frame
.label_h
- 2);
3451 // set the top frame margin
3452 frame
.margin
.top
= frame
.border_w
+ frame
.title_h
+
3453 frame
.border_w
+ frame
.mwm_border_w
;
3459 // set the top frame margin
3460 frame
.margin
.top
= frame
.border_w
+ frame
.mwm_border_w
;
3463 // set the left/right frame margin
3464 frame
.margin
.left
= frame
.margin
.right
= frame
.border_w
+ frame
.mwm_border_w
;
3466 if (decorations
& Decor_Handle
) {
3467 frame
.grip_w
= frame
.button_w
* 2;
3468 frame
.handle_h
= screen
->getHandleWidth();
3470 // set the bottom frame margin
3471 frame
.margin
.bottom
= frame
.border_w
+ frame
.handle_h
+
3472 frame
.border_w
+ frame
.mwm_border_w
;
3477 // set the bottom frame margin
3478 frame
.margin
.bottom
= frame
.border_w
+ frame
.mwm_border_w
;
3482 We first get the normal dimensions and use this to define the inside_w/h
3483 then we modify the height if shading is in effect.
3484 If the shade state is not considered then frame.rect gets reset to the
3485 normal window size on a reconfigure() call resulting in improper
3486 dimensions appearing in move/resize and other events.
3489 height
= client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
,
3490 width
= client
.rect
.width() + frame
.margin
.left
+ frame
.margin
.right
;
3492 frame
.inside_w
= width
- (frame
.border_w
* 2);
3493 frame
.inside_h
= height
- (frame
.border_w
* 2);
3496 height
= frame
.title_h
+ (frame
.border_w
* 2);
3497 frame
.rect
.setSize(width
, height
);
3502 * Calculate the size of the client window and constrain it to the
3503 * size specified by the size hints of the client window.
3505 * The logical width and height are placed into pw and ph, if they
3506 * are non-zero. Logical size refers to the users perception of
3507 * the window size (for example an xterm resizes in cells, not in pixels).
3509 * The physical geometry is placed into frame.changing_{x,y,width,height}.
3510 * Physical geometry refers to the geometry of the window in pixels.
3512 void BlackboxWindow::constrain(Corner anchor
, int *pw
, int *ph
) {
3513 // frame.changing represents the requested frame size, we need to
3514 // strip the frame margin off and constrain the client size
3515 frame
.changing
.setCoords(frame
.changing
.left() + frame
.margin
.left
,
3516 frame
.changing
.top() + frame
.margin
.top
,
3517 frame
.changing
.right() - frame
.margin
.right
,
3518 frame
.changing
.bottom() - frame
.margin
.bottom
);
3520 int dw
= frame
.changing
.width(), dh
= frame
.changing
.height(),
3521 base_width
= (client
.base_width
) ? client
.base_width
: client
.min_width
,
3522 base_height
= (client
.base_height
) ? client
.base_height
:
3526 if (dw
< static_cast<signed>(client
.min_width
)) dw
= client
.min_width
;
3527 if (dh
< static_cast<signed>(client
.min_height
)) dh
= client
.min_height
;
3528 if (dw
> static_cast<signed>(client
.max_width
)) dw
= client
.max_width
;
3529 if (dh
> static_cast<signed>(client
.max_height
)) dh
= client
.max_height
;
3532 dw
/= client
.width_inc
;
3534 dh
/= client
.height_inc
;
3537 if (client
.width_inc
== 1)
3538 *pw
= dw
+ base_width
;
3543 if (client
.height_inc
== 1)
3544 *ph
= dh
+ base_height
;
3549 dw
*= client
.width_inc
;
3551 dh
*= client
.height_inc
;
3554 frame
.changing
.setSize(dw
, dh
);
3556 // add the frame margin back onto frame.changing
3557 frame
.changing
.setCoords(frame
.changing
.left() - frame
.margin
.left
,
3558 frame
.changing
.top() - frame
.margin
.top
,
3559 frame
.changing
.right() + frame
.margin
.right
,
3560 frame
.changing
.bottom() + frame
.margin
.bottom
);
3562 // move frame.changing to the specified anchor
3570 dx
= frame
.rect
.right() - frame
.changing
.right();
3574 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3578 dx
= frame
.rect
.right() - frame
.changing
.right();
3579 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3583 assert(false); // unhandled corner
3585 frame
.changing
.setPos(frame
.changing
.x() + dx
, frame
.changing
.y() + dy
);
3589 int WindowStyle::doJustify(const char *text
, int &start_pos
,
3590 unsigned int max_length
, unsigned int modifier
,
3591 bool multibyte
) const {
3592 size_t text_len
= strlen(text
);
3593 unsigned int length
;
3597 XRectangle ink
, logical
;
3598 XmbTextExtents(fontset
, text
, text_len
, &ink
, &logical
);
3599 length
= logical
.width
;
3601 length
= XTextWidth(font
, text
, text_len
);
3604 } while (length
> max_length
&& text_len
-- > 0);
3608 start_pos
+= max_length
- length
;
3612 start_pos
+= (max_length
- length
) / 2;
3624 BWindowGroup::BWindowGroup(Blackbox
*b
, Window _group
)
3625 : blackbox(b
), group(_group
) {
3626 XWindowAttributes wattrib
;
3627 if (! XGetWindowAttributes(blackbox
->getXDisplay(), group
, &wattrib
)) {
3628 // group window doesn't seem to exist anymore
3634 watch for destroy notify on the group window (in addition to
3635 any other events we are looking for)
3637 since some managed windows can also be window group controllers,
3638 we need to make sure that we don't clobber the event mask for the
3641 XSelectInput(blackbox
->getXDisplay(), group
,
3642 wattrib
.your_event_mask
| StructureNotifyMask
);
3644 blackbox
->saveGroupSearch(group
, this);
3648 BWindowGroup::~BWindowGroup(void) {
3649 blackbox
->removeGroupSearch(group
);
3654 BWindowGroup::find(BScreen
*screen
, bool allow_transients
) const {
3655 BlackboxWindow
*ret
= blackbox
->getFocusedWindow();
3657 // does the focus window match (or any transient_fors)?
3659 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3660 if (ret
->isTransient() && allow_transients
) break;
3661 else if (! ret
->isTransient()) break;
3664 ret
= ret
->getTransientFor();
3667 if (ret
) return ret
;
3669 // the focus window didn't match, look in the group's window list
3670 BlackboxWindowList::const_iterator it
, end
= windowList
.end();
3671 for (it
= windowList
.begin(); it
!= end
; ++it
) {
3673 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3674 if (ret
->isTransient() && allow_transients
) break;
3675 else if (! ret
->isTransient()) break;