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
44 #endif // HAVE_STDLIB_H
48 #include "blackbox.hh"
49 #include "Clientmenu.hh"
52 #include "Iconmenu.hh"
58 #include "Windowmenu.hh"
59 #include "Workspace.hh"
66 * Initializes the class with default values/the window's set initial values.
68 BlackboxWindow::BlackboxWindow(Blackbox
*b
, Window w
, BScreen
*s
) {
69 // fprintf(stderr, "BlackboxWindow size: %d bytes\n",
70 // sizeof(BlackboxWindow));
73 fprintf(stderr
, "BlackboxWindow::BlackboxWindow(): creating 0x%lx\n", w
);
77 set timer to zero... it is initialized properly later, so we check
78 if timer is zero in the destructor, and assume that the window is not
79 fully constructed if timer is zero...
85 xatom
= blackbox
->getXAtom();
87 if (! validateClient()) {
92 // fetch client size and placement
93 XWindowAttributes wattrib
;
94 if (! XGetWindowAttributes(blackbox
->getXDisplay(),
95 client
.window
, &wattrib
) ||
96 ! wattrib
.screen
|| wattrib
.override_redirect
) {
99 "BlackboxWindow::BlackboxWindow(): XGetWindowAttributes failed\n");
106 // set the eventmask early in the game so that we make sure we get
107 // all the events we are interested in
108 XSetWindowAttributes attrib_set
;
109 attrib_set
.event_mask
= PropertyChangeMask
| FocusChangeMask
|
111 attrib_set
.do_not_propagate_mask
= ButtonPressMask
| ButtonReleaseMask
|
113 XChangeWindowAttributes(blackbox
->getXDisplay(), client
.window
,
114 CWEventMask
|CWDontPropagate
, &attrib_set
);
116 flags
.moving
= flags
.resizing
= flags
.shaded
= flags
.visible
=
117 flags
.iconic
= flags
.focused
= flags
.stuck
= flags
.modal
=
118 flags
.send_focus_message
= flags
.shaped
= flags
.skip_taskbar
=
119 flags
.skip_pager
= flags
.fullscreen
= False
;
122 blackbox_attrib
.workspace
= window_number
= BSENTINEL
;
124 blackbox_attrib
.flags
= blackbox_attrib
.attrib
= blackbox_attrib
.stack
= 0l;
125 blackbox_attrib
.decoration
= DecorNormal
;
126 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
127 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
130 frame
.window
= frame
.plate
= frame
.title
= frame
.handle
= None
;
131 frame
.close_button
= frame
.iconify_button
= frame
.maximize_button
=
132 frame
.stick_button
= None
;
133 frame
.right_grip
= frame
.left_grip
= None
;
135 frame
.ulabel_pixel
= frame
.flabel_pixel
= frame
.utitle_pixel
=
136 frame
.ftitle_pixel
= frame
.uhandle_pixel
= frame
.fhandle_pixel
=
137 frame
.ubutton_pixel
= frame
.fbutton_pixel
= frame
.uborder_pixel
=
138 frame
.fborder_pixel
= frame
.ugrip_pixel
= frame
.fgrip_pixel
= 0;
139 frame
.utitle
= frame
.ftitle
= frame
.uhandle
= frame
.fhandle
= None
;
140 frame
.ulabel
= frame
.flabel
= frame
.ubutton
= frame
.fbutton
= None
;
141 frame
.ugrip
= frame
.fgrip
= None
;
143 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
144 mwm_decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
145 Decor_Iconify
| Decor_Maximize
;
147 client
.normal_hint_flags
= 0;
148 client
.window_group
= None
;
149 client
.transient_for
= 0;
151 current_state
= NormalState
;
156 set the initial size and location of client window (relative to the
157 _root window_). This position is the reference point used with the
158 window's gravity to find the window's initial position.
160 client
.rect
.setRect(wattrib
.x
, wattrib
.y
, wattrib
.width
, wattrib
.height
);
161 client
.old_bw
= wattrib
.border_width
;
163 lastButtonPressTime
= 0;
165 timer
= new BTimer(blackbox
, this);
166 timer
->setTimeout(blackbox
->getAutoRaiseDelay());
168 // get size, aspect, minimum/maximum size and other hints set by the
171 if (! getBlackboxHints())
178 frame
.window
= createToplevelWindow();
180 blackbox
->saveWindowSearch(frame
.window
, this);
182 frame
.plate
= createChildWindow(frame
.window
, ExposureMask
);
183 blackbox
->saveWindowSearch(frame
.plate
, this);
185 // determine if this is a transient window
188 // determine the window's type, so we can decide its decorations and
189 // functionality, or if we should not manage it at all
190 if (getWindowType()) {
191 // adjust the window decorations/behavior based on the window type
192 switch (window_type
) {
196 blackbox_attrib
.workspace
= 0; // we do need to belong to a workspace
197 flags
.stuck
= True
; // we show up on all workspaces
199 // none of these windows are manipulated by the window manager
205 // these windows get less functionality
206 functions
&= ~(Func_Maximize
| Func_Resize
| Func_Iconify
);
210 // dialogs cannot be maximized
211 functions
&= ~Func_Maximize
;
215 // normal windows retain all of the possible decorations and
223 // further adjeust the window's decorations/behavior based on window sizes
224 if ((client
.normal_hint_flags
& PMinSize
) &&
225 (client
.normal_hint_flags
& PMaxSize
) &&
226 client
.max_width
<= client
.min_width
&&
227 client
.max_height
<= client
.min_height
) {
228 functions
&= ~(Func_Resize
| Func_Maximize
);
235 if (decorations
& Decor_Titlebar
)
238 if (decorations
& Decor_Handle
)
241 // apply the size and gravity hint to the frame
245 bool place_window
= True
;
246 if (blackbox
->isStartup() || isTransient() ||
247 client
.normal_hint_flags
& (PPosition
|USPosition
)) {
248 applyGravity(frame
.rect
);
250 if (blackbox
->isStartup() || client
.rect
.intersects(screen
->getRect()))
251 place_window
= False
;
254 // add the window's strut. note this is done *after* placing the window.
255 screen
->addStrut(&client
.strut
);
259 the server needs to be grabbed here to prevent client's from sending
260 events while we are in the process of configuring their window.
261 We hold the grab until after we are done moving the window around.
264 XGrabServer(blackbox
->getXDisplay());
266 associateClientWindow();
268 blackbox
->saveWindowSearch(client
.window
, this);
270 if (blackbox_attrib
.workspace
>= screen
->getWorkspaceCount())
271 screen
->getCurrentWorkspace()->addWindow(this, place_window
);
273 screen
->getWorkspace(blackbox_attrib
.workspace
)->
274 addWindow(this, place_window
);
276 if (! place_window
) {
277 // don't need to call configure if we are letting the workspace
279 configure(frame
.rect
.x(), frame
.rect
.y(),
280 frame
.rect
.width(), frame
.rect
.height());
286 XUngrabServer(blackbox
->getXDisplay());
289 if (blackbox
->hasShapeExtensions() && flags
.shaped
)
293 // now that we know where to put the window and what it should look like
294 // we apply the decorations
299 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
301 // this ensures the title, buttons, and other decor are properly displayed
304 // preserve the window's initial state on first map, and its current state
306 unsigned long initial_state
= current_state
;
308 current_state
= initial_state
;
310 // get sticky state from our parent window if we've got one
311 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
312 client
.transient_for
->isStuck() != flags
.stuck
)
316 flags
.shaded
= False
;
317 initial_state
= current_state
;
321 At this point in the life of a window, current_state should only be set
322 to IconicState if the window was an *icon*, not if it was shaded.
324 if (initial_state
!= IconicState
)
325 current_state
= NormalState
;
333 if (flags
.maximized
&& (functions
& Func_Maximize
))
336 // create this last so it only needs to be configured once
337 windowmenu
= new Windowmenu(this);
341 BlackboxWindow::~BlackboxWindow(void) {
343 fprintf(stderr
, "BlackboxWindow::~BlackboxWindow: destroying 0x%lx\n",
347 if (! timer
) // window not managed...
353 screen
->removeStrut(&client
.strut
);
354 screen
->updateAvailableArea();
356 // We don't need to worry about resizing because resizing always grabs the X
357 // server. This should only ever happen if using opaque moving.
365 if (client
.window_group
) {
366 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
367 if (group
) group
->removeWindow(this);
370 // remove ourselves from our transient_for
372 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul)
373 client
.transient_for
->client
.transientList
.remove(this);
374 client
.transient_for
= (BlackboxWindow
*) 0;
377 if (client
.transientList
.size() > 0) {
378 // reset transient_for for all transients
379 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
380 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
381 (*it
)->client
.transient_for
= (BlackboxWindow
*) 0;
391 blackbox
->removeWindowSearch(frame
.plate
);
392 XDestroyWindow(blackbox
->getXDisplay(), frame
.plate
);
396 blackbox
->removeWindowSearch(frame
.window
);
397 XDestroyWindow(blackbox
->getXDisplay(), frame
.window
);
400 blackbox
->removeWindowSearch(client
.window
);
404 void BlackboxWindow::enableDecor(bool enable
) {
405 blackbox_attrib
.flags
|= AttribDecoration
;
406 blackbox_attrib
.decoration
= enable
? DecorNormal
: DecorNone
;
409 // we can not be shaded if we lack a titlebar
410 if (! (decorations
& Decor_Titlebar
) && flags
.shaded
)
413 if (flags
.visible
&& frame
.window
) {
414 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
415 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
419 setState(current_state
);
423 void BlackboxWindow::setupDecor() {
424 if (blackbox_attrib
.decoration
!= DecorNone
) {
425 // start with everything on
426 decorations
= Decor_Close
|
427 (mwm_decorations
& Decor_Titlebar
? Decor_Titlebar
: 0) |
428 (mwm_decorations
& Decor_Border
? Decor_Border
: 0) |
429 (mwm_decorations
& Decor_Handle
? Decor_Handle
: 0) |
430 (mwm_decorations
& Decor_Iconify
? Decor_Iconify
: 0) |
431 (mwm_decorations
& Decor_Maximize
? Decor_Maximize
: 0);
433 if (! (functions
& Func_Close
)) decorations
&= ~Decor_Close
;
434 if (! (functions
& Func_Maximize
)) decorations
&= ~Decor_Maximize
;
435 if (! (functions
& Func_Iconify
)) decorations
&= ~Decor_Iconify
;
436 if (! (functions
& Func_Resize
)) decorations
&= ~Decor_Handle
;
438 switch (window_type
) {
443 // none of these windows are decorated by the window manager at all
449 decorations
&= ~(Decor_Border
);
453 decorations
&= ~Decor_Handle
;
465 * Creates a new top level window, with a given location, size, and border
467 * Returns: the newly created window
469 Window
BlackboxWindow::createToplevelWindow(void) {
470 XSetWindowAttributes attrib_create
;
471 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
| CWColormap
|
472 CWOverrideRedirect
| CWEventMask
;
474 attrib_create
.background_pixmap
= None
;
475 attrib_create
.colormap
= screen
->getColormap();
476 attrib_create
.override_redirect
= True
;
477 attrib_create
.event_mask
= EnterWindowMask
| LeaveWindowMask
|
480 We catch button presses because other wise they get passed down to the
481 root window, which will then cause root menus to show when you click the
485 return XCreateWindow(blackbox
->getXDisplay(), screen
->getRootWindow(),
486 0, 0, 1, 1, frame
.border_w
, screen
->getDepth(),
487 InputOutput
, screen
->getVisual(), create_mask
,
493 * Creates a child window, and optionally associates a given cursor with
496 Window
BlackboxWindow::createChildWindow(Window parent
,
497 unsigned long event_mask
,
499 XSetWindowAttributes attrib_create
;
500 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
|
503 attrib_create
.background_pixmap
= None
;
504 attrib_create
.event_mask
= event_mask
;
507 create_mask
|= CWCursor
;
508 attrib_create
.cursor
= cursor
;
511 return XCreateWindow(blackbox
->getXDisplay(), parent
, 0, 0, 1, 1, 0,
512 screen
->getDepth(), InputOutput
, screen
->getVisual(),
513 create_mask
, &attrib_create
);
517 void BlackboxWindow::associateClientWindow(void) {
518 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, 0);
522 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeInsert
);
524 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, SubstructureRedirectMask
);
527 note we used to grab around this call to XReparentWindow however the
528 server is now grabbed before this method is called
530 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
532 XSelectInput(blackbox
->getXDisplay(), client
.window
,
533 event_mask
& ~StructureNotifyMask
);
534 XReparentWindow(blackbox
->getXDisplay(), client
.window
, frame
.plate
, 0, 0);
535 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
537 XRaiseWindow(blackbox
->getXDisplay(), frame
.plate
);
538 XMapSubwindows(blackbox
->getXDisplay(), frame
.plate
);
541 if (blackbox
->hasShapeExtensions()) {
542 XShapeSelectInput(blackbox
->getXDisplay(), client
.window
,
549 XShapeQueryExtents(blackbox
->getXDisplay(), client
.window
, &shaped
,
550 &foo
, &foo
, &ufoo
, &ufoo
, &foo
, &foo
, &foo
,
552 flags
.shaped
= shaped
;
558 void BlackboxWindow::decorate(void) {
561 texture
= &(screen
->getWindowStyle()->b_focus
);
562 frame
.fbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
565 frame
.fbutton_pixel
= texture
->color().pixel();
567 texture
= &(screen
->getWindowStyle()->b_unfocus
);
568 frame
.ubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
571 frame
.ubutton_pixel
= texture
->color().pixel();
573 unsigned char needsPressed
= 0;
575 texture
= &(screen
->getWindowStyle()->b_pressed_focus
);
577 if (texture
->texture() != BTexture::NoTexture
) {
578 frame
.pfbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
580 if (! frame
.pfbutton
)
581 frame
.pfbutton_pixel
= texture
->color().pixel();
586 texture
= &(screen
->getWindowStyle()->b_pressed_unfocus
);
588 if (texture
->texture() != BTexture::NoTexture
) {
589 frame
.pubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
591 if (! frame
.pubutton
)
592 frame
.pubutton
= texture
->color().pixel();
597 // if we either pressed unfocused, or pressed focused were undefined,
598 // make them inherit from the old resource. It's a hack for sure, but
599 // it allows for some backwards and forwards compatibility.
601 texture
= &(screen
->getWindowStyle()->b_pressed
);
603 if (needsPressed
& 0x1) {
604 frame
.pfbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
606 if (! frame
.pfbutton
)
607 frame
.pfbutton_pixel
= texture
->color().pixel();
609 if (needsPressed
& 0x2) {
610 frame
.pubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
612 if (! frame
.pubutton
)
613 frame
.pubutton
= texture
->color().pixel();
618 if (decorations
& Decor_Titlebar
) {
619 texture
= &(screen
->getWindowStyle()->t_focus
);
620 frame
.ftitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
623 frame
.ftitle_pixel
= texture
->color().pixel();
625 texture
= &(screen
->getWindowStyle()->t_unfocus
);
626 frame
.utitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
629 frame
.utitle_pixel
= texture
->color().pixel();
631 XSetWindowBorder(blackbox
->getXDisplay(), frame
.title
,
632 screen
->getBorderColor()->pixel());
637 if (decorations
& Decor_Border
) {
638 frame
.fborder_pixel
= screen
->getWindowStyle()->f_focus
.color().pixel();
639 frame
.uborder_pixel
= screen
->getWindowStyle()->f_unfocus
.color().pixel();
642 if (decorations
& Decor_Handle
) {
643 texture
= &(screen
->getWindowStyle()->h_focus
);
644 frame
.fhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
647 frame
.fhandle_pixel
= texture
->color().pixel();
649 texture
= &(screen
->getWindowStyle()->h_unfocus
);
650 frame
.uhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
653 frame
.uhandle_pixel
= texture
->color().pixel();
655 texture
= &(screen
->getWindowStyle()->g_focus
);
656 frame
.fgrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.fgrip
);
658 frame
.fgrip_pixel
= texture
->color().pixel();
660 texture
= &(screen
->getWindowStyle()->g_unfocus
);
661 frame
.ugrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.ugrip
);
663 frame
.ugrip_pixel
= texture
->color().pixel();
665 XSetWindowBorder(blackbox
->getXDisplay(), frame
.handle
,
666 screen
->getBorderColor()->pixel());
667 XSetWindowBorder(blackbox
->getXDisplay(), frame
.left_grip
,
668 screen
->getBorderColor()->pixel());
669 XSetWindowBorder(blackbox
->getXDisplay(), frame
.right_grip
,
670 screen
->getBorderColor()->pixel());
673 XSetWindowBorder(blackbox
->getXDisplay(), frame
.window
,
674 screen
->getBorderColor()->pixel());
678 void BlackboxWindow::decorateLabel(void) {
681 texture
= &(screen
->getWindowStyle()->l_focus
);
682 frame
.flabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.flabel
);
684 frame
.flabel_pixel
= texture
->color().pixel();
686 texture
= &(screen
->getWindowStyle()->l_unfocus
);
687 frame
.ulabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.ulabel
);
689 frame
.ulabel_pixel
= texture
->color().pixel();
693 void BlackboxWindow::createHandle(void) {
694 frame
.handle
= createChildWindow(frame
.window
,
695 ButtonPressMask
| ButtonReleaseMask
|
696 ButtonMotionMask
| ExposureMask
);
697 blackbox
->saveWindowSearch(frame
.handle
, this);
700 createChildWindow(frame
.handle
,
701 ButtonPressMask
| ButtonReleaseMask
|
702 ButtonMotionMask
| ExposureMask
,
703 blackbox
->getLowerLeftAngleCursor());
704 blackbox
->saveWindowSearch(frame
.left_grip
, this);
707 createChildWindow(frame
.handle
,
708 ButtonPressMask
| ButtonReleaseMask
|
709 ButtonMotionMask
| ExposureMask
,
710 blackbox
->getLowerRightAngleCursor());
711 blackbox
->saveWindowSearch(frame
.right_grip
, this);
715 void BlackboxWindow::destroyHandle(void) {
717 screen
->getImageControl()->removeImage(frame
.fhandle
);
720 screen
->getImageControl()->removeImage(frame
.uhandle
);
723 screen
->getImageControl()->removeImage(frame
.fgrip
);
726 screen
->getImageControl()->removeImage(frame
.ugrip
);
728 blackbox
->removeWindowSearch(frame
.left_grip
);
729 blackbox
->removeWindowSearch(frame
.right_grip
);
731 XDestroyWindow(blackbox
->getXDisplay(), frame
.left_grip
);
732 XDestroyWindow(blackbox
->getXDisplay(), frame
.right_grip
);
733 frame
.left_grip
= frame
.right_grip
= None
;
735 blackbox
->removeWindowSearch(frame
.handle
);
736 XDestroyWindow(blackbox
->getXDisplay(), frame
.handle
);
741 void BlackboxWindow::createTitlebar(void) {
742 frame
.title
= createChildWindow(frame
.window
,
743 ButtonPressMask
| ButtonReleaseMask
|
744 ButtonMotionMask
| ExposureMask
);
745 frame
.label
= createChildWindow(frame
.title
,
746 ButtonPressMask
| ButtonReleaseMask
|
747 ButtonMotionMask
| ExposureMask
);
748 blackbox
->saveWindowSearch(frame
.title
, this);
749 blackbox
->saveWindowSearch(frame
.label
, this);
751 if (decorations
& Decor_Iconify
) createIconifyButton();
752 if (decorations
& Decor_Maximize
) createMaximizeButton();
753 if (decorations
& Decor_Close
) createCloseButton();
757 void BlackboxWindow::destroyTitlebar(void) {
758 if (frame
.close_button
)
759 destroyCloseButton();
761 if (frame
.iconify_button
)
762 destroyIconifyButton();
764 if (frame
.maximize_button
)
765 destroyMaximizeButton();
767 if (frame
.stick_button
)
768 destroyStickyButton();
771 screen
->getImageControl()->removeImage(frame
.ftitle
);
774 screen
->getImageControl()->removeImage(frame
.utitle
);
777 screen
->getImageControl()->removeImage(frame
.flabel
);
780 screen
->getImageControl()->removeImage(frame
.ulabel
);
783 screen
->getImageControl()->removeImage(frame
.fbutton
);
786 screen
->getImageControl()->removeImage(frame
.ubutton
);
788 blackbox
->removeWindowSearch(frame
.title
);
789 blackbox
->removeWindowSearch(frame
.label
);
791 XDestroyWindow(blackbox
->getXDisplay(), frame
.label
);
792 XDestroyWindow(blackbox
->getXDisplay(), frame
.title
);
793 frame
.title
= frame
.label
= None
;
797 void BlackboxWindow::createCloseButton(void) {
798 if (frame
.title
!= None
) {
799 frame
.close_button
= createChildWindow(frame
.title
,
802 ButtonMotionMask
| ExposureMask
);
803 blackbox
->saveWindowSearch(frame
.close_button
, this);
808 void BlackboxWindow::destroyCloseButton(void) {
809 blackbox
->removeWindowSearch(frame
.close_button
);
810 XDestroyWindow(blackbox
->getXDisplay(), frame
.close_button
);
811 frame
.close_button
= None
;
815 void BlackboxWindow::createIconifyButton(void) {
816 if (frame
.title
!= None
) {
817 frame
.iconify_button
= createChildWindow(frame
.title
,
820 ButtonMotionMask
| ExposureMask
);
821 blackbox
->saveWindowSearch(frame
.iconify_button
, this);
826 void BlackboxWindow::destroyIconifyButton(void) {
827 blackbox
->removeWindowSearch(frame
.iconify_button
);
828 XDestroyWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
829 frame
.iconify_button
= None
;
833 void BlackboxWindow::createMaximizeButton(void) {
834 if (frame
.title
!= None
) {
835 frame
.maximize_button
= createChildWindow(frame
.title
,
838 ButtonMotionMask
| ExposureMask
);
839 blackbox
->saveWindowSearch(frame
.maximize_button
, this);
844 void BlackboxWindow::destroyMaximizeButton(void) {
845 blackbox
->removeWindowSearch(frame
.maximize_button
);
846 XDestroyWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
847 frame
.maximize_button
= None
;
850 void BlackboxWindow::createStickyButton(void) {
851 if (frame
.title
!= None
) {
852 frame
.stick_button
= createChildWindow(frame
.title
,
855 ButtonMotionMask
| ExposureMask
);
856 blackbox
->saveWindowSearch(frame
.stick_button
, this);
860 void BlackboxWindow::destroyStickyButton(void) {
861 blackbox
->removeWindowSearch(frame
.stick_button
);
862 XDestroyWindow(blackbox
->getXDisplay(), frame
.stick_button
);
863 frame
.stick_button
= None
;
866 void BlackboxWindow::positionButtons(bool redecorate_label
) {
867 string layout
= blackbox
->getTitlebarLayout();
870 bool hasclose
, hasiconify
, hasmaximize
, haslabel
, hasstick
;
871 hasclose
= hasiconify
= hasmaximize
= haslabel
= hasstick
= false;
873 string::const_iterator it
, end
;
874 for (it
= layout
.begin(), end
= layout
.end(); it
!= end
; ++it
) {
877 if (! hasclose
&& (decorations
& Decor_Close
)) {
883 if (! hasiconify
&& (decorations
& Decor_Iconify
)) {
895 if (! hasmaximize
&& (decorations
& Decor_Maximize
)) {
909 if (! hasclose
&& frame
.close_button
)
910 destroyCloseButton();
911 if (! hasiconify
&& frame
.iconify_button
)
912 destroyIconifyButton();
913 if (! hasmaximize
&& frame
.maximize_button
)
914 destroyMaximizeButton();
915 if (! hasstick
&& frame
.stick_button
)
916 destroyStickyButton();
918 parsed
+= 'L'; // require that the label be in the layout
920 const unsigned int bsep
= frame
.bevel_w
+ 1; // separation between elements
921 const unsigned int by
= frame
.bevel_w
+ 1;
922 const unsigned int ty
= frame
.bevel_w
;
924 frame
.label_w
= frame
.inside_w
- bsep
* 2 -
925 (frame
.button_w
+ bsep
) * (parsed
.size() - 1);
927 unsigned int x
= bsep
;
928 for (it
= parsed
.begin(), end
= parsed
.end(); it
!= end
; ++it
) {
931 if (! frame
.close_button
) createCloseButton();
932 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.close_button
, x
, by
,
933 frame
.button_w
, frame
.button_w
);
934 x
+= frame
.button_w
+ bsep
;
937 if (! frame
.iconify_button
) createIconifyButton();
938 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.iconify_button
, x
, by
,
939 frame
.button_w
, frame
.button_w
);
940 x
+= frame
.button_w
+ bsep
;
943 if (! frame
.stick_button
) createStickyButton();
944 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.stick_button
, x
, by
,
945 frame
.button_w
, frame
.button_w
);
946 x
+= frame
.button_w
+ bsep
;
949 if (! frame
.maximize_button
) createMaximizeButton();
950 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.maximize_button
, x
, by
,
951 frame
.button_w
, frame
.button_w
);
952 x
+= frame
.button_w
+ bsep
;
955 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.label
, x
, ty
,
956 frame
.label_w
, frame
.label_h
);
957 x
+= frame
.label_w
+ bsep
;
962 if (redecorate_label
) decorateLabel();
968 void BlackboxWindow::reconfigure(void) {
969 restoreGravity(client
.rect
);
971 applyGravity(frame
.rect
);
980 windowmenu
->move(windowmenu
->getX(), frame
.rect
.y() + frame
.title_h
);
981 windowmenu
->reconfigure();
986 void BlackboxWindow::grabButtons(void) {
987 mod_mask
= blackbox
->getMouseModMask();
989 if (! screen
->isSloppyFocus() || screen
->doClickRaise())
990 // grab button 1 for changing focus/raising
991 blackbox
->grabButton(Button1
, 0, frame
.plate
, True
, ButtonPressMask
,
992 GrabModeSync
, GrabModeSync
, frame
.plate
, None
,
993 screen
->allowScrollLock());
995 if (functions
& Func_Move
)
996 blackbox
->grabButton(Button1
, mod_mask
, frame
.window
, True
,
997 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
998 GrabModeAsync
, frame
.window
, None
,
999 screen
->allowScrollLock());
1000 if (functions
& Func_Resize
)
1001 blackbox
->grabButton(Button3
, mod_mask
, frame
.window
, True
,
1002 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
1003 GrabModeAsync
, frame
.window
, None
,
1004 screen
->allowScrollLock());
1005 // alt+middle lowers the window
1006 blackbox
->grabButton(Button2
, mod_mask
, frame
.window
, True
,
1007 ButtonReleaseMask
, GrabModeAsync
, GrabModeAsync
,
1008 frame
.window
, None
, screen
->allowScrollLock());
1012 void BlackboxWindow::ungrabButtons(void) {
1013 blackbox
->ungrabButton(Button1
, 0, frame
.plate
);
1014 blackbox
->ungrabButton(Button1
, mod_mask
, frame
.window
);
1015 blackbox
->ungrabButton(Button2
, mod_mask
, frame
.window
);
1016 blackbox
->ungrabButton(Button3
, mod_mask
, frame
.window
);
1020 void BlackboxWindow::positionWindows(void) {
1021 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1022 frame
.rect
.x(), frame
.rect
.y(), frame
.inside_w
,
1023 (flags
.shaded
) ? frame
.title_h
: frame
.inside_h
);
1024 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.window
,
1026 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.plate
,
1027 frame
.mwm_border_w
);
1028 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.plate
,
1029 frame
.margin
.left
- frame
.mwm_border_w
- frame
.border_w
,
1030 frame
.margin
.top
- frame
.mwm_border_w
- frame
.border_w
,
1031 client
.rect
.width(), client
.rect
.height());
1032 XMoveResizeWindow(blackbox
->getXDisplay(), client
.window
,
1033 0, 0, client
.rect
.width(), client
.rect
.height());
1034 // ensure client.rect contains the real location
1035 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1036 frame
.rect
.top() + frame
.margin
.top
);
1038 if (decorations
& Decor_Titlebar
) {
1039 if (frame
.title
== None
) createTitlebar();
1041 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.title
,
1043 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.title
, -frame
.border_w
,
1044 -frame
.border_w
, frame
.inside_w
, frame
.title_h
);
1047 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
1048 XMapWindow(blackbox
->getXDisplay(), frame
.title
);
1049 } else if (frame
.title
) {
1052 if (decorations
& Decor_Handle
) {
1053 if (frame
.handle
== None
) createHandle();
1054 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.handle
,
1056 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.left_grip
,
1058 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.right_grip
,
1061 // use client.rect here so the value is correct even if shaded
1062 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.handle
,
1064 client
.rect
.height() + frame
.margin
.top
+
1065 frame
.mwm_border_w
- frame
.border_w
,
1066 frame
.inside_w
, frame
.handle_h
);
1067 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.left_grip
,
1068 -frame
.border_w
, -frame
.border_w
,
1069 frame
.grip_w
, frame
.handle_h
);
1070 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.right_grip
,
1071 frame
.inside_w
- frame
.grip_w
- frame
.border_w
,
1072 -frame
.border_w
, frame
.grip_w
, frame
.handle_h
);
1074 XMapSubwindows(blackbox
->getXDisplay(), frame
.handle
);
1075 XMapWindow(blackbox
->getXDisplay(), frame
.handle
);
1076 } else if (frame
.handle
) {
1079 XSync(blackbox
->getXDisplay(), False
);
1083 void BlackboxWindow::updateStrut(void) {
1084 unsigned long num
= 4;
1085 unsigned long *data
;
1086 if (! xatom
->getValue(client
.window
, XAtom::net_wm_strut
, XAtom::cardinal
,
1091 client
.strut
.left
= data
[0];
1092 client
.strut
.right
= data
[1];
1093 client
.strut
.top
= data
[2];
1094 client
.strut
.bottom
= data
[3];
1096 screen
->updateAvailableArea();
1103 bool BlackboxWindow::getWindowType(void) {
1104 window_type
= (WindowType
) -1;
1107 unsigned long num
= (unsigned) -1;
1108 if (xatom
->getValue(client
.window
, XAtom::net_wm_window_type
, XAtom::atom
,
1110 for (unsigned long i
= 0; i
< num
; ++i
) {
1111 if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_desktop
))
1112 window_type
= Type_Desktop
;
1113 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_dock
))
1114 window_type
= Type_Dock
;
1115 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_toolbar
))
1116 window_type
= Type_Toolbar
;
1117 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_menu
))
1118 window_type
= Type_Menu
;
1119 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_utility
))
1120 window_type
= Type_Utility
;
1121 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_splash
))
1122 window_type
= Type_Splash
;
1123 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_dialog
))
1124 window_type
= Type_Dialog
;
1125 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_normal
))
1126 window_type
= Type_Normal
;
1128 xatom
->getAtom(XAtom::kde_net_wm_window_type_override
))
1129 mwm_decorations
= 0; // prevent this window from getting any decor
1134 if (window_type
== (WindowType
) -1) {
1136 * the window type hint was not set, which means we either classify ourself
1137 * as a normal window or a dialog, depending on if we are a transient.
1140 window_type
= Type_Dialog
;
1142 window_type
= Type_Normal
;
1151 void BlackboxWindow::getWMName(void) {
1152 if (xatom
->getValue(client
.window
, XAtom::net_wm_name
,
1153 XAtom::utf8
, client
.title
) &&
1154 !client
.title
.empty()) {
1155 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
1158 //fall through to using WM_NAME
1159 if (xatom
->getValue(client
.window
, XAtom::wm_name
, XAtom::ansi
, client
.title
)
1160 && !client
.title
.empty()) {
1161 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
1164 // fall back to an internal default
1165 client
.title
= i18n(WindowSet
, WindowUnnamed
, "Unnamed");
1166 xatom
->setValue(client
.window
, XAtom::net_wm_visible_name
, XAtom::utf8
,
1169 #ifdef DEBUG_WITH_ID
1170 // the 16 is the 8 chars of the debug text plus the number
1171 char *tmp
= new char[client
.title
.length() + 16];
1172 sprintf(tmp
, "%s; id: 0x%lx", client
.title
.c_str(), client
.window
);
1179 void BlackboxWindow::getWMIconName(void) {
1180 if (xatom
->getValue(client
.window
, XAtom::net_wm_icon_name
,
1181 XAtom::utf8
, client
.icon_title
) &&
1182 !client
.icon_title
.empty()) {
1183 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1186 //fall through to using WM_ICON_NAME
1187 if (xatom
->getValue(client
.window
, XAtom::wm_icon_name
, XAtom::ansi
,
1188 client
.icon_title
) &&
1189 !client
.icon_title
.empty()) {
1190 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1193 // fall back to using the main name
1194 client
.icon_title
= client
.title
;
1195 xatom
->setValue(client
.window
, XAtom::net_wm_visible_icon_name
, XAtom::utf8
,
1201 * Retrieve which WM Protocols are supported by the client window.
1202 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
1203 * window's decorations and allow the close behavior.
1204 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
1207 void BlackboxWindow::getWMProtocols(void) {
1211 if (XGetWMProtocols(blackbox
->getXDisplay(), client
.window
,
1212 &proto
, &num_return
)) {
1213 for (int i
= 0; i
< num_return
; ++i
) {
1214 if (proto
[i
] == xatom
->getAtom(XAtom::wm_delete_window
)) {
1215 decorations
|= Decor_Close
;
1216 functions
|= Func_Close
;
1217 } else if (proto
[i
] == xatom
->getAtom(XAtom::wm_take_focus
))
1218 flags
.send_focus_message
= True
;
1219 else if (proto
[i
] == xatom
->getAtom(XAtom::blackbox_structure_messages
))
1220 screen
->addNetizen(new Netizen(screen
, client
.window
));
1229 * Gets the value of the WM_HINTS property.
1230 * If the property is not set, then use a set of default values.
1232 void BlackboxWindow::getWMHints(void) {
1233 focus_mode
= F_Passive
;
1235 // remove from current window group
1236 if (client
.window_group
) {
1237 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1238 if (group
) group
->removeWindow(this);
1240 client
.window_group
= None
;
1242 XWMHints
*wmhint
= XGetWMHints(blackbox
->getXDisplay(), client
.window
);
1247 if (wmhint
->flags
& InputHint
) {
1248 if (wmhint
->input
== True
) {
1249 if (flags
.send_focus_message
)
1250 focus_mode
= F_LocallyActive
;
1252 if (flags
.send_focus_message
)
1253 focus_mode
= F_GloballyActive
;
1255 focus_mode
= F_NoInput
;
1259 if (wmhint
->flags
& StateHint
)
1260 current_state
= wmhint
->initial_state
;
1262 if (wmhint
->flags
& WindowGroupHint
) {
1263 client
.window_group
= wmhint
->window_group
;
1265 // add window to the appropriate group
1266 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1267 if (! group
) { // no group found, create it!
1268 new BWindowGroup(blackbox
, client
.window_group
);
1269 group
= blackbox
->searchGroup(client
.window_group
);
1272 group
->addWindow(this);
1280 * Gets the value of the WM_NORMAL_HINTS property.
1281 * If the property is not set, then use a set of default values.
1283 void BlackboxWindow::getWMNormalHints(void) {
1285 XSizeHints sizehint
;
1287 client
.min_width
= client
.min_height
=
1288 client
.width_inc
= client
.height_inc
= 1;
1289 client
.base_width
= client
.base_height
= 0;
1290 client
.win_gravity
= NorthWestGravity
;
1292 client
.min_aspect_x
= client
.min_aspect_y
=
1293 client
.max_aspect_x
= client
.max_aspect_y
= 1;
1296 // don't limit the size of a window, the default max width is the biggest
1298 client
.max_width
= (unsigned) -1;
1299 client
.max_height
= (unsigned) -1;
1302 if (! XGetWMNormalHints(blackbox
->getXDisplay(), client
.window
,
1303 &sizehint
, &icccm_mask
))
1306 client
.normal_hint_flags
= sizehint
.flags
;
1308 if (sizehint
.flags
& PMinSize
) {
1309 if (sizehint
.min_width
>= 0)
1310 client
.min_width
= sizehint
.min_width
;
1311 if (sizehint
.min_height
>= 0)
1312 client
.min_height
= sizehint
.min_height
;
1315 if (sizehint
.flags
& PMaxSize
) {
1316 if (sizehint
.max_width
> static_cast<signed>(client
.min_width
))
1317 client
.max_width
= sizehint
.max_width
;
1319 client
.max_width
= client
.min_width
;
1321 if (sizehint
.max_height
> static_cast<signed>(client
.min_height
))
1322 client
.max_height
= sizehint
.max_height
;
1324 client
.max_height
= client
.min_height
;
1327 if (sizehint
.flags
& PResizeInc
) {
1328 client
.width_inc
= sizehint
.width_inc
;
1329 client
.height_inc
= sizehint
.height_inc
;
1332 #if 0 // we do not support this at the moment
1333 if (sizehint
.flags
& PAspect
) {
1334 client
.min_aspect_x
= sizehint
.min_aspect
.x
;
1335 client
.min_aspect_y
= sizehint
.min_aspect
.y
;
1336 client
.max_aspect_x
= sizehint
.max_aspect
.x
;
1337 client
.max_aspect_y
= sizehint
.max_aspect
.y
;
1341 if (sizehint
.flags
& PBaseSize
) {
1342 client
.base_width
= sizehint
.base_width
;
1343 client
.base_height
= sizehint
.base_height
;
1346 if (sizehint
.flags
& PWinGravity
)
1347 client
.win_gravity
= sizehint
.win_gravity
;
1352 * Gets the NETWM hints for the class' contained window.
1354 void BlackboxWindow::getNetWMHints(void) {
1355 unsigned long workspace
;
1357 if (xatom
->getValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1359 if (workspace
== 0xffffffff)
1362 blackbox_attrib
.workspace
= workspace
;
1365 unsigned long *state
;
1366 unsigned long num
= (unsigned) -1;
1367 if (xatom
->getValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
1371 for (unsigned long i
= 0; i
< num
; ++i
) {
1372 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
))
1374 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_shaded
))
1375 flags
.shaded
= True
;
1376 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
))
1377 flags
.skip_taskbar
= True
;
1378 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_pager
))
1379 flags
.skip_pager
= True
;
1380 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_fullscreen
))
1381 flags
.fullscreen
= True
;
1382 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_hidden
))
1383 setState(IconicState
);
1384 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_vert
))
1386 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_horz
))
1390 flags
.maximized
= 1;
1392 flags
.maximized
= 2;
1394 flags
.maximized
= 3;
1402 * Gets the MWM hints for the class' contained window.
1403 * This is used while initializing the window to its first state, and not
1405 * Returns: true if the MWM hints are successfully retreived and applied;
1406 * false if they are not.
1408 void BlackboxWindow::getMWMHints(void) {
1412 num
= PropMwmHintsElements
;
1413 if (! xatom
->getValue(client
.window
, XAtom::motif_wm_hints
,
1414 XAtom::motif_wm_hints
, num
,
1415 (unsigned long **)&mwm_hint
))
1417 if (num
< PropMwmHintsElements
) {
1422 if (mwm_hint
->flags
& MwmHintsDecorations
) {
1423 if (mwm_hint
->decorations
& MwmDecorAll
) {
1424 mwm_decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
1425 Decor_Iconify
| Decor_Maximize
;
1427 mwm_decorations
= 0;
1429 if (mwm_hint
->decorations
& MwmDecorBorder
)
1430 mwm_decorations
|= Decor_Border
;
1431 if (mwm_hint
->decorations
& MwmDecorHandle
)
1432 mwm_decorations
|= Decor_Handle
;
1433 if (mwm_hint
->decorations
& MwmDecorTitle
)
1434 mwm_decorations
|= Decor_Titlebar
;
1435 if (mwm_hint
->decorations
& MwmDecorIconify
)
1436 mwm_decorations
|= Decor_Iconify
;
1437 if (mwm_hint
->decorations
& MwmDecorMaximize
)
1438 mwm_decorations
|= Decor_Maximize
;
1442 if (mwm_hint
->flags
& MwmHintsFunctions
) {
1443 if (mwm_hint
->functions
& MwmFuncAll
) {
1444 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
|
1449 if (mwm_hint
->functions
& MwmFuncResize
)
1450 functions
|= Func_Resize
;
1451 if (mwm_hint
->functions
& MwmFuncMove
)
1452 functions
|= Func_Move
;
1453 if (mwm_hint
->functions
& MwmFuncIconify
)
1454 functions
|= Func_Iconify
;
1455 if (mwm_hint
->functions
& MwmFuncMaximize
)
1456 functions
|= Func_Maximize
;
1457 if (mwm_hint
->functions
& MwmFuncClose
)
1458 functions
|= Func_Close
;
1466 * Gets the blackbox hints from the class' contained window.
1467 * This is used while initializing the window to its first state, and not
1469 * Returns: true if the hints are successfully retreived and applied; false if
1472 bool BlackboxWindow::getBlackboxHints(void) {
1474 BlackboxHints
*blackbox_hint
;
1476 num
= PropBlackboxHintsElements
;
1477 if (! xatom
->getValue(client
.window
, XAtom::blackbox_hints
,
1478 XAtom::blackbox_hints
, num
,
1479 (unsigned long **)&blackbox_hint
))
1481 if (num
< PropBlackboxHintsElements
) {
1482 delete [] blackbox_hint
;
1486 if (blackbox_hint
->flags
& AttribShaded
)
1487 flags
.shaded
= (blackbox_hint
->attrib
& AttribShaded
);
1489 if ((blackbox_hint
->flags
& AttribMaxHoriz
) &&
1490 (blackbox_hint
->flags
& AttribMaxVert
))
1491 flags
.maximized
= (blackbox_hint
->attrib
&
1492 (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1493 else if (blackbox_hint
->flags
& AttribMaxVert
)
1494 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxVert
) ? 2 : 0;
1495 else if (blackbox_hint
->flags
& AttribMaxHoriz
)
1496 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1498 if (blackbox_hint
->flags
& AttribOmnipresent
)
1499 flags
.stuck
= (blackbox_hint
->attrib
& AttribOmnipresent
);
1501 if (blackbox_hint
->flags
& AttribWorkspace
)
1502 blackbox_attrib
.workspace
= blackbox_hint
->workspace
;
1504 // if (blackbox_hint->flags & AttribStack)
1505 // don't yet have always on top/bottom for blackbox yet... working
1508 if (blackbox_hint
->flags
& AttribDecoration
) {
1509 switch (blackbox_hint
->decoration
) {
1511 blackbox_attrib
.decoration
= DecorNone
;
1518 // blackbox_attrib.decoration defaults to DecorNormal
1523 delete [] blackbox_hint
;
1529 void BlackboxWindow::getTransientInfo(void) {
1530 if (client
.transient_for
&&
1531 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1532 // reset transient_for in preparation of looking for a new owner
1533 client
.transient_for
->client
.transientList
.remove(this);
1536 // we have no transient_for until we find a new one
1537 client
.transient_for
= (BlackboxWindow
*) 0;
1540 if (! XGetTransientForHint(blackbox
->getXDisplay(), client
.window
,
1542 // transient_for hint not set
1546 if (trans_for
== client
.window
) {
1547 // wierd client... treat this window as a normal window
1551 if (trans_for
== None
|| trans_for
== screen
->getRootWindow()) {
1552 // this is an undocumented interpretation of the ICCCM. a transient
1553 // associated with None/Root/itself is assumed to be a modal root
1554 // transient. we don't support the concept of a global transient,
1555 // so we just associate this transient with nothing, and perhaps
1556 // we will add support later for global modality.
1557 client
.transient_for
= (BlackboxWindow
*) ~0ul;
1562 client
.transient_for
= blackbox
->searchWindow(trans_for
);
1563 if (! client
.transient_for
&&
1564 client
.window_group
&& trans_for
== client
.window_group
) {
1565 // no direct transient_for, perhaps this is a group transient?
1566 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1567 if (group
) client
.transient_for
= group
->find(screen
);
1570 if (! client
.transient_for
|| client
.transient_for
== this) {
1571 // no transient_for found, or we have a wierd client that wants to be
1572 // a transient for itself, so we treat this window as a normal window
1573 client
.transient_for
= (BlackboxWindow
*) 0;
1577 // Check for a circular transient state: this can lock up Blackbox
1578 // when it tries to find the non-transient window for a transient.
1579 BlackboxWindow
*w
= this;
1580 while(w
->client
.transient_for
&&
1581 w
->client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1582 if(w
->client
.transient_for
== this) {
1583 client
.transient_for
= (BlackboxWindow
*) 0;
1586 w
= w
->client
.transient_for
;
1589 if (client
.transient_for
&&
1590 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1591 // register ourselves with our new transient_for
1592 client
.transient_for
->client
.transientList
.push_back(this);
1593 flags
.stuck
= client
.transient_for
->flags
.stuck
;
1598 BlackboxWindow
*BlackboxWindow::getTransientFor(void) const {
1599 if (client
.transient_for
&&
1600 client
.transient_for
!= (BlackboxWindow
*) ~0ul)
1601 return client
.transient_for
;
1607 * This function is responsible for updating both the client and the frame
1609 * According to the ICCCM a client message is not sent for a resize, only a
1612 void BlackboxWindow::configure(int dx
, int dy
,
1613 unsigned int dw
, unsigned int dh
) {
1614 bool send_event
= ((frame
.rect
.x() != dx
|| frame
.rect
.y() != dy
) &&
1617 if (dw
!= frame
.rect
.width() || dh
!= frame
.rect
.height()) {
1618 frame
.rect
.setRect(dx
, dy
, dw
, dh
);
1619 frame
.inside_w
= frame
.rect
.width() - (frame
.border_w
* 2);
1620 frame
.inside_h
= frame
.rect
.height() - (frame
.border_w
* 2);
1622 if (frame
.rect
.right() <= 0 || frame
.rect
.bottom() <= 0)
1623 frame
.rect
.setPos(0, 0);
1625 client
.rect
.setCoords(frame
.rect
.left() + frame
.margin
.left
,
1626 frame
.rect
.top() + frame
.margin
.top
,
1627 frame
.rect
.right() - frame
.margin
.right
,
1628 frame
.rect
.bottom() - frame
.margin
.bottom
);
1631 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
1638 redrawWindowFrame();
1640 frame
.rect
.setPos(dx
, dy
);
1642 XMoveWindow(blackbox
->getXDisplay(), frame
.window
,
1643 frame
.rect
.x(), frame
.rect
.y());
1645 we may have been called just after an opaque window move, so even though
1646 the old coords match the new ones no ConfigureNotify has been sent yet.
1647 There are likely other times when this will be relevant as well.
1649 if (! flags
.moving
) send_event
= True
;
1653 // if moving, the update and event will occur when the move finishes
1654 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1655 frame
.rect
.top() + frame
.margin
.top
);
1658 event
.type
= ConfigureNotify
;
1660 event
.xconfigure
.display
= blackbox
->getXDisplay();
1661 event
.xconfigure
.event
= client
.window
;
1662 event
.xconfigure
.window
= client
.window
;
1663 event
.xconfigure
.x
= client
.rect
.x();
1664 event
.xconfigure
.y
= client
.rect
.y();
1665 event
.xconfigure
.width
= client
.rect
.width();
1666 event
.xconfigure
.height
= client
.rect
.height();
1667 event
.xconfigure
.border_width
= client
.old_bw
;
1668 event
.xconfigure
.above
= frame
.window
;
1669 event
.xconfigure
.override_redirect
= False
;
1671 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1672 StructureNotifyMask
, &event
);
1673 screen
->updateNetizenConfigNotify(&event
);
1674 XFlush(blackbox
->getXDisplay());
1680 void BlackboxWindow::configureShape(void) {
1681 XShapeCombineShape(blackbox
->getXDisplay(), frame
.window
, ShapeBounding
,
1682 frame
.margin
.left
- frame
.border_w
,
1683 frame
.margin
.top
- frame
.border_w
,
1684 client
.window
, ShapeBounding
, ShapeSet
);
1687 XRectangle xrect
[2];
1689 if (decorations
& Decor_Titlebar
) {
1690 xrect
[0].x
= xrect
[0].y
= -frame
.border_w
;
1691 xrect
[0].width
= frame
.rect
.width();
1692 xrect
[0].height
= frame
.title_h
+ (frame
.border_w
* 2);
1696 if (decorations
& Decor_Handle
) {
1697 xrect
[1].x
= -frame
.border_w
;
1698 xrect
[1].y
= frame
.rect
.height() - frame
.margin
.bottom
+
1699 frame
.mwm_border_w
- frame
.border_w
;
1700 xrect
[1].width
= frame
.rect
.width();
1701 xrect
[1].height
= frame
.handle_h
+ (frame
.border_w
* 2);
1705 XShapeCombineRectangles(blackbox
->getXDisplay(), frame
.window
,
1706 ShapeBounding
, 0, 0, xrect
, num
,
1707 ShapeUnion
, Unsorted
);
1711 void BlackboxWindow::clearShape(void) {
1712 XShapeCombineMask(blackbox
->getXDisplay(), frame
.window
, ShapeBounding
,
1713 frame
.margin
.left
- frame
.border_w
,
1714 frame
.margin
.top
- frame
.border_w
,
1720 bool BlackboxWindow::setInputFocus(void) {
1721 if (flags
.focused
) return True
;
1723 assert(flags
.stuck
|| // window must be on the current workspace or sticky
1724 blackbox_attrib
.workspace
== screen
->getCurrentWorkspaceID());
1727 We only do this check for normal windows and dialogs because other windows
1728 do this on purpose, such as kde's kicker, and we don't want to go moving
1731 if (window_type
== Type_Normal
|| window_type
== Type_Dialog
)
1732 if (! frame
.rect
.intersects(screen
->getRect())) {
1733 // client is outside the screen, move it to the center
1734 configure((screen
->getWidth() - frame
.rect
.width()) / 2,
1735 (screen
->getHeight() - frame
.rect
.height()) / 2,
1736 frame
.rect
.width(), frame
.rect
.height());
1739 if (client
.transientList
.size() > 0) {
1740 // transfer focus to any modal transients
1741 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1742 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1743 if ((*it
)->flags
.modal
) return (*it
)->setInputFocus();
1747 if (focus_mode
== F_LocallyActive
|| focus_mode
== F_Passive
) {
1748 XSetInputFocus(blackbox
->getXDisplay(), client
.window
,
1749 RevertToPointerRoot
, CurrentTime
);
1751 /* we could set the focus to none, since the window doesn't accept focus,
1752 * but we shouldn't set focus to nothing since this would surely make
1758 if (flags
.send_focus_message
) {
1760 ce
.xclient
.type
= ClientMessage
;
1761 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1762 ce
.xclient
.display
= blackbox
->getXDisplay();
1763 ce
.xclient
.window
= client
.window
;
1764 ce
.xclient
.format
= 32;
1765 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_take_focus
);
1766 ce
.xclient
.data
.l
[1] = blackbox
->getLastTime();
1767 ce
.xclient
.data
.l
[2] = 0l;
1768 ce
.xclient
.data
.l
[3] = 0l;
1769 ce
.xclient
.data
.l
[4] = 0l;
1770 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1772 XFlush(blackbox
->getXDisplay());
1779 void BlackboxWindow::iconify(void) {
1780 if (flags
.iconic
|| ! (functions
& Func_Iconify
)) return;
1782 // We don't need to worry about resizing because resizing always grabs the X
1783 // server. This should only ever happen if using opaque moving.
1787 if (windowmenu
) windowmenu
->hide();
1790 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1791 * we need to clear the event mask on client.window for a split second.
1792 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1793 * split second, leaving us with a ghost window... so, we need to do this
1794 * while the X server is grabbed
1796 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1797 StructureNotifyMask
;
1798 XGrabServer(blackbox
->getXDisplay());
1799 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1800 event_mask
& ~StructureNotifyMask
);
1801 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1802 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1803 XUngrabServer(blackbox
->getXDisplay());
1805 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1806 flags
.visible
= False
;
1807 flags
.iconic
= True
;
1809 setState(IconicState
);
1811 screen
->getWorkspace(blackbox_attrib
.workspace
)->removeWindow(this);
1813 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
1814 if (i
!= blackbox_attrib
.workspace
)
1815 screen
->getWorkspace(i
)->removeWindow(this, True
);
1818 if (isTransient()) {
1819 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1820 ! client
.transient_for
->flags
.iconic
) {
1821 // iconify our transient_for
1822 client
.transient_for
->iconify();
1826 screen
->addIcon(this);
1828 if (client
.transientList
.size() > 0) {
1829 // iconify all transients
1830 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1831 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1832 if (! (*it
)->flags
.iconic
) (*it
)->iconify();
1835 screen
->updateStackingList();
1839 void BlackboxWindow::show(void) {
1840 flags
.visible
= True
;
1841 flags
.iconic
= False
;
1843 current_state
= (flags
.shaded
) ? IconicState
: NormalState
;
1844 setState(current_state
);
1846 XMapWindow(blackbox
->getXDisplay(), client
.window
);
1847 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
1848 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
1853 XTranslateCoordinates(blackbox
->getXDisplay(), client
.window
,
1854 screen
->getRootWindow(),
1855 0, 0, &real_x
, &real_y
, &child
);
1856 fprintf(stderr
, "%s -- assumed: (%d, %d), real: (%d, %d)\n", getTitle(),
1857 client
.rect
.left(), client
.rect
.top(), real_x
, real_y
);
1858 assert(client
.rect
.left() == real_x
&& client
.rect
.top() == real_y
);
1863 void BlackboxWindow::deiconify(bool reassoc
, bool raise
) {
1864 if (flags
.iconic
|| reassoc
)
1865 screen
->reassociateWindow(this, BSENTINEL
, False
);
1866 else if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID())
1871 // reassociate and deiconify all transients
1872 if (reassoc
&& client
.transientList
.size() > 0) {
1873 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1874 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1875 (*it
)->deiconify(True
, False
);
1879 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1883 void BlackboxWindow::close(void) {
1884 if (! (functions
& Func_Close
)) return;
1887 ce
.xclient
.type
= ClientMessage
;
1888 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1889 ce
.xclient
.display
= blackbox
->getXDisplay();
1890 ce
.xclient
.window
= client
.window
;
1891 ce
.xclient
.format
= 32;
1892 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_delete_window
);
1893 ce
.xclient
.data
.l
[1] = CurrentTime
;
1894 ce
.xclient
.data
.l
[2] = 0l;
1895 ce
.xclient
.data
.l
[3] = 0l;
1896 ce
.xclient
.data
.l
[4] = 0l;
1897 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
, NoEventMask
, &ce
);
1898 XFlush(blackbox
->getXDisplay());
1902 void BlackboxWindow::withdraw(void) {
1903 // We don't need to worry about resizing because resizing always grabs the X
1904 // server. This should only ever happen if using opaque moving.
1908 flags
.visible
= False
;
1909 flags
.iconic
= False
;
1911 setState(current_state
);
1913 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1915 XGrabServer(blackbox
->getXDisplay());
1917 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1918 StructureNotifyMask
;
1919 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1920 event_mask
& ~StructureNotifyMask
);
1921 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1922 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1924 XUngrabServer(blackbox
->getXDisplay());
1926 if (windowmenu
) windowmenu
->hide();
1930 void BlackboxWindow::maximize(unsigned int button
) {
1931 if (! (functions
& Func_Maximize
)) return;
1933 // We don't need to worry about resizing because resizing always grabs the X
1934 // server. This should only ever happen if using opaque moving.
1938 // handle case where menu is open then the max button is used instead
1939 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
1941 if (flags
.maximized
) {
1942 flags
.maximized
= 0;
1944 blackbox_attrib
.flags
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1945 blackbox_attrib
.attrib
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1948 when a resize finishes, maximize(0) is called to clear any maximization
1949 flags currently set. Otherwise it still thinks it is maximized.
1950 so we do not need to call configure() because resizing will handle it
1952 if (! flags
.resizing
)
1953 configure(blackbox_attrib
.premax_x
, blackbox_attrib
.premax_y
,
1954 blackbox_attrib
.premax_w
, blackbox_attrib
.premax_h
);
1956 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
1957 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
1959 redrawAllButtons(); // in case it is not called in configure()
1960 setState(current_state
);
1964 blackbox_attrib
.premax_x
= frame
.rect
.x();
1965 blackbox_attrib
.premax_y
= frame
.rect
.y();
1966 blackbox_attrib
.premax_w
= frame
.rect
.width();
1967 // use client.rect so that clients can be restored even if shaded
1968 blackbox_attrib
.premax_h
=
1969 client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
;
1972 if (screen
->isXineramaActive() && blackbox
->doXineramaMaximizing()) {
1973 // find the area to use
1974 RectList availableAreas
= screen
->allAvailableAreas();
1975 RectList::iterator it
, end
= availableAreas
.end();
1977 for (it
= availableAreas
.begin(); it
!= end
; ++it
)
1978 if (it
->intersects(frame
.rect
)) break;
1979 if (it
== end
) // the window isn't inside an area
1980 it
= availableAreas
.begin(); // so just default to the first one
1982 frame
.changing
= *it
;
1985 frame
.changing
= screen
->availableArea();
1989 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1990 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1994 blackbox_attrib
.flags
|= AttribMaxVert
;
1995 blackbox_attrib
.attrib
|= AttribMaxVert
;
1997 frame
.changing
.setX(frame
.rect
.x());
1998 frame
.changing
.setWidth(frame
.rect
.width());
2002 blackbox_attrib
.flags
|= AttribMaxHoriz
;
2003 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
2005 frame
.changing
.setY(frame
.rect
.y());
2006 frame
.changing
.setHeight(frame
.rect
.height());
2013 blackbox_attrib
.flags
^= AttribShaded
;
2014 blackbox_attrib
.attrib
^= AttribShaded
;
2015 flags
.shaded
= False
;
2018 flags
.maximized
= button
;
2020 configure(frame
.changing
.x(), frame
.changing
.y(),
2021 frame
.changing
.width(), frame
.changing
.height());
2023 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2024 redrawAllButtons(); // in case it is not called in configure()
2025 setState(current_state
);
2029 // re-maximizes the window to take into account availableArea changes
2030 void BlackboxWindow::remaximize(void) {
2032 // we only update the window's attributes otherwise we lose the shade bit
2033 switch(flags
.maximized
) {
2035 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
2036 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
2040 blackbox_attrib
.flags
|= AttribMaxVert
;
2041 blackbox_attrib
.attrib
|= AttribMaxVert
;
2045 blackbox_attrib
.flags
|= AttribMaxHoriz
;
2046 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
2052 // save the original dimensions because maximize will wipe them out
2053 int premax_x
= blackbox_attrib
.premax_x
,
2054 premax_y
= blackbox_attrib
.premax_y
,
2055 premax_w
= blackbox_attrib
.premax_w
,
2056 premax_h
= blackbox_attrib
.premax_h
;
2058 unsigned int button
= flags
.maximized
;
2059 flags
.maximized
= 0; // trick maximize() into working
2062 // restore saved values
2063 blackbox_attrib
.premax_x
= premax_x
;
2064 blackbox_attrib
.premax_y
= premax_y
;
2065 blackbox_attrib
.premax_w
= premax_w
;
2066 blackbox_attrib
.premax_h
= premax_h
;
2070 void BlackboxWindow::setWorkspace(unsigned int n
) {
2071 blackbox_attrib
.flags
|= AttribWorkspace
;
2072 blackbox_attrib
.workspace
= n
;
2073 if (n
== BSENTINEL
) { // iconified window
2075 we set the workspace to 'all workspaces' so that taskbars will show the
2076 window. otherwise, it made uniconifying a window imposible without the
2077 blackbox workspace menu
2081 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
, n
);
2085 void BlackboxWindow::shade(void) {
2087 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
2088 frame
.inside_w
, frame
.inside_h
);
2089 flags
.shaded
= False
;
2090 blackbox_attrib
.flags
^= AttribShaded
;
2091 blackbox_attrib
.attrib
^= AttribShaded
;
2093 setState(NormalState
);
2095 // set the frame rect to the normal size
2096 frame
.rect
.setHeight(client
.rect
.height() + frame
.margin
.top
+
2097 frame
.margin
.bottom
);
2099 if (! (decorations
& Decor_Titlebar
))
2100 return; // can't shade it without a titlebar!
2102 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
2103 frame
.inside_w
, frame
.title_h
);
2104 flags
.shaded
= True
;
2105 blackbox_attrib
.flags
|= AttribShaded
;
2106 blackbox_attrib
.attrib
|= AttribShaded
;
2108 setState(IconicState
);
2110 // set the frame rect to the shaded size
2111 frame
.rect
.setHeight(frame
.title_h
+ (frame
.border_w
* 2));
2117 * (Un)Sticks a window and its relatives.
2119 void BlackboxWindow::stick(void) {
2121 blackbox_attrib
.flags
^= AttribOmnipresent
;
2122 blackbox_attrib
.attrib
^= AttribOmnipresent
;
2124 flags
.stuck
= False
;
2126 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
2127 if (i
!= blackbox_attrib
.workspace
)
2128 screen
->getWorkspace(i
)->removeWindow(this, True
);
2131 screen
->reassociateWindow(this, BSENTINEL
, True
);
2132 // temporary fix since sticky windows suck. set the hint to what we
2133 // actually hold in our data.
2134 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
2135 blackbox_attrib
.workspace
);
2137 setState(current_state
);
2141 blackbox_attrib
.flags
|= AttribOmnipresent
;
2142 blackbox_attrib
.attrib
|= AttribOmnipresent
;
2144 // temporary fix since sticky windows suck. set the hint to a different
2145 // value than that contained in the class' data.
2146 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
2149 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
2150 if (i
!= blackbox_attrib
.workspace
)
2151 screen
->getWorkspace(i
)->addWindow(this, False
, True
);
2153 setState(current_state
);
2159 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
2160 client
.transient_for
->isStuck() != flags
.stuck
)
2161 client
.transient_for
->stick();
2162 // go down the chain
2163 BlackboxWindowList::iterator it
;
2164 const BlackboxWindowList::iterator end
= client
.transientList
.end();
2165 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
2166 if ((*it
)->isStuck() != flags
.stuck
)
2171 void BlackboxWindow::redrawWindowFrame(void) const {
2172 if (decorations
& Decor_Titlebar
) {
2173 if (flags
.focused
) {
2175 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2176 frame
.title
, frame
.ftitle
);
2178 XSetWindowBackground(blackbox
->getXDisplay(),
2179 frame
.title
, frame
.ftitle_pixel
);
2182 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2183 frame
.title
, frame
.utitle
);
2185 XSetWindowBackground(blackbox
->getXDisplay(),
2186 frame
.title
, frame
.utitle_pixel
);
2188 XClearWindow(blackbox
->getXDisplay(), frame
.title
);
2194 if (decorations
& Decor_Handle
) {
2195 if (flags
.focused
) {
2197 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2198 frame
.handle
, frame
.fhandle
);
2200 XSetWindowBackground(blackbox
->getXDisplay(),
2201 frame
.handle
, frame
.fhandle_pixel
);
2204 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2205 frame
.left_grip
, frame
.fgrip
);
2206 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2207 frame
.right_grip
, frame
.fgrip
);
2209 XSetWindowBackground(blackbox
->getXDisplay(),
2210 frame
.left_grip
, frame
.fgrip_pixel
);
2211 XSetWindowBackground(blackbox
->getXDisplay(),
2212 frame
.right_grip
, frame
.fgrip_pixel
);
2216 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2217 frame
.handle
, frame
.uhandle
);
2219 XSetWindowBackground(blackbox
->getXDisplay(),
2220 frame
.handle
, frame
.uhandle_pixel
);
2223 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2224 frame
.left_grip
, frame
.ugrip
);
2225 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2226 frame
.right_grip
, frame
.ugrip
);
2228 XSetWindowBackground(blackbox
->getXDisplay(),
2229 frame
.left_grip
, frame
.ugrip_pixel
);
2230 XSetWindowBackground(blackbox
->getXDisplay(),
2231 frame
.right_grip
, frame
.ugrip_pixel
);
2234 XClearWindow(blackbox
->getXDisplay(), frame
.handle
);
2235 XClearWindow(blackbox
->getXDisplay(), frame
.left_grip
);
2236 XClearWindow(blackbox
->getXDisplay(), frame
.right_grip
);
2239 if (decorations
& Decor_Border
) {
2241 XSetWindowBorder(blackbox
->getXDisplay(),
2242 frame
.plate
, frame
.fborder_pixel
);
2244 XSetWindowBorder(blackbox
->getXDisplay(),
2245 frame
.plate
, frame
.uborder_pixel
);
2250 void BlackboxWindow::setFocusFlag(bool focus
) {
2251 // only focus a window if it is visible
2252 if (focus
&& ! flags
.visible
)
2255 flags
.focused
= focus
;
2257 redrawWindowFrame();
2260 blackbox
->setFocusedWindow(this);
2262 if (! flags
.iconic
) {
2263 // iconic windows arent in a workspace menu!
2265 screen
->getCurrentWorkspace()->setFocused(this, isFocused());
2267 screen
->getWorkspace(blackbox_attrib
.workspace
)->
2268 setFocused(this, flags
.focused
);
2273 void BlackboxWindow::installColormap(bool install
) {
2274 int i
= 0, ncmap
= 0;
2275 Colormap
*cmaps
= XListInstalledColormaps(blackbox
->getXDisplay(),
2276 client
.window
, &ncmap
);
2278 XWindowAttributes wattrib
;
2279 if (XGetWindowAttributes(blackbox
->getXDisplay(),
2280 client
.window
, &wattrib
)) {
2282 // install the window's colormap
2283 for (i
= 0; i
< ncmap
; i
++) {
2284 if (*(cmaps
+ i
) == wattrib
.colormap
)
2285 // this window is using an installed color map... do not install
2288 // otherwise, install the window's colormap
2290 XInstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2292 // uninstall the window's colormap
2293 for (i
= 0; i
< ncmap
; i
++) {
2294 if (*(cmaps
+ i
) == wattrib
.colormap
)
2295 // we found the colormap to uninstall
2296 XUninstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2306 void BlackboxWindow::setAllowedActions(void) {
2310 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_shade
);
2311 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_change_desktop
);
2312 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_close
);
2314 if (functions
& Func_Move
)
2315 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_move
);
2316 if (functions
& Func_Resize
)
2317 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_resize
);
2318 if (functions
& Func_Maximize
) {
2319 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_horz
);
2320 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_vert
);
2323 xatom
->setValue(client
.window
, XAtom::net_wm_allowed_actions
, XAtom::atom
,
2328 void BlackboxWindow::setState(unsigned long new_state
) {
2329 current_state
= new_state
;
2331 unsigned long state
[2];
2332 state
[0] = current_state
;
2334 xatom
->setValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
, state
, 2);
2336 xatom
->setValue(client
.window
, XAtom::blackbox_attributes
,
2337 XAtom::blackbox_attributes
, (unsigned long *)&blackbox_attrib
,
2338 PropBlackboxAttributesElements
);
2343 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_modal
);
2345 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_shaded
);
2347 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_hidden
);
2348 if (flags
.skip_taskbar
)
2349 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
);
2350 if (flags
.skip_pager
)
2351 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_pager
);
2352 if (flags
.fullscreen
)
2353 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_fullscreen
);
2354 if (flags
.maximized
== 1 || flags
.maximized
== 2)
2355 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_vert
);
2356 if (flags
.maximized
== 1 || flags
.maximized
== 3)
2357 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_horz
);
2358 xatom
->setValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
2363 bool BlackboxWindow::getState(void) {
2364 bool ret
= xatom
->getValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
,
2366 if (! ret
) current_state
= 0;
2371 void BlackboxWindow::restoreAttributes(void) {
2372 unsigned long num
= PropBlackboxAttributesElements
;
2373 BlackboxAttributes
*net
;
2374 if (! xatom
->getValue(client
.window
, XAtom::blackbox_attributes
,
2375 XAtom::blackbox_attributes
, num
,
2376 (unsigned long **)&net
))
2378 if (num
< PropBlackboxAttributesElements
) {
2383 if (net
->flags
& AttribShaded
&& net
->attrib
& AttribShaded
) {
2384 flags
.shaded
= False
;
2385 unsigned long orig_state
= current_state
;
2389 At this point in the life of a window, current_state should only be set
2390 to IconicState if the window was an *icon*, not if it was shaded.
2392 if (orig_state
!= IconicState
)
2393 current_state
= WithdrawnState
;
2396 if (net
->workspace
!= screen
->getCurrentWorkspaceID() &&
2397 net
->workspace
< screen
->getWorkspaceCount())
2398 screen
->reassociateWindow(this, net
->workspace
, True
);
2400 if ((blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID()) &&
2401 (blackbox_attrib
.workspace
< screen
->getWorkspaceCount())) {
2402 // set to WithdrawnState so it will be mapped on the new workspace
2403 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2404 } else if (current_state
== WithdrawnState
) {
2405 // the window is on this workspace and is Withdrawn, so it is waiting to
2407 current_state
= NormalState
;
2410 if (net
->flags
& AttribOmnipresent
&& net
->attrib
& AttribOmnipresent
&&
2414 // if the window was on another workspace, it was going to be hidden. this
2415 // specifies that the window should be mapped since it is sticky.
2416 if (current_state
== WithdrawnState
) current_state
= NormalState
;
2419 if (net
->flags
& AttribMaxHoriz
|| net
->flags
& AttribMaxVert
) {
2420 int x
= net
->premax_x
, y
= net
->premax_y
;
2421 unsigned int w
= net
->premax_w
, h
= net
->premax_h
;
2422 flags
.maximized
= 0;
2425 if ((net
->flags
& AttribMaxHoriz
) &&
2426 (net
->flags
& AttribMaxVert
))
2427 m
= (net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
2428 else if (net
->flags
& AttribMaxVert
)
2429 m
= (net
->attrib
& AttribMaxVert
) ? 2 : 0;
2430 else if (net
->flags
& AttribMaxHoriz
)
2431 m
= (net
->attrib
& AttribMaxHoriz
) ? 3 : 0;
2435 blackbox_attrib
.premax_x
= x
;
2436 blackbox_attrib
.premax_y
= y
;
2437 blackbox_attrib
.premax_w
= w
;
2438 blackbox_attrib
.premax_h
= h
;
2441 if (net
->flags
& AttribDecoration
) {
2442 switch (net
->decoration
) {
2447 /* since tools only let you toggle this anyways, we'll just make that all
2448 it supports for now.
2459 // with the state set it will then be the map event's job to read the
2460 // window's state and behave accordingly
2467 * Positions the Rect r according the the client window position and
2470 void BlackboxWindow::applyGravity(Rect
&r
) {
2471 // apply horizontal window gravity
2472 switch (client
.win_gravity
) {
2474 case NorthWestGravity
:
2475 case SouthWestGravity
:
2477 r
.setX(client
.rect
.x());
2483 r
.setX(client
.rect
.x() - (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2486 case NorthEastGravity
:
2487 case SouthEastGravity
:
2489 r
.setX(client
.rect
.x() - frame
.margin
.left
- frame
.margin
.right
+ 2);
2494 r
.setX(client
.rect
.x() - frame
.margin
.left
);
2498 // apply vertical window gravity
2499 switch (client
.win_gravity
) {
2501 case NorthWestGravity
:
2502 case NorthEastGravity
:
2504 r
.setY(client
.rect
.y());
2510 r
.setY(client
.rect
.y() - (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2513 case SouthWestGravity
:
2514 case SouthEastGravity
:
2516 r
.setY(client
.rect
.y() - frame
.margin
.top
- frame
.margin
.bottom
+ 2);
2521 r
.setY(client
.rect
.y() - frame
.margin
.top
);
2528 * The reverse of the applyGravity function.
2530 * Positions the Rect r according to the frame window position and
2533 void BlackboxWindow::restoreGravity(Rect
&r
) {
2534 // restore horizontal window gravity
2535 switch (client
.win_gravity
) {
2537 case NorthWestGravity
:
2538 case SouthWestGravity
:
2540 r
.setX(frame
.rect
.x());
2546 r
.setX(frame
.rect
.x() + (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2549 case NorthEastGravity
:
2550 case SouthEastGravity
:
2552 r
.setX(frame
.rect
.x() + frame
.margin
.left
+ frame
.margin
.right
- 2);
2557 r
.setX(frame
.rect
.x() + frame
.margin
.left
);
2561 // restore vertical window gravity
2562 switch (client
.win_gravity
) {
2564 case NorthWestGravity
:
2565 case NorthEastGravity
:
2567 r
.setY(frame
.rect
.y());
2573 r
.setY(frame
.rect
.y() + (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2576 case SouthWestGravity
:
2577 case SouthEastGravity
:
2579 r
.setY(frame
.rect
.y() + frame
.margin
.top
+ frame
.margin
.bottom
- 2);
2584 r
.setY(frame
.rect
.y() + frame
.margin
.top
);
2590 void BlackboxWindow::redrawLabel(void) const {
2591 if (flags
.focused
) {
2593 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2594 frame
.label
, frame
.flabel
);
2596 XSetWindowBackground(blackbox
->getXDisplay(),
2597 frame
.label
, frame
.flabel_pixel
);
2600 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2601 frame
.label
, frame
.ulabel
);
2603 XSetWindowBackground(blackbox
->getXDisplay(),
2604 frame
.label
, frame
.ulabel_pixel
);
2606 XClearWindow(blackbox
->getXDisplay(), frame
.label
);
2608 WindowStyle
*style
= screen
->getWindowStyle();
2610 int pos
= frame
.bevel_w
* 2;
2611 style
->doJustify(client
.title
.c_str(), pos
, frame
.label_w
, frame
.bevel_w
* 4);
2612 style
->font
->drawString(frame
.label
, pos
, 1,
2613 (flags
.focused
? style
->l_text_focus
:
2614 style
->l_text_unfocus
),
2619 void BlackboxWindow::redrawAllButtons(void) const {
2620 if (frame
.iconify_button
) redrawIconifyButton(False
);
2621 if (frame
.maximize_button
) redrawMaximizeButton(flags
.maximized
);
2622 if (frame
.close_button
) redrawCloseButton(False
);
2623 if (frame
.stick_button
) redrawStickyButton(flags
.stuck
);
2627 void BlackboxWindow::redrawButton(bool pressed
, Window win
,
2628 Pixmap fppix
, unsigned long fppixel
,
2629 Pixmap uppix
, unsigned long uppixel
,
2630 Pixmap fpix
, unsigned long fpixel
,
2631 Pixmap upix
, unsigned long upixel
) const {
2636 if (flags
.focused
) {
2644 if (flags
.focused
) {
2654 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), win
, p
);
2656 XSetWindowBackground(blackbox
->getXDisplay(), win
, pix
);
2660 void BlackboxWindow::redrawIconifyButton(bool pressed
) const {
2661 redrawButton(pressed
, frame
.iconify_button
,
2662 frame
.pfbutton
, frame
.pfbutton_pixel
,
2663 frame
.pubutton
, frame
.pubutton_pixel
,
2664 frame
.fbutton
, frame
.fbutton_pixel
,
2665 frame
.ubutton
, frame
.ubutton_pixel
);
2667 XClearWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
2668 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2669 screen
->getWindowStyle()->b_pic_unfocus
);
2671 #ifdef BITMAPBUTTONS
2672 PixmapMask pm
= screen
->getWindowStyle()->icon_button
;
2674 if (screen
->getWindowStyle()->icon_button
.mask
!= None
) {
2675 XSetClipMask(blackbox
->getXDisplay(), pen
.gc(), pm
.mask
);
2676 XSetClipOrigin(blackbox
->getXDisplay(), pen
.gc(),
2677 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2);
2679 XFillRectangle(blackbox
->getXDisplay(), frame
.iconify_button
, pen
.gc(),
2680 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2,
2681 (frame
.button_w
+ pm
.w
)/2, (frame
.button_w
+ pm
.h
)/2);
2683 XSetClipMask(blackbox
->getXDisplay(), pen
.gc(), None
);
2684 XSetClipOrigin(blackbox
->getXDisplay(), pen
.gc(), 0, 0);
2686 #endif // BITMAPBUTTONS
2687 XDrawRectangle(blackbox
->getXDisplay(), frame
.iconify_button
, pen
.gc(),
2688 2, (frame
.button_w
- 5), (frame
.button_w
- 5), 2);
2689 #ifdef BITMAPBUTTONS
2691 #endif // BITMAPBUTTONS
2695 void BlackboxWindow::redrawMaximizeButton(bool pressed
) const {
2696 redrawButton(pressed
, frame
.maximize_button
,
2697 frame
.pfbutton
, frame
.pfbutton_pixel
,
2698 frame
.pubutton
, frame
.pubutton_pixel
,
2699 frame
.fbutton
, frame
.fbutton_pixel
,
2700 frame
.ubutton
, frame
.ubutton_pixel
);
2702 XClearWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
2704 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2705 screen
->getWindowStyle()->b_pic_unfocus
);
2707 #ifdef BITMAPBUTTONS
2708 PixmapMask pm
= screen
->getWindowStyle()->max_button
;
2710 if (pm
.mask
!= None
) {
2711 XSetClipMask(blackbox
->getXDisplay(), pen
.gc(), pm
.mask
);
2712 XSetClipOrigin(blackbox
->getXDisplay(), pen
.gc(),
2713 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2);
2715 XFillRectangle(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2716 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2,
2717 (frame
.button_w
+ pm
.w
)/2, (frame
.button_w
+ pm
.h
)/2);
2719 XSetClipOrigin(blackbox
->getXDisplay(), pen
.gc(), 0, 0 );
2720 XSetClipMask( blackbox
->getXDisplay(), pen
.gc(), None
);
2722 #endif // BITMAPBUTTONS
2723 XDrawRectangle(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2724 2, 2, (frame
.button_w
- 5), (frame
.button_w
- 5));
2725 XDrawLine(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2726 2, 3, (frame
.button_w
- 3), 3);
2727 #ifdef BITMAPBUTTONS
2729 #endif // BITMAPBUTTONS
2733 void BlackboxWindow::redrawCloseButton(bool pressed
) const {
2734 redrawButton(pressed
, frame
.close_button
,
2735 frame
.pfbutton
, frame
.pfbutton_pixel
,
2736 frame
.pubutton
, frame
.pubutton_pixel
,
2737 frame
.fbutton
, frame
.fbutton_pixel
,
2738 frame
.ubutton
, frame
.ubutton_pixel
);
2740 XClearWindow(blackbox
->getXDisplay(), frame
.close_button
);
2742 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2743 screen
->getWindowStyle()->b_pic_unfocus
);
2745 #ifdef BITMAPBUTTONS
2746 PixmapMask pm
= screen
->getWindowStyle()->close_button
;
2748 if (pm
.mask
!= None
) {
2749 XSetClipMask(blackbox
->getXDisplay(), pen
.gc(), pm
.mask
);
2750 XSetClipOrigin(blackbox
->getXDisplay(), pen
.gc(),
2751 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2);
2753 XFillRectangle(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2754 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2,
2755 (frame
.button_w
+ pm
.w
)/2, (frame
.button_w
+ pm
.h
)/2);
2758 XSetClipOrigin(blackbox
->getXDisplay(), pen
.gc(), 0, 0 );
2759 XSetClipMask( blackbox
->getXDisplay(), pen
.gc(), None
);
2761 #endif // BITMAPBUTTONS
2762 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2763 2, 2, (frame
.button_w
- 3), (frame
.button_w
- 3));
2764 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2765 2, (frame
.button_w
- 3), (frame
.button_w
- 3), 2);
2766 #ifdef BITMAPBUTTONS
2768 #endif // BITMAPBUTTONS
2771 void BlackboxWindow::redrawStickyButton(bool pressed
) const {
2772 redrawButton(pressed
, frame
.stick_button
,
2773 frame
.pfbutton
, frame
.pfbutton_pixel
,
2774 frame
.pubutton
, frame
.pubutton_pixel
,
2775 frame
.fbutton
, frame
.fbutton_pixel
,
2776 frame
.ubutton
, frame
.ubutton_pixel
);
2778 XClearWindow(blackbox
->getXDisplay(), frame
.stick_button
);
2780 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2781 screen
->getWindowStyle()->b_pic_unfocus
);
2783 #ifdef BITMAPBUTTONS
2784 PixmapMask pm
= screen
->getWindowStyle()->stick_button
;
2786 if (pm
.mask
!= None
) {
2787 XSetClipMask(blackbox
->getXDisplay(), pen
.gc(), pm
.mask
);
2788 XSetClipOrigin(blackbox
->getXDisplay(), pen
.gc(),
2789 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2);
2791 XFillRectangle(blackbox
->getXDisplay(), frame
.stick_button
, pen
.gc(),
2792 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2,
2793 (frame
.button_w
+ pm
.w
)/2, (frame
.button_w
+ pm
.h
)/2);
2796 XSetClipOrigin(blackbox
->getXDisplay(), pen
.gc(), 0, 0 );
2797 XSetClipMask( blackbox
->getXDisplay(), pen
.gc(), None
);
2799 #endif // BITMAPBUTTONS
2800 XFillRectangle(blackbox
->getXDisplay(), frame
.stick_button
, pen
.gc(),
2801 frame
.button_w
/2 - 1, frame
.button_w
/2 -1, 2, 2 );
2802 #ifdef BITMAPBUTTONS
2807 void BlackboxWindow::mapRequestEvent(const XMapRequestEvent
*re
) {
2808 if (re
->window
!= client
.window
)
2812 fprintf(stderr
, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2817 Even though the window wants to be shown, if it is not on the current
2818 workspace, then it isn't going to be shown right now.
2820 if (! flags
.stuck
&&
2821 blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID() &&
2822 blackbox_attrib
.workspace
< screen
->getWorkspaceCount())
2823 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2825 switch (current_state
) {
2830 case WithdrawnState
:
2839 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2841 if (! blackbox
->isStartup()) {
2842 XSync(blackbox
->getXDisplay(), False
); // make sure the frame is mapped
2843 if (screen
->doFocusNew() || (isTransient() && getTransientFor() &&
2844 getTransientFor()->isFocused())) {
2847 if (screen
->getPlacementPolicy() == BScreen::ClickMousePlacement
) {
2851 XQueryPointer(blackbox
->getXDisplay(), screen
->getRootWindow(),
2852 &r
, &c
, &rx
, &ry
, &x
, &y
, &m
);
2862 void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent
*ue
) {
2863 if (ue
->window
!= client
.window
)
2867 fprintf(stderr
, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2871 screen
->unmanageWindow(this, False
);
2875 void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent
*de
) {
2876 if (de
->window
!= client
.window
)
2880 fprintf(stderr
, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2884 screen
->unmanageWindow(this, False
);
2888 void BlackboxWindow::reparentNotifyEvent(const XReparentEvent
*re
) {
2889 if (re
->window
!= client
.window
|| re
->parent
== frame
.plate
)
2893 fprintf(stderr
, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2894 "0x%lx.\n", client
.window
, re
->parent
);
2899 XPutBackEvent(blackbox
->getXDisplay(), &ev
);
2900 screen
->unmanageWindow(this, True
);
2904 void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent
*pe
) {
2905 if (pe
->state
== PropertyDelete
|| ! validateClient())
2909 fprintf(stderr
, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n",
2915 case XA_WM_CLIENT_MACHINE
:
2919 case XA_WM_TRANSIENT_FOR
: {
2920 bool s
= flags
.stuck
;
2922 // determine if this is a transient window
2925 if (flags
.stuck
!= s
) stick();
2927 // adjust the window decorations based on transience
2928 if (isTransient()) {
2929 functions
&= ~Func_Maximize
;
2930 setAllowedActions();
2942 case XA_WM_ICON_NAME
:
2944 if (flags
.iconic
) screen
->propagateWindowName(this);
2947 case XAtom::net_wm_name
:
2951 if (decorations
& Decor_Titlebar
)
2954 screen
->propagateWindowName(this);
2957 case XA_WM_NORMAL_HINTS
: {
2960 if ((client
.normal_hint_flags
& PMinSize
) &&
2961 (client
.normal_hint_flags
& PMaxSize
)) {
2962 // the window now can/can't resize itself, so the buttons need to be
2965 if (client
.max_width
<= client
.min_width
&&
2966 client
.max_height
<= client
.min_height
) {
2967 functions
&= ~(Func_Resize
| Func_Maximize
);
2969 if (! isTransient())
2970 functions
|= Func_Maximize
;
2971 functions
|= Func_Resize
;
2974 setAllowedActions();
2978 Rect old_rect
= frame
.rect
;
2982 if (old_rect
!= frame
.rect
)
2989 if (pe
->atom
== xatom
->getAtom(XAtom::wm_protocols
)) {
2992 if ((decorations
& Decor_Close
) && (! frame
.close_button
)) {
2993 createCloseButton();
2994 if (decorations
& Decor_Titlebar
) {
2995 positionButtons(True
);
2996 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
2998 if (windowmenu
) windowmenu
->reconfigure();
3000 } else if (pe
->atom
== xatom
->getAtom(XAtom::net_wm_strut
)) {
3009 void BlackboxWindow::exposeEvent(const XExposeEvent
*ee
) {
3011 fprintf(stderr
, "BlackboxWindow::exposeEvent() for 0x%lx\n", client
.window
);
3014 if (frame
.label
== ee
->window
&& (decorations
& Decor_Titlebar
))
3016 else if (frame
.close_button
== ee
->window
)
3017 redrawCloseButton(False
);
3018 else if (frame
.maximize_button
== ee
->window
)
3019 redrawMaximizeButton(flags
.maximized
);
3020 else if (frame
.iconify_button
== ee
->window
)
3021 redrawIconifyButton(False
);
3022 else if (frame
.stick_button
== ee
->window
)
3023 redrawStickyButton(flags
.stuck
);
3027 void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent
*cr
) {
3028 if (cr
->window
!= client
.window
|| flags
.iconic
)
3031 if (cr
->value_mask
& CWBorderWidth
)
3032 client
.old_bw
= cr
->border_width
;
3034 if (cr
->value_mask
& (CWX
| CWY
| CWWidth
| CWHeight
)) {
3035 frame
.changing
= frame
.rect
;
3037 if (cr
->value_mask
& (CWX
| CWY
)) {
3038 if (cr
->value_mask
& CWX
)
3039 client
.rect
.setX(cr
->x
);
3040 if (cr
->value_mask
& CWY
)
3041 client
.rect
.setY(cr
->y
);
3043 applyGravity(frame
.changing
);
3046 if (cr
->value_mask
& (CWWidth
| CWHeight
)) {
3047 if (cr
->value_mask
& CWWidth
)
3048 frame
.changing
.setWidth(cr
->width
+
3049 frame
.margin
.left
+ frame
.margin
.right
);
3051 if (cr
->value_mask
& CWHeight
)
3052 frame
.changing
.setHeight(cr
->height
+
3053 frame
.margin
.top
+ frame
.margin
.bottom
);
3056 if a position change has been specified, then that position will be
3057 used instead of determining a position based on the window's gravity.
3059 if (! (cr
->value_mask
& (CWX
| CWY
))) {
3061 switch (client
.win_gravity
) {
3062 case NorthEastGravity
:
3066 case SouthWestGravity
:
3068 corner
= BottomLeft
;
3070 case SouthEastGravity
:
3071 corner
= BottomRight
;
3073 default: // NorthWest, Static, etc
3080 configure(frame
.changing
.x(), frame
.changing
.y(),
3081 frame
.changing
.width(), frame
.changing
.height());
3084 if (cr
->value_mask
& CWStackMode
&& !isDesktop()) {
3085 switch (cr
->detail
) {
3088 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
3094 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3101 void BlackboxWindow::buttonPressEvent(const XButtonEvent
*be
) {
3103 fprintf(stderr
, "BlackboxWindow::buttonPressEvent() for 0x%lx\n",
3107 if (frame
.maximize_button
== be
->window
&& be
->button
<= 3) {
3108 redrawMaximizeButton(True
);
3109 } else if (be
->button
== 1 || (be
->button
== 3 && be
->state
== mod_mask
)) {
3110 if (! flags
.focused
)
3113 if (frame
.iconify_button
== be
->window
) {
3114 redrawIconifyButton(True
);
3115 } else if (frame
.close_button
== be
->window
) {
3116 redrawCloseButton(True
);
3117 } else if (frame
.stick_button
== be
->window
) {
3118 redrawStickyButton(True
);
3119 } else if (frame
.plate
== be
->window
) {
3120 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
3122 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3124 XAllowEvents(blackbox
->getXDisplay(), ReplayPointer
, be
->time
);
3126 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
3127 if (((be
->time
- lastButtonPressTime
) <=
3128 blackbox
->getDoubleClickInterval()) ||
3129 (be
->state
== ControlMask
)) {
3130 lastButtonPressTime
= 0;
3133 lastButtonPressTime
= be
->time
;
3137 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
3139 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3141 } else if (be
->button
== 2 && (be
->window
!= frame
.iconify_button
) &&
3142 (be
->window
!= frame
.close_button
) &&
3143 (be
->window
!= frame
.stick_button
)) {
3144 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
3145 } else if (windowmenu
&& be
->button
== 3 &&
3146 (frame
.title
== be
->window
|| frame
.label
== be
->window
||
3147 frame
.handle
== be
->window
|| frame
.window
== be
->window
)) {
3148 if (windowmenu
->isVisible()) {
3151 int mx
= be
->x_root
- windowmenu
->getWidth() / 2,
3152 my
= be
->y_root
- windowmenu
->getHeight() / 2;
3154 // snap the window menu into a corner/side if necessary
3155 int left_edge
, right_edge
, top_edge
, bottom_edge
;
3158 the " + (frame.border_w * 2) - 1" bits are to get the proper width
3159 and height of the menu, as the sizes returned by it do not include
3162 left_edge
= frame
.rect
.x();
3163 right_edge
= frame
.rect
.right() -
3164 (windowmenu
->getWidth() + (frame
.border_w
* 2) - 1);
3165 top_edge
= client
.rect
.top() - (frame
.border_w
+ frame
.mwm_border_w
);
3166 bottom_edge
= client
.rect
.bottom() -
3167 (windowmenu
->getHeight() + (frame
.border_w
* 2) - 1) +
3168 (frame
.border_w
+ frame
.mwm_border_w
);
3172 else if (mx
> right_edge
)
3176 else if (my
> bottom_edge
)
3179 if (my
+ windowmenu
->getHeight() > screen
->getHeight())
3180 my
= screen
->getHeight() - windowmenu
->getHeight() -
3181 (screen
->getBorderWidth() * 2);
3183 windowmenu
->move(mx
, my
);
3185 XRaiseWindow(blackbox
->getXDisplay(), windowmenu
->getWindowID());
3186 XRaiseWindow(blackbox
->getXDisplay(),
3187 windowmenu
->getSendToMenu()->getWindowID());
3190 } else if (be
->button
== 4) {
3191 if ((be
->window
== frame
.label
||
3192 be
->window
== frame
.title
||
3193 be
->window
== frame
.maximize_button
||
3194 be
->window
== frame
.iconify_button
||
3195 be
->window
== frame
.close_button
||
3196 be
->window
== frame
.stick_button
) &&
3200 } else if (be
->button
== 5) {
3201 if ((be
->window
== frame
.label
||
3202 be
->window
== frame
.title
||
3203 be
->window
== frame
.maximize_button
||
3204 be
->window
== frame
.iconify_button
||
3205 be
->window
== frame
.close_button
||
3206 be
->window
== frame
.stick_button
) &&
3213 void BlackboxWindow::buttonReleaseEvent(const XButtonEvent
*re
) {
3215 fprintf(stderr
, "BlackboxWindow::buttonReleaseEvent() for 0x%lx\n",
3219 if (re
->window
== frame
.maximize_button
&&
3220 re
->button
>= 1 && re
->button
<= 3) {
3221 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3222 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
3223 maximize(re
->button
);
3225 redrawMaximizeButton(flags
.maximized
);
3227 } else if (re
->window
== frame
.iconify_button
&& re
->button
== 1) {
3228 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3229 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
3232 redrawIconifyButton(False
);
3234 } else if (re
->window
== frame
.stick_button
&& re
->button
== 1) {
3235 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3236 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
3239 redrawStickyButton(False
);
3241 } else if (re
->window
== frame
.close_button
& re
->button
== 1) {
3242 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3243 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
)))
3245 redrawCloseButton(False
);
3246 } else if (flags
.moving
) {
3248 } else if (flags
.resizing
) {
3250 } else if (re
->window
== frame
.window
) {
3251 if (re
->button
== 2 && re
->state
== mod_mask
)
3252 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3258 void BlackboxWindow::beginMove(int x_root
, int y_root
) {
3259 if (! (functions
& Func_Move
)) return;
3261 assert(! (flags
.resizing
|| flags
.moving
));
3264 Only one window can be moved/resized at a time. If another window is already
3265 being moved or resized, then stop it before whating to work with this one.
3267 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3268 if (changing
&& changing
!= this) {
3269 if (changing
->flags
.moving
)
3270 changing
->endMove();
3271 else // if (changing->flags.resizing)
3272 changing
->endResize();
3275 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3276 PointerMotionMask
| ButtonReleaseMask
,
3277 GrabModeAsync
, GrabModeAsync
,
3278 None
, blackbox
->getMoveCursor(), CurrentTime
);
3280 if (windowmenu
&& windowmenu
->isVisible())
3283 flags
.moving
= True
;
3284 blackbox
->setChangingWindow(this);
3286 if (! screen
->doOpaqueMove()) {
3287 XGrabServer(blackbox
->getXDisplay());
3289 frame
.changing
= frame
.rect
;
3290 screen
->showPosition(frame
.changing
.x(), frame
.changing
.y());
3292 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3296 frame
.changing
.width() - 1,
3297 frame
.changing
.height() - 1);
3300 frame
.grab_x
= x_root
- frame
.rect
.x() - frame
.border_w
;
3301 frame
.grab_y
= y_root
- frame
.rect
.y() - frame
.border_w
;
3305 void BlackboxWindow::doMove(int x_root
, int y_root
) {
3306 assert(flags
.moving
);
3307 assert(blackbox
->getChangingWindow() == this);
3309 int dx
= x_root
- frame
.grab_x
, dy
= y_root
- frame
.grab_y
;
3310 dx
-= frame
.border_w
;
3311 dy
-= frame
.border_w
;
3313 doWindowSnapping(dx
, dy
);
3315 if (screen
->doOpaqueMove()) {
3316 if (screen
->doWorkspaceWarping())
3317 doWorkspaceWarping(x_root
, y_root
, dx
);
3319 configure(dx
, dy
, frame
.rect
.width(), frame
.rect
.height());
3321 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3325 frame
.changing
.width() - 1,
3326 frame
.changing
.height() - 1);
3328 if (screen
->doWorkspaceWarping())
3329 doWorkspaceWarping(x_root
, y_root
, dx
);
3331 frame
.changing
.setPos(dx
, dy
);
3333 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3337 frame
.changing
.width() - 1,
3338 frame
.changing
.height() - 1);
3341 screen
->showPosition(dx
, dy
);
3345 void BlackboxWindow::doWorkspaceWarping(int x_root
, int y_root
, int &dx
) {
3346 // workspace warping
3348 unsigned int dest
= screen
->getCurrentWorkspaceID();
3352 if (dest
> 0) dest
--;
3353 else dest
= screen
->getNumberOfWorkspaces() - 1;
3355 } else if (x_root
>= screen
->getRect().right()) {
3358 if (dest
< screen
->getNumberOfWorkspaces() - 1) dest
++;
3364 bool focus
= flags
.focused
; // had focus while moving?
3366 int dest_x
= x_root
;
3368 dest_x
+= screen
->getRect().width() - 1;
3369 dx
+= screen
->getRect().width() - 1;
3371 dest_x
-= screen
->getRect().width() - 1;
3372 dx
-= screen
->getRect().width() - 1;
3376 screen
->reassociateWindow(this, dest
, False
);
3377 screen
->changeWorkspaceID(dest
);
3379 if (screen
->doOpaqueMove())
3380 XGrabServer(blackbox
->getXDisplay());
3382 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3383 XWarpPointer(blackbox
->getXDisplay(), None
,
3384 screen
->getRootWindow(), 0, 0, 0, 0,
3386 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3387 PointerMotionMask
| ButtonReleaseMask
,
3388 GrabModeAsync
, GrabModeAsync
,
3389 None
, blackbox
->getMoveCursor(), CurrentTime
);
3391 if (screen
->doOpaqueMove())
3392 XUngrabServer(blackbox
->getXDisplay());
3400 void BlackboxWindow::doWindowSnapping(int &dx
, int &dy
) {
3401 // how much resistance to edges to provide
3402 const int resistance_size
= screen
->getResistanceSize();
3404 // how far away to snap
3405 const int snap_distance
= screen
->getSnapThreshold();
3407 // how to snap windows
3408 const int snap_to_windows
= screen
->getWindowToWindowSnap();
3409 const int snap_to_edges
= screen
->getWindowToEdgeSnap();
3410 // the amount of space away from the edge to provide resistance/snap
3411 const int snap_offset
= screen
->getSnapOffset();
3413 // find the geomeetery where the moving window currently is
3414 const Rect
&moving
= screen
->doOpaqueMove() ? frame
.rect
: frame
.changing
;
3417 const int wleft
= dx
,
3418 wright
= dx
+ frame
.rect
.width() - 1,
3420 wbottom
= dy
+ frame
.rect
.height() - 1;
3422 if (snap_to_windows
) {
3425 Workspace
*w
= screen
->getWorkspace(getWorkspaceNumber());
3428 // add windows on the workspace to the rect list
3429 const BlackboxWindowList
& stack_list
= w
->getStackingList();
3430 BlackboxWindowList::const_iterator st_it
, st_end
= stack_list
.end();
3431 for (st_it
= stack_list
.begin(); st_it
!= st_end
; ++st_it
)
3432 if (*st_it
!= this) // don't snap to ourself
3433 rectlist
.push_back( (*st_it
)->frameRect() );
3435 // add the toolbar and the slit to the rect list.
3436 // (only if they are not hidden)
3437 Toolbar
*tbar
= screen
->getToolbar();
3438 Slit
*slit
= screen
->getSlit();
3439 Rect tbar_rect
, slit_rect
;
3440 unsigned int bwidth
= screen
->getBorderWidth() * 2;
3442 if (! (screen
->doHideToolbar() || tbar
->isHidden())) {
3443 tbar_rect
.setRect(tbar
->getX(), tbar
->getY(), tbar
->getWidth() + bwidth
,
3444 tbar
->getHeight() + bwidth
);
3445 rectlist
.push_back(tbar_rect
);
3448 if (! slit
->isHidden()) {
3449 slit_rect
.setRect(slit
->getX(), slit
->getY(), slit
->getWidth() + bwidth
,
3450 slit
->getHeight() + bwidth
);
3451 rectlist
.push_back(slit_rect
);
3454 RectList::const_iterator it
, end
= rectlist
.end();
3455 for (it
= rectlist
.begin(); it
!= end
; ++it
) {
3456 bool snapped
= False
;
3457 const Rect
&winrect
= *it
;
3459 offsetrect
.setCoords(winrect
.left() - snap_offset
,
3460 winrect
.top() - snap_offset
,
3461 winrect
.right() + snap_offset
,
3462 winrect
.bottom() + snap_offset
);
3464 if (snap_to_windows
== BScreen::WindowResistance
)
3465 // if the window is already over top of this snap target, then
3466 // resistance is futile, so just ignore it
3467 if (winrect
.intersects(moving
))
3470 int dleft
, dright
, dtop
, dbottom
;
3472 // if the windows are in the same plane vertically
3473 if (wtop
>= (signed)(winrect
.y() - frame
.rect
.height() + 1) &&
3474 wtop
< (signed)(winrect
.y() + winrect
.height() - 1)) {
3476 if (snap_to_windows
== BScreen::WindowResistance
) {
3477 dleft
= wright
- offsetrect
.left();
3478 dright
= offsetrect
.right() - wleft
;
3480 // snap left of other window?
3481 if (dleft
>= 0 && dleft
< resistance_size
&&
3482 dleft
< (wright
- wleft
)) {
3483 dx
= offsetrect
.left() - frame
.rect
.width();
3486 // snap right of other window?
3487 else if (dright
>= 0 && dright
< resistance_size
&&
3488 dright
< (wright
- wleft
)) {
3489 dx
= offsetrect
.right() + 1;
3492 } else { // BScreen::WindowSnap
3493 dleft
= abs(wright
- offsetrect
.left());
3494 dright
= abs(wleft
- offsetrect
.right());
3496 // snap left of other window?
3497 if (dleft
< snap_distance
&& dleft
<= dright
) {
3498 dx
= offsetrect
.left() - frame
.rect
.width();
3501 // snap right of other window?
3502 else if (dright
< snap_distance
) {
3503 dx
= offsetrect
.right() + 1;
3509 if (screen
->getWindowCornerSnap()) {
3510 // try corner-snap to its other sides
3511 if (snap_to_windows
== BScreen::WindowResistance
) {
3512 dtop
= winrect
.top() - wtop
;
3513 dbottom
= wbottom
- winrect
.bottom();
3514 if (dtop
> 0 && dtop
< resistance_size
) {
3515 // if we're already past the top edge, then don't provide
3517 if (moving
.top() >= winrect
.top())
3519 } else if (dbottom
> 0 && dbottom
< resistance_size
) {
3520 // if we're already past the bottom edge, then don't provide
3522 if (moving
.bottom() <= winrect
.bottom())
3523 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
3525 } else { // BScreen::WindowSnap
3526 dtop
= abs(wtop
- winrect
.top());
3527 dbottom
= abs(wbottom
- winrect
.bottom());
3528 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3530 else if (dbottom
< snap_distance
)
3531 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
3539 // if the windows are on the same plane horizontally
3540 if (wleft
>= (signed)(winrect
.x() - frame
.rect
.width() + 1) &&
3541 wleft
< (signed)(winrect
.x() + winrect
.width() - 1)) {
3543 if (snap_to_windows
== BScreen::WindowResistance
) {
3544 dtop
= wbottom
- offsetrect
.top();
3545 dbottom
= offsetrect
.bottom() - wtop
;
3547 // snap top of other window?
3548 if (dtop
>= 0 && dtop
< resistance_size
&& dtop
< (wbottom
- wtop
)) {
3549 dy
= offsetrect
.top() - frame
.rect
.height();
3552 // snap bottom of other window?
3553 else if (dbottom
>= 0 && dbottom
< resistance_size
&&
3554 dbottom
< (wbottom
- wtop
)) {
3555 dy
= offsetrect
.bottom() + 1;
3558 } else { // BScreen::WindowSnap
3559 dtop
= abs(wbottom
- offsetrect
.top());
3560 dbottom
= abs(wtop
- offsetrect
.bottom());
3562 // snap top of other window?
3563 if (dtop
< snap_distance
&& dtop
<= dbottom
) {
3564 dy
= offsetrect
.top() - frame
.rect
.height();
3567 // snap bottom of other window?
3568 else if (dbottom
< snap_distance
) {
3569 dy
= offsetrect
.bottom() + 1;
3576 if (screen
->getWindowCornerSnap()) {
3577 // try corner-snap to its other sides
3578 if (snap_to_windows
== BScreen::WindowResistance
) {
3579 dleft
= winrect
.left() - wleft
;
3580 dright
= wright
- winrect
.right();
3581 if (dleft
> 0 && dleft
< resistance_size
) {
3582 // if we're already past the left edge, then don't provide
3584 if (moving
.left() >= winrect
.left())
3585 dx
= winrect
.left();
3586 } else if (dright
> 0 && dright
< resistance_size
) {
3587 // if we're already past the right edge, then don't provide
3589 if (moving
.right() <= winrect
.right())
3590 dx
= winrect
.right() - frame
.rect
.width() + 1;
3592 } else { // BScreen::WindowSnap
3593 dleft
= abs(wleft
- winrect
.left());
3594 dright
= abs(wright
- winrect
.right());
3595 if (dleft
< snap_distance
&& dleft
<= dright
)
3596 dx
= winrect
.left();
3597 else if (dright
< snap_distance
)
3598 dx
= winrect
.right() - frame
.rect
.width() + 1;
3608 if (snap_to_edges
) {
3611 // snap to the screen edges (and screen boundaries for xinerama)
3613 if (screen
->isXineramaActive() && blackbox
->doXineramaSnapping()) {
3614 rectlist
.insert(rectlist
.begin(),
3615 screen
->getXineramaAreas().begin(),
3616 screen
->getXineramaAreas().end());
3619 rectlist
.push_back(screen
->getRect());
3621 RectList::const_iterator it
, end
= rectlist
.end();
3622 for (it
= rectlist
.begin(); it
!= end
; ++it
) {
3623 const Rect
&srect
= *it
;
3625 offsetrect
.setCoords(srect
.left() + snap_offset
,
3626 srect
.top() + snap_offset
,
3627 srect
.right() - snap_offset
,
3628 srect
.bottom() - snap_offset
);
3630 if (snap_to_edges
== BScreen::WindowResistance
) {
3631 // if we're not in the rectangle then don't snap to it.
3632 if (! srect
.contains(moving
))
3634 } else { // BScreen::WindowSnap
3635 // if we're not in the rectangle then don't snap to it.
3636 if (! srect
.intersects(Rect(wleft
, wtop
, frame
.rect
.width(),
3637 frame
.rect
.height())))
3641 if (snap_to_edges
== BScreen::WindowResistance
) {
3642 int dleft
= offsetrect
.left() - wleft
,
3643 dright
= wright
- offsetrect
.right(),
3644 dtop
= offsetrect
.top() - wtop
,
3645 dbottom
= wbottom
- offsetrect
.bottom();
3648 if (dleft
> 0 && dleft
< resistance_size
)
3649 dx
= offsetrect
.left();
3651 else if (dright
> 0 && dright
< resistance_size
)
3652 dx
= offsetrect
.right() - frame
.rect
.width() + 1;
3655 if (dtop
> 0 && dtop
< resistance_size
)
3656 dy
= offsetrect
.top();
3658 else if (dbottom
> 0 && dbottom
< resistance_size
)
3659 dy
= offsetrect
.bottom() - frame
.rect
.height() + 1;
3660 } else { // BScreen::WindowSnap
3661 int dleft
= abs(wleft
- offsetrect
.left()),
3662 dright
= abs(wright
- offsetrect
.right()),
3663 dtop
= abs(wtop
- offsetrect
.top()),
3664 dbottom
= abs(wbottom
- offsetrect
.bottom());
3667 if (dleft
< snap_distance
&& dleft
<= dright
)
3668 dx
= offsetrect
.left();
3670 else if (dright
< snap_distance
)
3671 dx
= offsetrect
.right() - frame
.rect
.width() + 1;
3674 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3675 dy
= offsetrect
.top();
3677 else if (dbottom
< snap_distance
)
3678 dy
= offsetrect
.bottom() - frame
.rect
.height() + 1;
3685 void BlackboxWindow::endMove(void) {
3686 assert(flags
.moving
);
3687 assert(blackbox
->getChangingWindow() == this);
3689 flags
.moving
= False
;
3690 blackbox
->setChangingWindow(0);
3692 if (! screen
->doOpaqueMove()) {
3693 /* when drawing the rubber band, we need to make sure we only draw inside
3694 * the frame... frame.changing_* contain the new coords for the window,
3695 * so we need to subtract 1 from changing_w/changing_h every where we
3696 * draw the rubber band (for both moving and resizing)
3698 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3699 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3700 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3701 XUngrabServer(blackbox
->getXDisplay());
3703 configure(frame
.changing
.x(), frame
.changing
.y(),
3704 frame
.changing
.width(), frame
.changing
.height());
3706 configure(frame
.rect
.x(), frame
.rect
.y(),
3707 frame
.rect
.width(), frame
.rect
.height());
3709 screen
->hideGeometry();
3711 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3713 // if there are any left over motions from the move, drop them now
3714 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3716 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3721 void BlackboxWindow::beginResize(int x_root
, int y_root
, Corner dir
) {
3722 if (! (functions
& Func_Resize
)) return;
3724 assert(! (flags
.resizing
|| flags
.moving
));
3727 Only one window can be moved/resized at a time. If another window is
3728 already being moved or resized, then stop it before whating to work with
3731 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3732 if (changing
&& changing
!= this) {
3733 if (changing
->flags
.moving
)
3734 changing
->endMove();
3735 else // if (changing->flags.resizing)
3736 changing
->endResize();
3744 switch (resize_dir
) {
3747 cursor
= blackbox
->getLowerLeftAngleCursor();
3752 cursor
= blackbox
->getLowerRightAngleCursor();
3756 anchor
= BottomRight
;
3757 cursor
= blackbox
->getUpperLeftAngleCursor();
3761 anchor
= BottomLeft
;
3762 cursor
= blackbox
->getUpperRightAngleCursor();
3766 assert(false); // unhandled Corner
3767 return; // unreachable, for the compiler
3770 XGrabServer(blackbox
->getXDisplay());
3771 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3772 PointerMotionMask
| ButtonReleaseMask
,
3773 GrabModeAsync
, GrabModeAsync
, None
, cursor
, CurrentTime
);
3775 flags
.resizing
= True
;
3776 blackbox
->setChangingWindow(this);
3778 unsigned int gw
, gh
;
3779 frame
.changing
= frame
.rect
;
3781 constrain(anchor
, &gw
, &gh
);
3783 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3784 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3785 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3787 screen
->showGeometry(gw
, gh
);
3789 frame
.grab_x
= x_root
;
3790 frame
.grab_y
= y_root
;
3794 void BlackboxWindow::doResize(int x_root
, int y_root
) {
3795 assert(flags
.resizing
);
3796 assert(blackbox
->getChangingWindow() == this);
3798 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3799 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3800 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3802 unsigned int gw
, gh
;
3804 int dx
, dy
; // the amount of change in the size of the window
3806 switch (resize_dir
) {
3809 dx
= - (x_root
- frame
.grab_x
);
3810 dy
= + (y_root
- frame
.grab_y
);
3814 dx
= + (x_root
- frame
.grab_x
);
3815 dy
= + (y_root
- frame
.grab_y
);
3818 anchor
= BottomRight
;
3819 dx
= - (x_root
- frame
.grab_x
);
3820 dy
= - (y_root
- frame
.grab_y
);
3823 anchor
= BottomLeft
;
3824 dx
= + (x_root
- frame
.grab_x
);
3825 dy
= - (y_root
- frame
.grab_y
);
3829 assert(false); // unhandled Corner
3830 return; // unreachable, for the compiler
3833 // make sure the user cant resize the window smaller than 0, which makes it
3834 // wrap around and become huge
3835 if (dx
< -(signed)client
.rect
.width()) dx
= -(signed)client
.rect
.width();
3836 if (dy
< -(signed)client
.rect
.height()) dy
= -(signed)client
.rect
.height();
3838 frame
.changing
.setSize(frame
.rect
.width() + dx
, frame
.rect
.height() + dy
);
3840 constrain(anchor
, &gw
, &gh
);
3842 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3843 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3844 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3846 screen
->showGeometry(gw
, gh
);
3850 void BlackboxWindow::endResize(void) {
3851 assert(flags
.resizing
);
3852 assert(blackbox
->getChangingWindow() == this);
3854 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3855 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3856 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3857 XUngrabServer(blackbox
->getXDisplay());
3859 // unset maximized state after resized when fully maximized
3860 if (flags
.maximized
== 1)
3863 flags
.resizing
= False
;
3864 blackbox
->setChangingWindow(0);
3866 configure(frame
.changing
.x(), frame
.changing
.y(),
3867 frame
.changing
.width(), frame
.changing
.height());
3868 screen
->hideGeometry();
3870 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3872 // if there are any left over motions from the resize, drop them now
3873 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3875 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3880 void BlackboxWindow::motionNotifyEvent(const XMotionEvent
*me
) {
3882 fprintf(stderr
, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n",
3887 doMove(me
->x_root
, me
->y_root
);
3888 } else if (flags
.resizing
) {
3889 doResize(me
->x_root
, me
->y_root
);
3891 if ((functions
& Func_Move
) &&
3892 (me
->state
& Button1Mask
) &&
3893 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3894 frame
.handle
== me
->window
|| frame
.window
== me
->window
)) {
3895 beginMove(me
->x_root
, me
->y_root
);
3896 } else if ((functions
& Func_Resize
) &&
3897 ((me
->state
& Button1Mask
) &&
3898 (me
->window
== frame
.right_grip
||
3899 me
->window
== frame
.left_grip
)) ||
3900 ((me
->state
& Button3Mask
) && (me
->state
& mod_mask
) &&
3901 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3902 frame
.handle
== me
->window
|| frame
.window
== me
->window
||
3903 frame
.right_grip
== me
->window
||
3904 frame
.left_grip
== me
->window
))) {
3905 unsigned int zones
= screen
->getResizeZones();
3908 if (me
->window
== frame
.left_grip
) {
3909 corner
= BottomLeft
;
3910 } else if (me
->window
== frame
.right_grip
|| zones
== 1) {
3911 corner
= BottomRight
;
3914 bool left
= (me
->x_root
- frame
.rect
.x() <=
3915 static_cast<signed>(frame
.rect
.width() / 2));
3918 else // (zones == 4)
3919 top
= (me
->y_root
- frame
.rect
.y() <=
3920 static_cast<signed>(frame
.rect
.height() / 2));
3921 corner
= (top
? (left
? TopLeft
: TopRight
) :
3922 (left
? BottomLeft
: BottomRight
));
3925 beginResize(me
->x_root
, me
->y_root
, corner
);
3931 void BlackboxWindow::enterNotifyEvent(const XCrossingEvent
* ce
) {
3932 if (! (screen
->isSloppyFocus() && isVisible() && isNormal()))
3936 bool leave
= False
, inferior
= False
;
3938 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), ce
->window
,
3940 if (e
.type
== LeaveNotify
&& e
.xcrossing
.mode
== NotifyNormal
) {
3942 inferior
= (e
.xcrossing
.detail
== NotifyInferior
);
3946 if (! leave
|| inferior
) {
3947 if (! isFocused()) {
3948 bool success
= setInputFocus();
3949 if (success
) // if focus succeeded install the colormap
3950 installColormap(True
); // XXX: shouldnt we honour no install?
3953 We only auto-raise when the window wasn't focused because otherwise
3954 we run into problems with gtk+ drop-down lists. The window ends up
3955 raising over the list.
3957 if (screen
->doAutoRaise())
3964 void BlackboxWindow::leaveNotifyEvent(const XCrossingEvent
*) {
3965 if (! (screen
->isSloppyFocus() && screen
->doAutoRaise() && isNormal()))
3968 installColormap(False
);
3970 if (timer
->isTiming())
3976 void BlackboxWindow::shapeEvent(XShapeEvent
*e
) {
3977 if (blackbox
->hasShapeExtensions()) {
3978 if (! e
->shaped
&& flags
.shaped
) {
3980 flags
.shaped
= False
;
3981 } else if (e
->shaped
) {
3983 flags
.shaped
= True
;
3990 bool BlackboxWindow::validateClient(void) const {
3991 XSync(blackbox
->getXDisplay(), False
);
3994 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3995 DestroyNotify
, &e
) ||
3996 XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3998 XPutBackEvent(blackbox
->getXDisplay(), &e
);
4007 void BlackboxWindow::restore(bool remap
) {
4008 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeDelete
);
4009 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
4010 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, NoEventMask
);
4012 // do not leave a shaded window as an icon unless it was an icon
4013 if (flags
.shaded
&& ! flags
.iconic
)
4014 setState(NormalState
);
4016 // erase the netwm stuff that we read when a window maps, so that it
4017 // doesn't persist between mappings.
4018 // (these are the ones read in getNetWMFlags().)
4019 xatom
->eraseValue(client
.window
, XAtom::net_wm_desktop
);
4020 xatom
->eraseValue(client
.window
, XAtom::net_wm_state
);
4022 restoreGravity(client
.rect
);
4024 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
4025 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
4027 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, client
.old_bw
);
4030 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
4031 ReparentNotify
, &ev
)) {
4034 // according to the ICCCM - if the client doesn't reparent to
4035 // root, then we have to do it for them
4036 XReparentWindow(blackbox
->getXDisplay(), client
.window
,
4037 screen
->getRootWindow(),
4038 client
.rect
.x(), client
.rect
.y());
4041 if (remap
) XMapWindow(blackbox
->getXDisplay(), client
.window
);
4045 // timer for autoraise
4046 void BlackboxWindow::timeout(void) {
4047 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
4051 void BlackboxWindow::changeBlackboxHints(const BlackboxHints
*net
) {
4052 if ((net
->flags
& AttribShaded
) &&
4053 ((blackbox_attrib
.attrib
& AttribShaded
) !=
4054 (net
->attrib
& AttribShaded
)))
4057 if (flags
.visible
&& // watch out for requests when we can not be seen
4058 (net
->flags
& (AttribMaxVert
| AttribMaxHoriz
)) &&
4059 ((blackbox_attrib
.attrib
& (AttribMaxVert
| AttribMaxHoriz
)) !=
4060 (net
->attrib
& (AttribMaxVert
| AttribMaxHoriz
)))) {
4061 if (flags
.maximized
) {
4066 if ((net
->flags
& AttribMaxHoriz
) && (net
->flags
& AttribMaxVert
))
4067 button
= ((net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0);
4068 else if (net
->flags
& AttribMaxVert
)
4069 button
= ((net
->attrib
& AttribMaxVert
) ? 2 : 0);
4070 else if (net
->flags
& AttribMaxHoriz
)
4071 button
= ((net
->attrib
& AttribMaxHoriz
) ? 3 : 0);
4077 if ((net
->flags
& AttribOmnipresent
) &&
4078 ((blackbox_attrib
.attrib
& AttribOmnipresent
) !=
4079 (net
->attrib
& AttribOmnipresent
)))
4082 if ((net
->flags
& AttribWorkspace
) &&
4083 (blackbox_attrib
.workspace
!= net
->workspace
)) {
4084 screen
->reassociateWindow(this, net
->workspace
, True
);
4086 if (screen
->getCurrentWorkspaceID() != net
->workspace
) {
4090 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
4094 if (net
->flags
& AttribDecoration
) {
4095 switch (net
->decoration
) {
4112 * Set the sizes of all components of the window frame
4113 * (the window decorations).
4114 * These values are based upon the current style settings and the client
4115 * window's dimensions.
4117 void BlackboxWindow::upsize(void) {
4118 frame
.bevel_w
= screen
->getBevelWidth();
4120 if (decorations
& Decor_Border
) {
4121 frame
.border_w
= screen
->getBorderWidth();
4122 if (! isTransient())
4123 frame
.mwm_border_w
= screen
->getFrameWidth();
4125 frame
.mwm_border_w
= 0;
4127 frame
.mwm_border_w
= frame
.border_w
= 0;
4130 if (decorations
& Decor_Titlebar
) {
4131 // the height of the titlebar is based upon the height of the font being
4132 // used to display the window's title
4133 WindowStyle
*style
= screen
->getWindowStyle();
4134 frame
.title_h
= style
->font
->height() + (frame
.bevel_w
* 2) + 2;
4136 frame
.label_h
= frame
.title_h
- (frame
.bevel_w
* 2);
4137 frame
.button_w
= (frame
.label_h
- 2);
4139 // set the top frame margin
4140 frame
.margin
.top
= frame
.border_w
+ frame
.title_h
+
4141 frame
.border_w
+ frame
.mwm_border_w
;
4147 // set the top frame margin
4148 frame
.margin
.top
= frame
.border_w
+ frame
.mwm_border_w
;
4151 // set the left/right frame margin
4152 frame
.margin
.left
= frame
.margin
.right
= frame
.border_w
+ frame
.mwm_border_w
;
4154 if (decorations
& Decor_Handle
) {
4155 frame
.grip_w
= frame
.button_w
* 2;
4156 frame
.handle_h
= screen
->getHandleWidth();
4158 // set the bottom frame margin
4159 frame
.margin
.bottom
= frame
.border_w
+ frame
.handle_h
+
4160 frame
.border_w
+ frame
.mwm_border_w
;
4165 // set the bottom frame margin
4166 frame
.margin
.bottom
= frame
.border_w
+ frame
.mwm_border_w
;
4170 We first get the normal dimensions and use this to define the inside_w/h
4171 then we modify the height if shading is in effect.
4172 If the shade state is not considered then frame.rect gets reset to the
4173 normal window size on a reconfigure() call resulting in improper
4174 dimensions appearing in move/resize and other events.
4177 height
= client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
,
4178 width
= client
.rect
.width() + frame
.margin
.left
+ frame
.margin
.right
;
4180 frame
.inside_w
= width
- (frame
.border_w
* 2);
4181 frame
.inside_h
= height
- (frame
.border_w
* 2);
4184 height
= frame
.title_h
+ (frame
.border_w
* 2);
4185 frame
.rect
.setSize(width
, height
);
4190 * Calculate the size of the client window and constrain it to the
4191 * size specified by the size hints of the client window.
4193 * The logical width and height are placed into pw and ph, if they
4194 * are non-zero. Logical size refers to the users perception of
4195 * the window size (for example an xterm resizes in cells, not in pixels).
4196 * pw and ph are then used to display the geometry during window moves, resize,
4199 * The physical geometry is placed into frame.changing_{x,y,width,height}.
4200 * Physical geometry refers to the geometry of the window in pixels.
4202 void BlackboxWindow::constrain(Corner anchor
,
4203 unsigned int *pw
, unsigned int *ph
) {
4204 // frame.changing represents the requested frame size, we need to
4205 // strip the frame margin off and constrain the client size
4206 frame
.changing
.setCoords(frame
.changing
.left() + frame
.margin
.left
,
4207 frame
.changing
.top() + frame
.margin
.top
,
4208 frame
.changing
.right() - frame
.margin
.right
,
4209 frame
.changing
.bottom() - frame
.margin
.bottom
);
4211 unsigned int dw
= frame
.changing
.width(), dh
= frame
.changing
.height(),
4212 base_width
= (client
.base_width
) ? client
.base_width
: client
.min_width
,
4213 base_height
= (client
.base_height
) ? client
.base_height
:
4216 // constrain, but only if the min/max are being used. if they aren't, then
4217 // this resize is going to be from a ConfigureRequest because the window
4218 // isn't allowed to be resized by the user. And in that case, we don't want
4219 // to limit what the app can do
4220 if (client
.max_width
> client
.min_width
||
4221 client
.max_height
> client
.min_height
) {
4222 if (dw
< client
.min_width
) dw
= client
.min_width
;
4223 if (dh
< client
.min_height
) dh
= client
.min_height
;
4224 if (dw
> client
.max_width
) dw
= client
.max_width
;
4225 if (dh
> client
.max_height
) dh
= client
.max_height
;
4228 assert(dw
>= base_width
&& dh
>= base_height
);
4230 if (client
.width_inc
> 1) {
4232 dw
/= client
.width_inc
;
4234 if (client
.height_inc
> 1) {
4236 dh
/= client
.height_inc
;
4245 if (client
.width_inc
> 1) {
4246 dw
*= client
.width_inc
;
4249 if (client
.height_inc
> 1) {
4250 dh
*= client
.height_inc
;
4254 frame
.changing
.setSize(dw
, dh
);
4256 // add the frame margin back onto frame.changing
4257 frame
.changing
.setCoords(frame
.changing
.left() - frame
.margin
.left
,
4258 frame
.changing
.top() - frame
.margin
.top
,
4259 frame
.changing
.right() + frame
.margin
.right
,
4260 frame
.changing
.bottom() + frame
.margin
.bottom
);
4262 // move frame.changing to the specified anchor
4270 dx
= frame
.rect
.right() - frame
.changing
.right();
4274 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
4278 dx
= frame
.rect
.right() - frame
.changing
.right();
4279 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
4283 assert(false); // unhandled corner
4285 frame
.changing
.setPos(frame
.changing
.x() + dx
, frame
.changing
.y() + dy
);
4289 void WindowStyle::doJustify(const std::string
&text
, int &start_pos
,
4290 unsigned int max_length
,
4291 unsigned int modifier
) const {
4292 size_t text_len
= text
.size();
4293 unsigned int length
;
4296 length
= font
->measureString(string(text
, 0, text_len
)) + modifier
;
4297 } while (length
> max_length
&& text_len
-- > 0);
4301 start_pos
+= max_length
- length
;
4305 start_pos
+= (max_length
- length
) / 2;
4315 BWindowGroup::BWindowGroup(Blackbox
*b
, Window _group
)
4316 : blackbox(b
), group(_group
) {
4317 XWindowAttributes wattrib
;
4318 if (! XGetWindowAttributes(blackbox
->getXDisplay(), group
, &wattrib
)) {
4319 // group window doesn't seem to exist anymore
4324 XSelectInput(blackbox
->getXDisplay(), group
,
4325 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
4327 blackbox
->saveGroupSearch(group
, this);
4331 BWindowGroup::~BWindowGroup(void) {
4332 blackbox
->removeGroupSearch(group
);
4337 BWindowGroup::find(BScreen
*screen
, bool allow_transients
) const {
4338 BlackboxWindow
*ret
= blackbox
->getFocusedWindow();
4340 // does the focus window match (or any transient_fors)?
4341 for (; ret
; ret
= ret
->getTransientFor()) {
4342 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
&&
4343 (! ret
->isTransient() || allow_transients
))
4347 if (ret
) return ret
;
4349 // the focus window didn't match, look in the group's window list
4350 BlackboxWindowList::const_iterator it
, end
= windowList
.end();
4351 for (it
= windowList
.begin(); it
!= end
; ++it
) {
4353 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
&&
4354 (! ret
->isTransient() || allow_transients
))