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
47 #include "blackbox.hh"
48 #include "clientmenu.hh"
51 #include "iconmenu.hh"
57 #include "windowmenu.hh"
58 #include "workspace.hh"
65 * Initializes the class with default values/the window's set initial values.
67 BlackboxWindow::BlackboxWindow(Blackbox
*b
, Window w
, BScreen
*s
) {
68 // fprintf(stderr, "BlackboxWindow size: %d bytes\n",
69 // sizeof(BlackboxWindow));
72 fprintf(stderr
, "BlackboxWindow::BlackboxWindow(): creating 0x%lx\n", w
);
76 set timer to zero... it is initialized properly later, so we check
77 if timer is zero in the destructor, and assume that the window is not
78 fully constructed if timer is zero...
84 xatom
= blackbox
->getXAtom();
86 if (! validateClient()) {
91 // fetch client size and placement
92 XWindowAttributes wattrib
;
93 if (! XGetWindowAttributes(blackbox
->getXDisplay(),
94 client
.window
, &wattrib
) ||
95 ! wattrib
.screen
|| wattrib
.override_redirect
) {
98 "BlackboxWindow::BlackboxWindow(): XGetWindowAttributes failed\n");
105 // set the eventmask early in the game so that we make sure we get
106 // all the events we are interested in
107 XSetWindowAttributes attrib_set
;
108 attrib_set
.event_mask
= PropertyChangeMask
| FocusChangeMask
|
110 attrib_set
.do_not_propagate_mask
= ButtonPressMask
| ButtonReleaseMask
|
112 XChangeWindowAttributes(blackbox
->getXDisplay(), client
.window
,
113 CWEventMask
|CWDontPropagate
, &attrib_set
);
115 flags
.moving
= flags
.resizing
= flags
.shaded
= flags
.visible
=
116 flags
.iconic
= flags
.focused
= flags
.stuck
= flags
.modal
=
117 flags
.send_focus_message
= flags
.shaped
= flags
.skip_taskbar
=
118 flags
.skip_pager
= flags
.fullscreen
= False
;
121 blackbox_attrib
.workspace
= window_number
= BSENTINEL
;
123 blackbox_attrib
.flags
= blackbox_attrib
.attrib
= blackbox_attrib
.stack
= 0l;
124 blackbox_attrib
.decoration
= DecorNormal
;
125 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
126 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
129 frame
.window
= frame
.plate
= frame
.title
= frame
.handle
= None
;
130 frame
.close_button
= frame
.iconify_button
= frame
.maximize_button
=
131 frame
.stick_button
= None
;
132 frame
.right_grip
= frame
.left_grip
= None
;
134 frame
.ulabel_pixel
= frame
.flabel_pixel
= frame
.utitle_pixel
=
135 frame
.ftitle_pixel
= frame
.uhandle_pixel
= frame
.fhandle_pixel
=
136 frame
.ubutton_pixel
= frame
.fbutton_pixel
= frame
.uborder_pixel
=
137 frame
.fborder_pixel
= frame
.ugrip_pixel
= frame
.fgrip_pixel
= 0;
138 frame
.utitle
= frame
.ftitle
= frame
.uhandle
= frame
.fhandle
= None
;
139 frame
.ulabel
= frame
.flabel
= frame
.ubutton
= frame
.fbutton
= None
;
140 frame
.ugrip
= frame
.fgrip
= None
;
142 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
143 mwm_decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
144 Decor_Iconify
| Decor_Maximize
;
146 client
.normal_hint_flags
= 0;
147 client
.window_group
= None
;
148 client
.transient_for
= 0;
150 current_state
= NormalState
;
155 set the initial size and location of client window (relative to the
156 _root window_). This position is the reference point used with the
157 window's gravity to find the window's initial position.
159 client
.rect
.setRect(wattrib
.x
, wattrib
.y
, wattrib
.width
, wattrib
.height
);
160 client
.old_bw
= wattrib
.border_width
;
162 lastButtonPressTime
= 0;
164 timer
= new BTimer(blackbox
, this);
165 timer
->setTimeout(blackbox
->getAutoRaiseDelay());
167 // get size, aspect, minimum/maximum size and other hints set by the
170 if (! getBlackboxHints())
177 frame
.window
= createToplevelWindow();
179 blackbox
->saveWindowSearch(frame
.window
, this);
181 frame
.plate
= createChildWindow(frame
.window
, ExposureMask
);
182 blackbox
->saveWindowSearch(frame
.plate
, this);
184 // determine if this is a transient window
187 // determine the window's type, so we can decide its decorations and
188 // functionality, or if we should not manage it at all
189 if (getWindowType()) {
190 // adjust the window decorations/behavior based on the window type
191 switch (window_type
) {
195 blackbox_attrib
.workspace
= 0; // we do need to belong to a workspace
196 flags
.stuck
= True
; // we show up on all workspaces
198 // none of these windows are manipulated by the window manager
204 // these windows get less functionality
205 functions
&= ~(Func_Maximize
| Func_Resize
| Func_Iconify
);
209 // dialogs cannot be maximized
210 functions
&= ~Func_Maximize
;
214 // normal windows retain all of the possible decorations and
222 // further adjeust the window's decorations/behavior based on window sizes
223 if ((client
.normal_hint_flags
& PMinSize
) &&
224 (client
.normal_hint_flags
& PMaxSize
) &&
225 client
.max_width
<= client
.min_width
&&
226 client
.max_height
<= client
.min_height
) {
227 functions
&= ~(Func_Resize
| Func_Maximize
);
234 if (decorations
& Decor_Titlebar
)
237 if (decorations
& Decor_Handle
)
240 // apply the size and gravity hint to the frame
244 bool place_window
= True
;
245 if (blackbox
->isStartup() || isTransient() ||
246 client
.normal_hint_flags
& (PPosition
|USPosition
)) {
247 applyGravity(frame
.rect
);
249 if (blackbox
->isStartup() || client
.rect
.intersects(screen
->getRect()))
250 place_window
= False
;
253 // add the window's strut. note this is done *after* placing the window.
254 screen
->addStrut(&client
.strut
);
258 the server needs to be grabbed here to prevent client's from sending
259 events while we are in the process of configuring their window.
260 We hold the grab until after we are done moving the window around.
263 XGrabServer(blackbox
->getXDisplay());
265 associateClientWindow();
267 blackbox
->saveWindowSearch(client
.window
, this);
269 if (blackbox_attrib
.workspace
>= screen
->getWorkspaceCount())
270 screen
->getCurrentWorkspace()->addWindow(this, place_window
);
272 screen
->getWorkspace(blackbox_attrib
.workspace
)->
273 addWindow(this, place_window
);
275 if (! place_window
) {
276 // don't need to call configure if we are letting the workspace
278 configure(frame
.rect
.x(), frame
.rect
.y(),
279 frame
.rect
.width(), frame
.rect
.height());
285 XUngrabServer(blackbox
->getXDisplay());
288 if (blackbox
->hasShapeExtensions() && flags
.shaped
)
292 // now that we know where to put the window and what it should look like
293 // we apply the decorations
298 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
300 // this ensures the title, buttons, and other decor are properly displayed
303 // preserve the window's initial state on first map, and its current state
305 unsigned long initial_state
= current_state
;
307 current_state
= initial_state
;
309 // get sticky state from our parent window if we've got one
310 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
311 client
.transient_for
->isStuck() != flags
.stuck
)
315 flags
.shaded
= False
;
316 initial_state
= current_state
;
320 At this point in the life of a window, current_state should only be set
321 to IconicState if the window was an *icon*, not if it was shaded.
323 if (initial_state
!= IconicState
)
324 current_state
= NormalState
;
332 if (flags
.maximized
&& (functions
& Func_Maximize
))
335 // create this last so it only needs to be configured once
336 windowmenu
= new Windowmenu(this);
340 BlackboxWindow::~BlackboxWindow(void) {
342 fprintf(stderr
, "BlackboxWindow::~BlackboxWindow: destroying 0x%lx\n",
346 if (! timer
) // window not managed...
352 screen
->removeStrut(&client
.strut
);
353 screen
->updateAvailableArea();
355 // We don't need to worry about resizing because resizing always grabs the X
356 // server. This should only ever happen if using opaque moving.
364 if (client
.window_group
) {
365 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
366 if (group
) group
->removeWindow(this);
369 // remove ourselves from our transient_for
371 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul)
372 client
.transient_for
->client
.transientList
.remove(this);
373 client
.transient_for
= (BlackboxWindow
*) 0;
376 if (client
.transientList
.size() > 0) {
377 // reset transient_for for all transients
378 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
379 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
380 (*it
)->client
.transient_for
= (BlackboxWindow
*) 0;
390 blackbox
->removeWindowSearch(frame
.plate
);
391 XDestroyWindow(blackbox
->getXDisplay(), frame
.plate
);
395 blackbox
->removeWindowSearch(frame
.window
);
396 XDestroyWindow(blackbox
->getXDisplay(), frame
.window
);
399 blackbox
->removeWindowSearch(client
.window
);
403 void BlackboxWindow::enableDecor(bool enable
) {
404 blackbox_attrib
.flags
|= AttribDecoration
;
405 blackbox_attrib
.decoration
= enable
? DecorNormal
: DecorNone
;
408 // we can not be shaded if we lack a titlebar
409 if (! (decorations
& Decor_Titlebar
) && flags
.shaded
)
412 if (flags
.visible
&& frame
.window
) {
413 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
414 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
418 setState(current_state
);
422 void BlackboxWindow::setupDecor() {
423 if (blackbox_attrib
.decoration
!= DecorNone
) {
424 // start with everything on
425 decorations
= Decor_Close
|
426 (mwm_decorations
& Decor_Titlebar
? Decor_Titlebar
: 0) |
427 (mwm_decorations
& Decor_Border
? Decor_Border
: 0) |
428 (mwm_decorations
& Decor_Handle
? Decor_Handle
: 0) |
429 (mwm_decorations
& Decor_Iconify
? Decor_Iconify
: 0) |
430 (mwm_decorations
& Decor_Maximize
? Decor_Maximize
: 0);
432 if (! (functions
& Func_Close
)) decorations
&= ~Decor_Close
;
433 if (! (functions
& Func_Maximize
)) decorations
&= ~Decor_Maximize
;
434 if (! (functions
& Func_Iconify
)) decorations
&= ~Decor_Iconify
;
435 if (! (functions
& Func_Resize
)) decorations
&= ~Decor_Handle
;
437 switch (window_type
) {
442 // none of these windows are decorated by the window manager at all
448 decorations
&= ~(Decor_Border
);
452 decorations
&= ~Decor_Handle
;
464 * Creates a new top level window, with a given location, size, and border
466 * Returns: the newly created window
468 Window
BlackboxWindow::createToplevelWindow(void) {
469 XSetWindowAttributes attrib_create
;
470 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
| CWColormap
|
471 CWOverrideRedirect
| CWEventMask
;
473 attrib_create
.background_pixmap
= None
;
474 attrib_create
.colormap
= screen
->getColormap();
475 attrib_create
.override_redirect
= True
;
476 attrib_create
.event_mask
= EnterWindowMask
| LeaveWindowMask
|
479 We catch button presses because other wise they get passed down to the
480 root window, which will then cause root menus to show when you click the
484 return XCreateWindow(blackbox
->getXDisplay(), screen
->getRootWindow(),
485 0, 0, 1, 1, frame
.border_w
, screen
->getDepth(),
486 InputOutput
, screen
->getVisual(), create_mask
,
492 * Creates a child window, and optionally associates a given cursor with
495 Window
BlackboxWindow::createChildWindow(Window parent
,
496 unsigned long event_mask
,
498 XSetWindowAttributes attrib_create
;
499 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
|
502 attrib_create
.background_pixmap
= None
;
503 attrib_create
.event_mask
= event_mask
;
506 create_mask
|= CWCursor
;
507 attrib_create
.cursor
= cursor
;
510 return XCreateWindow(blackbox
->getXDisplay(), parent
, 0, 0, 1, 1, 0,
511 screen
->getDepth(), InputOutput
, screen
->getVisual(),
512 create_mask
, &attrib_create
);
516 void BlackboxWindow::associateClientWindow(void) {
517 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, 0);
521 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeInsert
);
523 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, SubstructureRedirectMask
);
526 note we used to grab around this call to XReparentWindow however the
527 server is now grabbed before this method is called
529 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
531 XSelectInput(blackbox
->getXDisplay(), client
.window
,
532 event_mask
& ~StructureNotifyMask
);
533 XReparentWindow(blackbox
->getXDisplay(), client
.window
, frame
.plate
, 0, 0);
534 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
536 XRaiseWindow(blackbox
->getXDisplay(), frame
.plate
);
537 XMapSubwindows(blackbox
->getXDisplay(), frame
.plate
);
540 if (blackbox
->hasShapeExtensions()) {
541 XShapeSelectInput(blackbox
->getXDisplay(), client
.window
,
548 XShapeQueryExtents(blackbox
->getXDisplay(), client
.window
, &shaped
,
549 &foo
, &foo
, &ufoo
, &ufoo
, &foo
, &foo
, &foo
,
551 flags
.shaped
= shaped
;
557 void BlackboxWindow::decorate(void) {
560 texture
= &(screen
->getWindowStyle()->b_focus
);
561 frame
.fbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
564 frame
.fbutton_pixel
= texture
->color().pixel();
566 texture
= &(screen
->getWindowStyle()->b_unfocus
);
567 frame
.ubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
570 frame
.ubutton_pixel
= texture
->color().pixel();
572 unsigned char needsPressed
= 0;
574 texture
= &(screen
->getWindowStyle()->b_pressed_focus
);
576 if (texture
->texture() != BTexture::NoTexture
) {
577 frame
.pfbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
579 if (! frame
.pfbutton
)
580 frame
.pfbutton_pixel
= texture
->color().pixel();
585 texture
= &(screen
->getWindowStyle()->b_pressed_unfocus
);
587 if (texture
->texture() != BTexture::NoTexture
) {
588 frame
.pubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
590 if (! frame
.pubutton
)
591 frame
.pubutton
= texture
->color().pixel();
596 // if we either pressed unfocused, or pressed focused were undefined,
597 // make them inherit from the old resource. It's a hack for sure, but
598 // it allows for some backwards and forwards compatibility.
600 texture
= &(screen
->getWindowStyle()->b_pressed
);
602 if (needsPressed
& 0x1) {
603 frame
.pfbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
605 if (! frame
.pfbutton
)
606 frame
.pfbutton_pixel
= texture
->color().pixel();
608 if (needsPressed
& 0x2) {
609 frame
.pubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
611 if (! frame
.pubutton
)
612 frame
.pubutton
= texture
->color().pixel();
617 if (decorations
& Decor_Titlebar
) {
618 texture
= &(screen
->getWindowStyle()->t_focus
);
619 frame
.ftitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
622 frame
.ftitle_pixel
= texture
->color().pixel();
624 texture
= &(screen
->getWindowStyle()->t_unfocus
);
625 frame
.utitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
628 frame
.utitle_pixel
= texture
->color().pixel();
630 XSetWindowBorder(blackbox
->getXDisplay(), frame
.title
,
631 screen
->getBorderColor()->pixel());
636 if (decorations
& Decor_Border
) {
637 frame
.fborder_pixel
= screen
->getWindowStyle()->f_focus
.color().pixel();
638 frame
.uborder_pixel
= screen
->getWindowStyle()->f_unfocus
.color().pixel();
641 if (decorations
& Decor_Handle
) {
642 texture
= &(screen
->getWindowStyle()->h_focus
);
643 frame
.fhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
646 frame
.fhandle_pixel
= texture
->color().pixel();
648 texture
= &(screen
->getWindowStyle()->h_unfocus
);
649 frame
.uhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
652 frame
.uhandle_pixel
= texture
->color().pixel();
654 texture
= &(screen
->getWindowStyle()->g_focus
);
655 frame
.fgrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.fgrip
);
657 frame
.fgrip_pixel
= texture
->color().pixel();
659 texture
= &(screen
->getWindowStyle()->g_unfocus
);
660 frame
.ugrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.ugrip
);
662 frame
.ugrip_pixel
= texture
->color().pixel();
664 XSetWindowBorder(blackbox
->getXDisplay(), frame
.handle
,
665 screen
->getBorderColor()->pixel());
666 XSetWindowBorder(blackbox
->getXDisplay(), frame
.left_grip
,
667 screen
->getBorderColor()->pixel());
668 XSetWindowBorder(blackbox
->getXDisplay(), frame
.right_grip
,
669 screen
->getBorderColor()->pixel());
672 XSetWindowBorder(blackbox
->getXDisplay(), frame
.window
,
673 screen
->getBorderColor()->pixel());
677 void BlackboxWindow::decorateLabel(void) {
680 texture
= &(screen
->getWindowStyle()->l_focus
);
681 frame
.flabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.flabel
);
683 frame
.flabel_pixel
= texture
->color().pixel();
685 texture
= &(screen
->getWindowStyle()->l_unfocus
);
686 frame
.ulabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.ulabel
);
688 frame
.ulabel_pixel
= texture
->color().pixel();
692 void BlackboxWindow::createHandle(void) {
693 frame
.handle
= createChildWindow(frame
.window
,
694 ButtonPressMask
| ButtonReleaseMask
|
695 ButtonMotionMask
| ExposureMask
);
696 blackbox
->saveWindowSearch(frame
.handle
, this);
699 createChildWindow(frame
.handle
,
700 ButtonPressMask
| ButtonReleaseMask
|
701 ButtonMotionMask
| ExposureMask
,
702 blackbox
->getLowerLeftAngleCursor());
703 blackbox
->saveWindowSearch(frame
.left_grip
, this);
706 createChildWindow(frame
.handle
,
707 ButtonPressMask
| ButtonReleaseMask
|
708 ButtonMotionMask
| ExposureMask
,
709 blackbox
->getLowerRightAngleCursor());
710 blackbox
->saveWindowSearch(frame
.right_grip
, this);
714 void BlackboxWindow::destroyHandle(void) {
716 screen
->getImageControl()->removeImage(frame
.fhandle
);
719 screen
->getImageControl()->removeImage(frame
.uhandle
);
722 screen
->getImageControl()->removeImage(frame
.fgrip
);
725 screen
->getImageControl()->removeImage(frame
.ugrip
);
727 blackbox
->removeWindowSearch(frame
.left_grip
);
728 blackbox
->removeWindowSearch(frame
.right_grip
);
730 XDestroyWindow(blackbox
->getXDisplay(), frame
.left_grip
);
731 XDestroyWindow(blackbox
->getXDisplay(), frame
.right_grip
);
732 frame
.left_grip
= frame
.right_grip
= None
;
734 blackbox
->removeWindowSearch(frame
.handle
);
735 XDestroyWindow(blackbox
->getXDisplay(), frame
.handle
);
740 void BlackboxWindow::createTitlebar(void) {
741 frame
.title
= createChildWindow(frame
.window
,
742 ButtonPressMask
| ButtonReleaseMask
|
743 ButtonMotionMask
| ExposureMask
);
744 frame
.label
= createChildWindow(frame
.title
,
745 ButtonPressMask
| ButtonReleaseMask
|
746 ButtonMotionMask
| ExposureMask
);
747 blackbox
->saveWindowSearch(frame
.title
, this);
748 blackbox
->saveWindowSearch(frame
.label
, this);
750 if (decorations
& Decor_Iconify
) createIconifyButton();
751 if (decorations
& Decor_Maximize
) createMaximizeButton();
752 if (decorations
& Decor_Close
) createCloseButton();
756 void BlackboxWindow::destroyTitlebar(void) {
757 if (frame
.close_button
)
758 destroyCloseButton();
760 if (frame
.iconify_button
)
761 destroyIconifyButton();
763 if (frame
.maximize_button
)
764 destroyMaximizeButton();
766 if (frame
.stick_button
)
767 destroyStickyButton();
770 screen
->getImageControl()->removeImage(frame
.ftitle
);
773 screen
->getImageControl()->removeImage(frame
.utitle
);
776 screen
->getImageControl()->removeImage(frame
.flabel
);
779 screen
->getImageControl()->removeImage(frame
.ulabel
);
782 screen
->getImageControl()->removeImage(frame
.fbutton
);
785 screen
->getImageControl()->removeImage(frame
.ubutton
);
787 blackbox
->removeWindowSearch(frame
.title
);
788 blackbox
->removeWindowSearch(frame
.label
);
790 XDestroyWindow(blackbox
->getXDisplay(), frame
.label
);
791 XDestroyWindow(blackbox
->getXDisplay(), frame
.title
);
792 frame
.title
= frame
.label
= None
;
796 void BlackboxWindow::createCloseButton(void) {
797 if (frame
.title
!= None
) {
798 frame
.close_button
= createChildWindow(frame
.title
,
801 ButtonMotionMask
| ExposureMask
);
802 blackbox
->saveWindowSearch(frame
.close_button
, this);
807 void BlackboxWindow::destroyCloseButton(void) {
808 blackbox
->removeWindowSearch(frame
.close_button
);
809 XDestroyWindow(blackbox
->getXDisplay(), frame
.close_button
);
810 frame
.close_button
= None
;
814 void BlackboxWindow::createIconifyButton(void) {
815 if (frame
.title
!= None
) {
816 frame
.iconify_button
= createChildWindow(frame
.title
,
819 ButtonMotionMask
| ExposureMask
);
820 blackbox
->saveWindowSearch(frame
.iconify_button
, this);
825 void BlackboxWindow::destroyIconifyButton(void) {
826 blackbox
->removeWindowSearch(frame
.iconify_button
);
827 XDestroyWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
828 frame
.iconify_button
= None
;
832 void BlackboxWindow::createMaximizeButton(void) {
833 if (frame
.title
!= None
) {
834 frame
.maximize_button
= createChildWindow(frame
.title
,
837 ButtonMotionMask
| ExposureMask
);
838 blackbox
->saveWindowSearch(frame
.maximize_button
, this);
843 void BlackboxWindow::destroyMaximizeButton(void) {
844 blackbox
->removeWindowSearch(frame
.maximize_button
);
845 XDestroyWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
846 frame
.maximize_button
= None
;
849 void BlackboxWindow::createStickyButton(void) {
850 if (frame
.title
!= None
) {
851 frame
.stick_button
= createChildWindow(frame
.title
,
854 ButtonMotionMask
| ExposureMask
);
855 blackbox
->saveWindowSearch(frame
.stick_button
, this);
859 void BlackboxWindow::destroyStickyButton(void) {
860 blackbox
->removeWindowSearch(frame
.stick_button
);
861 XDestroyWindow(blackbox
->getXDisplay(), frame
.stick_button
);
862 frame
.stick_button
= None
;
865 void BlackboxWindow::positionButtons(bool redecorate_label
) {
866 string layout
= blackbox
->getTitlebarLayout();
869 bool hasclose
, hasiconify
, hasmaximize
, haslabel
, hasstick
;
870 hasclose
= hasiconify
= hasmaximize
= haslabel
= hasstick
= false;
872 string::const_iterator it
, end
;
873 for (it
= layout
.begin(), end
= layout
.end(); it
!= end
; ++it
) {
876 if (! hasclose
&& (decorations
& Decor_Close
)) {
882 if (! hasiconify
&& (decorations
& Decor_Iconify
)) {
894 if (! hasmaximize
&& (decorations
& Decor_Maximize
)) {
908 if (! hasclose
&& frame
.close_button
)
909 destroyCloseButton();
910 if (! hasiconify
&& frame
.iconify_button
)
911 destroyIconifyButton();
912 if (! hasmaximize
&& frame
.maximize_button
)
913 destroyMaximizeButton();
914 if (! hasstick
&& frame
.stick_button
)
915 destroyStickyButton();
917 parsed
+= 'L'; // require that the label be in the layout
919 const unsigned int bsep
= frame
.bevel_w
+ 1; // separation between elements
920 const unsigned int by
= frame
.bevel_w
+ 1;
921 const unsigned int ty
= frame
.bevel_w
;
923 frame
.label_w
= frame
.inside_w
- bsep
* 2 -
924 (frame
.button_w
+ bsep
) * (parsed
.size() - 1);
926 unsigned int x
= bsep
;
927 for (it
= parsed
.begin(), end
= parsed
.end(); it
!= end
; ++it
) {
930 if (! frame
.close_button
) createCloseButton();
931 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.close_button
, x
, by
,
932 frame
.button_w
, frame
.button_w
);
933 x
+= frame
.button_w
+ bsep
;
936 if (! frame
.iconify_button
) createIconifyButton();
937 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.iconify_button
, x
, by
,
938 frame
.button_w
, frame
.button_w
);
939 x
+= frame
.button_w
+ bsep
;
942 if (! frame
.stick_button
) createStickyButton();
943 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.stick_button
, x
, by
,
944 frame
.button_w
, frame
.button_w
);
945 x
+= frame
.button_w
+ bsep
;
948 if (! frame
.maximize_button
) createMaximizeButton();
949 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.maximize_button
, x
, by
,
950 frame
.button_w
, frame
.button_w
);
951 x
+= frame
.button_w
+ bsep
;
954 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.label
, x
, ty
,
955 frame
.label_w
, frame
.label_h
);
956 x
+= frame
.label_w
+ bsep
;
961 if (redecorate_label
) decorateLabel();
967 void BlackboxWindow::reconfigure(void) {
968 restoreGravity(client
.rect
);
970 applyGravity(frame
.rect
);
979 windowmenu
->move(windowmenu
->getX(), frame
.rect
.y() + frame
.title_h
);
980 windowmenu
->reconfigure();
985 void BlackboxWindow::grabButtons(void) {
986 mod_mask
= blackbox
->getMouseModMask();
988 if (! screen
->isSloppyFocus() || screen
->doClickRaise())
989 // grab button 1 for changing focus/raising
990 blackbox
->grabButton(Button1
, 0, frame
.plate
, True
, ButtonPressMask
,
991 GrabModeSync
, GrabModeSync
, frame
.plate
, None
,
992 screen
->allowScrollLock());
994 if (functions
& Func_Move
)
995 blackbox
->grabButton(Button1
, mod_mask
, frame
.window
, True
,
996 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
997 GrabModeAsync
, frame
.window
, None
,
998 screen
->allowScrollLock());
999 if (functions
& Func_Resize
)
1000 blackbox
->grabButton(Button3
, mod_mask
, frame
.window
, True
,
1001 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
1002 GrabModeAsync
, frame
.window
, None
,
1003 screen
->allowScrollLock());
1004 // alt+middle lowers the window
1005 blackbox
->grabButton(Button2
, mod_mask
, frame
.window
, True
,
1006 ButtonReleaseMask
, GrabModeAsync
, GrabModeAsync
,
1007 frame
.window
, None
, screen
->allowScrollLock());
1011 void BlackboxWindow::ungrabButtons(void) {
1012 blackbox
->ungrabButton(Button1
, 0, frame
.plate
);
1013 blackbox
->ungrabButton(Button1
, mod_mask
, frame
.window
);
1014 blackbox
->ungrabButton(Button2
, mod_mask
, frame
.window
);
1015 blackbox
->ungrabButton(Button3
, mod_mask
, frame
.window
);
1019 void BlackboxWindow::positionWindows(void) {
1020 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1021 frame
.rect
.x(), frame
.rect
.y(), frame
.inside_w
,
1022 (flags
.shaded
) ? frame
.title_h
: frame
.inside_h
);
1023 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.window
,
1025 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.plate
,
1026 frame
.mwm_border_w
);
1027 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.plate
,
1028 frame
.margin
.left
- frame
.mwm_border_w
- frame
.border_w
,
1029 frame
.margin
.top
- frame
.mwm_border_w
- frame
.border_w
,
1030 client
.rect
.width(), client
.rect
.height());
1031 XMoveResizeWindow(blackbox
->getXDisplay(), client
.window
,
1032 0, 0, client
.rect
.width(), client
.rect
.height());
1033 // ensure client.rect contains the real location
1034 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1035 frame
.rect
.top() + frame
.margin
.top
);
1037 if (decorations
& Decor_Titlebar
) {
1038 if (frame
.title
== None
) createTitlebar();
1040 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.title
,
1042 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.title
, -frame
.border_w
,
1043 -frame
.border_w
, frame
.inside_w
, frame
.title_h
);
1046 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
1047 XMapWindow(blackbox
->getXDisplay(), frame
.title
);
1048 } else if (frame
.title
) {
1051 if (decorations
& Decor_Handle
) {
1052 if (frame
.handle
== None
) createHandle();
1053 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.handle
,
1055 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.left_grip
,
1057 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.right_grip
,
1060 // use client.rect here so the value is correct even if shaded
1061 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.handle
,
1063 client
.rect
.height() + frame
.margin
.top
+
1064 frame
.mwm_border_w
- frame
.border_w
,
1065 frame
.inside_w
, frame
.handle_h
);
1066 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.left_grip
,
1067 -frame
.border_w
, -frame
.border_w
,
1068 frame
.grip_w
, frame
.handle_h
);
1069 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.right_grip
,
1070 frame
.inside_w
- frame
.grip_w
- frame
.border_w
,
1071 -frame
.border_w
, frame
.grip_w
, frame
.handle_h
);
1073 XMapSubwindows(blackbox
->getXDisplay(), frame
.handle
);
1074 XMapWindow(blackbox
->getXDisplay(), frame
.handle
);
1075 } else if (frame
.handle
) {
1078 XSync(blackbox
->getXDisplay(), False
);
1082 void BlackboxWindow::updateStrut(void) {
1083 unsigned long num
= 4;
1084 unsigned long *data
;
1085 if (! xatom
->getValue(client
.window
, XAtom::net_wm_strut
, XAtom::cardinal
,
1090 client
.strut
.left
= data
[0];
1091 client
.strut
.right
= data
[1];
1092 client
.strut
.top
= data
[2];
1093 client
.strut
.bottom
= data
[3];
1095 screen
->updateAvailableArea();
1102 bool BlackboxWindow::getWindowType(void) {
1103 window_type
= (WindowType
) -1;
1106 unsigned long num
= (unsigned) -1;
1107 if (xatom
->getValue(client
.window
, XAtom::net_wm_window_type
, XAtom::atom
,
1109 for (unsigned long i
= 0; i
< num
; ++i
) {
1110 if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_desktop
))
1111 window_type
= Type_Desktop
;
1112 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_dock
))
1113 window_type
= Type_Dock
;
1114 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_toolbar
))
1115 window_type
= Type_Toolbar
;
1116 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_menu
))
1117 window_type
= Type_Menu
;
1118 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_utility
))
1119 window_type
= Type_Utility
;
1120 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_splash
))
1121 window_type
= Type_Splash
;
1122 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_dialog
))
1123 window_type
= Type_Dialog
;
1124 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_normal
))
1125 window_type
= Type_Normal
;
1127 xatom
->getAtom(XAtom::kde_net_wm_window_type_override
))
1128 mwm_decorations
= 0; // prevent this window from getting any decor
1133 if (window_type
== (WindowType
) -1) {
1135 * the window type hint was not set, which means we either classify ourself
1136 * as a normal window or a dialog, depending on if we are a transient.
1139 window_type
= Type_Dialog
;
1141 window_type
= Type_Normal
;
1150 void BlackboxWindow::getWMName(void) {
1151 if (xatom
->getValue(client
.window
, XAtom::net_wm_name
,
1152 XAtom::utf8
, client
.title
) &&
1153 !client
.title
.empty()) {
1154 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
1157 //fall through to using WM_NAME
1158 if (xatom
->getValue(client
.window
, XAtom::wm_name
, XAtom::ansi
, client
.title
)
1159 && !client
.title
.empty()) {
1160 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
1163 // fall back to an internal default
1164 client
.title
= i18n(WindowSet
, WindowUnnamed
, "Unnamed");
1165 xatom
->setValue(client
.window
, XAtom::net_wm_visible_name
, XAtom::utf8
,
1168 #ifdef DEBUG_WITH_ID
1169 // the 16 is the 8 chars of the debug text plus the number
1170 char *tmp
= new char[client
.title
.length() + 16];
1171 sprintf(tmp
, "%s; id: 0x%lx", client
.title
.c_str(), client
.window
);
1178 void BlackboxWindow::getWMIconName(void) {
1179 if (xatom
->getValue(client
.window
, XAtom::net_wm_icon_name
,
1180 XAtom::utf8
, client
.icon_title
) &&
1181 !client
.icon_title
.empty()) {
1182 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1185 //fall through to using WM_ICON_NAME
1186 if (xatom
->getValue(client
.window
, XAtom::wm_icon_name
, XAtom::ansi
,
1187 client
.icon_title
) &&
1188 !client
.icon_title
.empty()) {
1189 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1192 // fall back to using the main name
1193 client
.icon_title
= client
.title
;
1194 xatom
->setValue(client
.window
, XAtom::net_wm_visible_icon_name
, XAtom::utf8
,
1200 * Retrieve which WM Protocols are supported by the client window.
1201 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
1202 * window's decorations and allow the close behavior.
1203 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
1206 void BlackboxWindow::getWMProtocols(void) {
1210 if (XGetWMProtocols(blackbox
->getXDisplay(), client
.window
,
1211 &proto
, &num_return
)) {
1212 for (int i
= 0; i
< num_return
; ++i
) {
1213 if (proto
[i
] == xatom
->getAtom(XAtom::wm_delete_window
)) {
1214 decorations
|= Decor_Close
;
1215 functions
|= Func_Close
;
1216 } else if (proto
[i
] == xatom
->getAtom(XAtom::wm_take_focus
))
1217 flags
.send_focus_message
= True
;
1218 else if (proto
[i
] == xatom
->getAtom(XAtom::blackbox_structure_messages
))
1219 screen
->addNetizen(new Netizen(screen
, client
.window
));
1228 * Gets the value of the WM_HINTS property.
1229 * If the property is not set, then use a set of default values.
1231 void BlackboxWindow::getWMHints(void) {
1232 focus_mode
= F_Passive
;
1234 // remove from current window group
1235 if (client
.window_group
) {
1236 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1237 if (group
) group
->removeWindow(this);
1239 client
.window_group
= None
;
1241 XWMHints
*wmhint
= XGetWMHints(blackbox
->getXDisplay(), client
.window
);
1246 if (wmhint
->flags
& InputHint
) {
1247 if (wmhint
->input
== True
) {
1248 if (flags
.send_focus_message
)
1249 focus_mode
= F_LocallyActive
;
1251 if (flags
.send_focus_message
)
1252 focus_mode
= F_GloballyActive
;
1254 focus_mode
= F_NoInput
;
1258 if (wmhint
->flags
& StateHint
)
1259 current_state
= wmhint
->initial_state
;
1261 if (wmhint
->flags
& WindowGroupHint
) {
1262 client
.window_group
= wmhint
->window_group
;
1264 // add window to the appropriate group
1265 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1266 if (! group
) { // no group found, create it!
1267 new BWindowGroup(blackbox
, client
.window_group
);
1268 group
= blackbox
->searchGroup(client
.window_group
);
1271 group
->addWindow(this);
1279 * Gets the value of the WM_NORMAL_HINTS property.
1280 * If the property is not set, then use a set of default values.
1282 void BlackboxWindow::getWMNormalHints(void) {
1284 XSizeHints sizehint
;
1286 client
.min_width
= client
.min_height
=
1287 client
.width_inc
= client
.height_inc
= 1;
1288 client
.base_width
= client
.base_height
= 0;
1289 client
.win_gravity
= NorthWestGravity
;
1291 client
.min_aspect_x
= client
.min_aspect_y
=
1292 client
.max_aspect_x
= client
.max_aspect_y
= 1;
1295 // don't limit the size of a window, the default max width is the biggest
1297 client
.max_width
= (unsigned) -1;
1298 client
.max_height
= (unsigned) -1;
1301 if (! XGetWMNormalHints(blackbox
->getXDisplay(), client
.window
,
1302 &sizehint
, &icccm_mask
))
1305 client
.normal_hint_flags
= sizehint
.flags
;
1307 if (sizehint
.flags
& PMinSize
) {
1308 if (sizehint
.min_width
>= 0)
1309 client
.min_width
= sizehint
.min_width
;
1310 if (sizehint
.min_height
>= 0)
1311 client
.min_height
= sizehint
.min_height
;
1314 if (sizehint
.flags
& PMaxSize
) {
1315 if (sizehint
.max_width
> static_cast<signed>(client
.min_width
))
1316 client
.max_width
= sizehint
.max_width
;
1318 client
.max_width
= client
.min_width
;
1320 if (sizehint
.max_height
> static_cast<signed>(client
.min_height
))
1321 client
.max_height
= sizehint
.max_height
;
1323 client
.max_height
= client
.min_height
;
1326 if (sizehint
.flags
& PResizeInc
) {
1327 client
.width_inc
= sizehint
.width_inc
;
1328 client
.height_inc
= sizehint
.height_inc
;
1331 #if 0 // we do not support this at the moment
1332 if (sizehint
.flags
& PAspect
) {
1333 client
.min_aspect_x
= sizehint
.min_aspect
.x
;
1334 client
.min_aspect_y
= sizehint
.min_aspect
.y
;
1335 client
.max_aspect_x
= sizehint
.max_aspect
.x
;
1336 client
.max_aspect_y
= sizehint
.max_aspect
.y
;
1340 if (sizehint
.flags
& PBaseSize
) {
1341 client
.base_width
= sizehint
.base_width
;
1342 client
.base_height
= sizehint
.base_height
;
1345 if (sizehint
.flags
& PWinGravity
)
1346 client
.win_gravity
= sizehint
.win_gravity
;
1351 * Gets the NETWM hints for the class' contained window.
1353 void BlackboxWindow::getNetWMHints(void) {
1354 unsigned long workspace
;
1356 if (xatom
->getValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1358 if (workspace
== 0xffffffff)
1361 blackbox_attrib
.workspace
= workspace
;
1364 unsigned long *state
;
1365 unsigned long num
= (unsigned) -1;
1366 if (xatom
->getValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
1370 for (unsigned long i
= 0; i
< num
; ++i
) {
1371 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
))
1373 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_shaded
))
1374 flags
.shaded
= True
;
1375 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
))
1376 flags
.skip_taskbar
= True
;
1377 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_pager
))
1378 flags
.skip_pager
= True
;
1379 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_fullscreen
))
1380 flags
.fullscreen
= True
;
1381 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_hidden
))
1382 setState(IconicState
);
1383 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_vert
))
1385 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_horz
))
1389 flags
.maximized
= 1;
1391 flags
.maximized
= 2;
1393 flags
.maximized
= 3;
1401 * Gets the MWM hints for the class' contained window.
1402 * This is used while initializing the window to its first state, and not
1404 * Returns: true if the MWM hints are successfully retreived and applied;
1405 * false if they are not.
1407 void BlackboxWindow::getMWMHints(void) {
1411 num
= PropMwmHintsElements
;
1412 if (! xatom
->getValue(client
.window
, XAtom::motif_wm_hints
,
1413 XAtom::motif_wm_hints
, num
,
1414 (unsigned long **)&mwm_hint
))
1416 if (num
< PropMwmHintsElements
) {
1421 if (mwm_hint
->flags
& MwmHintsDecorations
) {
1422 if (mwm_hint
->decorations
& MwmDecorAll
) {
1423 mwm_decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
1424 Decor_Iconify
| Decor_Maximize
;
1426 mwm_decorations
= 0;
1428 if (mwm_hint
->decorations
& MwmDecorBorder
)
1429 mwm_decorations
|= Decor_Border
;
1430 if (mwm_hint
->decorations
& MwmDecorHandle
)
1431 mwm_decorations
|= Decor_Handle
;
1432 if (mwm_hint
->decorations
& MwmDecorTitle
)
1433 mwm_decorations
|= Decor_Titlebar
;
1434 if (mwm_hint
->decorations
& MwmDecorIconify
)
1435 mwm_decorations
|= Decor_Iconify
;
1436 if (mwm_hint
->decorations
& MwmDecorMaximize
)
1437 mwm_decorations
|= Decor_Maximize
;
1441 if (mwm_hint
->flags
& MwmHintsFunctions
) {
1442 if (mwm_hint
->functions
& MwmFuncAll
) {
1443 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
|
1448 if (mwm_hint
->functions
& MwmFuncResize
)
1449 functions
|= Func_Resize
;
1450 if (mwm_hint
->functions
& MwmFuncMove
)
1451 functions
|= Func_Move
;
1452 if (mwm_hint
->functions
& MwmFuncIconify
)
1453 functions
|= Func_Iconify
;
1454 if (mwm_hint
->functions
& MwmFuncMaximize
)
1455 functions
|= Func_Maximize
;
1456 if (mwm_hint
->functions
& MwmFuncClose
)
1457 functions
|= Func_Close
;
1465 * Gets the blackbox hints from the class' contained window.
1466 * This is used while initializing the window to its first state, and not
1468 * Returns: true if the hints are successfully retreived and applied; false if
1471 bool BlackboxWindow::getBlackboxHints(void) {
1473 BlackboxHints
*blackbox_hint
;
1475 num
= PropBlackboxHintsElements
;
1476 if (! xatom
->getValue(client
.window
, XAtom::blackbox_hints
,
1477 XAtom::blackbox_hints
, num
,
1478 (unsigned long **)&blackbox_hint
))
1480 if (num
< PropBlackboxHintsElements
) {
1481 delete [] blackbox_hint
;
1485 if (blackbox_hint
->flags
& AttribShaded
)
1486 flags
.shaded
= (blackbox_hint
->attrib
& AttribShaded
);
1488 if ((blackbox_hint
->flags
& AttribMaxHoriz
) &&
1489 (blackbox_hint
->flags
& AttribMaxVert
))
1490 flags
.maximized
= (blackbox_hint
->attrib
&
1491 (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1492 else if (blackbox_hint
->flags
& AttribMaxVert
)
1493 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxVert
) ? 2 : 0;
1494 else if (blackbox_hint
->flags
& AttribMaxHoriz
)
1495 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1497 if (blackbox_hint
->flags
& AttribOmnipresent
)
1498 flags
.stuck
= (blackbox_hint
->attrib
& AttribOmnipresent
);
1500 if (blackbox_hint
->flags
& AttribWorkspace
)
1501 blackbox_attrib
.workspace
= blackbox_hint
->workspace
;
1503 // if (blackbox_hint->flags & AttribStack)
1504 // don't yet have always on top/bottom for blackbox yet... working
1507 if (blackbox_hint
->flags
& AttribDecoration
) {
1508 switch (blackbox_hint
->decoration
) {
1510 blackbox_attrib
.decoration
= DecorNone
;
1517 // blackbox_attrib.decoration defaults to DecorNormal
1522 delete [] blackbox_hint
;
1528 void BlackboxWindow::getTransientInfo(void) {
1529 if (client
.transient_for
&&
1530 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1531 // reset transient_for in preparation of looking for a new owner
1532 client
.transient_for
->client
.transientList
.remove(this);
1535 // we have no transient_for until we find a new one
1536 client
.transient_for
= (BlackboxWindow
*) 0;
1539 if (! XGetTransientForHint(blackbox
->getXDisplay(), client
.window
,
1541 // transient_for hint not set
1545 if (trans_for
== client
.window
) {
1546 // wierd client... treat this window as a normal window
1550 if (trans_for
== None
|| trans_for
== screen
->getRootWindow()) {
1551 // this is an undocumented interpretation of the ICCCM. a transient
1552 // associated with None/Root/itself is assumed to be a modal root
1553 // transient. we don't support the concept of a global transient,
1554 // so we just associate this transient with nothing, and perhaps
1555 // we will add support later for global modality.
1556 client
.transient_for
= (BlackboxWindow
*) ~0ul;
1561 client
.transient_for
= blackbox
->searchWindow(trans_for
);
1562 if (! client
.transient_for
&&
1563 client
.window_group
&& trans_for
== client
.window_group
) {
1564 // no direct transient_for, perhaps this is a group transient?
1565 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1566 if (group
) client
.transient_for
= group
->find(screen
);
1569 if (! client
.transient_for
|| client
.transient_for
== this) {
1570 // no transient_for found, or we have a wierd client that wants to be
1571 // a transient for itself, so we treat this window as a normal window
1572 client
.transient_for
= (BlackboxWindow
*) 0;
1576 // Check for a circular transient state: this can lock up Blackbox
1577 // when it tries to find the non-transient window for a transient.
1578 BlackboxWindow
*w
= this;
1579 while(w
->client
.transient_for
&&
1580 w
->client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1581 if(w
->client
.transient_for
== this) {
1582 client
.transient_for
= (BlackboxWindow
*) 0;
1585 w
= w
->client
.transient_for
;
1588 if (client
.transient_for
&&
1589 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1590 // register ourselves with our new transient_for
1591 client
.transient_for
->client
.transientList
.push_back(this);
1592 flags
.stuck
= client
.transient_for
->flags
.stuck
;
1597 BlackboxWindow
*BlackboxWindow::getTransientFor(void) const {
1598 if (client
.transient_for
&&
1599 client
.transient_for
!= (BlackboxWindow
*) ~0ul)
1600 return client
.transient_for
;
1606 * This function is responsible for updating both the client and the frame
1608 * According to the ICCCM a client message is not sent for a resize, only a
1611 void BlackboxWindow::configure(int dx
, int dy
,
1612 unsigned int dw
, unsigned int dh
) {
1613 bool send_event
= ((frame
.rect
.x() != dx
|| frame
.rect
.y() != dy
) &&
1616 if (dw
!= frame
.rect
.width() || dh
!= frame
.rect
.height()) {
1617 frame
.rect
.setRect(dx
, dy
, dw
, dh
);
1618 frame
.inside_w
= frame
.rect
.width() - (frame
.border_w
* 2);
1619 frame
.inside_h
= frame
.rect
.height() - (frame
.border_w
* 2);
1621 if (frame
.rect
.right() <= 0 || frame
.rect
.bottom() <= 0)
1622 frame
.rect
.setPos(0, 0);
1624 client
.rect
.setCoords(frame
.rect
.left() + frame
.margin
.left
,
1625 frame
.rect
.top() + frame
.margin
.top
,
1626 frame
.rect
.right() - frame
.margin
.right
,
1627 frame
.rect
.bottom() - frame
.margin
.bottom
);
1630 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
1637 redrawWindowFrame();
1639 frame
.rect
.setPos(dx
, dy
);
1641 XMoveWindow(blackbox
->getXDisplay(), frame
.window
,
1642 frame
.rect
.x(), frame
.rect
.y());
1644 we may have been called just after an opaque window move, so even though
1645 the old coords match the new ones no ConfigureNotify has been sent yet.
1646 There are likely other times when this will be relevant as well.
1648 if (! flags
.moving
) send_event
= True
;
1652 // if moving, the update and event will occur when the move finishes
1653 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1654 frame
.rect
.top() + frame
.margin
.top
);
1657 event
.type
= ConfigureNotify
;
1659 event
.xconfigure
.display
= blackbox
->getXDisplay();
1660 event
.xconfigure
.event
= client
.window
;
1661 event
.xconfigure
.window
= client
.window
;
1662 event
.xconfigure
.x
= client
.rect
.x();
1663 event
.xconfigure
.y
= client
.rect
.y();
1664 event
.xconfigure
.width
= client
.rect
.width();
1665 event
.xconfigure
.height
= client
.rect
.height();
1666 event
.xconfigure
.border_width
= client
.old_bw
;
1667 event
.xconfigure
.above
= frame
.window
;
1668 event
.xconfigure
.override_redirect
= False
;
1670 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1671 StructureNotifyMask
, &event
);
1672 screen
->updateNetizenConfigNotify(&event
);
1673 XFlush(blackbox
->getXDisplay());
1679 void BlackboxWindow::configureShape(void) {
1680 XShapeCombineShape(blackbox
->getXDisplay(), frame
.window
, ShapeBounding
,
1681 frame
.margin
.left
- frame
.border_w
,
1682 frame
.margin
.top
- frame
.border_w
,
1683 client
.window
, ShapeBounding
, ShapeSet
);
1686 XRectangle xrect
[2];
1688 if (decorations
& Decor_Titlebar
) {
1689 xrect
[0].x
= xrect
[0].y
= -frame
.border_w
;
1690 xrect
[0].width
= frame
.rect
.width();
1691 xrect
[0].height
= frame
.title_h
+ (frame
.border_w
* 2);
1695 if (decorations
& Decor_Handle
) {
1696 xrect
[1].x
= -frame
.border_w
;
1697 xrect
[1].y
= frame
.rect
.height() - frame
.margin
.bottom
+
1698 frame
.mwm_border_w
- frame
.border_w
;
1699 xrect
[1].width
= frame
.rect
.width();
1700 xrect
[1].height
= frame
.handle_h
+ (frame
.border_w
* 2);
1704 XShapeCombineRectangles(blackbox
->getXDisplay(), frame
.window
,
1705 ShapeBounding
, 0, 0, xrect
, num
,
1706 ShapeUnion
, Unsorted
);
1710 void BlackboxWindow::clearShape(void) {
1711 XShapeCombineMask(blackbox
->getXDisplay(), frame
.window
, ShapeBounding
,
1712 frame
.margin
.left
- frame
.border_w
,
1713 frame
.margin
.top
- frame
.border_w
,
1719 bool BlackboxWindow::setInputFocus(void) {
1720 if (flags
.focused
) return True
;
1722 assert(flags
.stuck
|| // window must be on the current workspace or sticky
1723 blackbox_attrib
.workspace
== screen
->getCurrentWorkspaceID());
1726 We only do this check for normal windows and dialogs because other windows
1727 do this on purpose, such as kde's kicker, and we don't want to go moving
1730 if (window_type
== Type_Normal
|| window_type
== Type_Dialog
)
1731 if (! frame
.rect
.intersects(screen
->getRect())) {
1732 // client is outside the screen, move it to the center
1733 configure((screen
->getWidth() - frame
.rect
.width()) / 2,
1734 (screen
->getHeight() - frame
.rect
.height()) / 2,
1735 frame
.rect
.width(), frame
.rect
.height());
1738 if (client
.transientList
.size() > 0) {
1739 // transfer focus to any modal transients
1740 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1741 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1742 if ((*it
)->flags
.modal
) return (*it
)->setInputFocus();
1746 if (focus_mode
== F_LocallyActive
|| focus_mode
== F_Passive
) {
1747 XSetInputFocus(blackbox
->getXDisplay(), client
.window
,
1748 RevertToPointerRoot
, CurrentTime
);
1750 /* we could set the focus to none, since the window doesn't accept focus,
1751 * but we shouldn't set focus to nothing since this would surely make
1757 if (flags
.send_focus_message
) {
1759 ce
.xclient
.type
= ClientMessage
;
1760 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1761 ce
.xclient
.display
= blackbox
->getXDisplay();
1762 ce
.xclient
.window
= client
.window
;
1763 ce
.xclient
.format
= 32;
1764 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_take_focus
);
1765 ce
.xclient
.data
.l
[1] = blackbox
->getLastTime();
1766 ce
.xclient
.data
.l
[2] = 0l;
1767 ce
.xclient
.data
.l
[3] = 0l;
1768 ce
.xclient
.data
.l
[4] = 0l;
1769 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1771 XFlush(blackbox
->getXDisplay());
1778 void BlackboxWindow::iconify(void) {
1779 if (flags
.iconic
|| ! (functions
& Func_Iconify
)) return;
1781 // We don't need to worry about resizing because resizing always grabs the X
1782 // server. This should only ever happen if using opaque moving.
1786 if (windowmenu
) windowmenu
->hide();
1789 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1790 * we need to clear the event mask on client.window for a split second.
1791 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1792 * split second, leaving us with a ghost window... so, we need to do this
1793 * while the X server is grabbed
1795 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1796 StructureNotifyMask
;
1797 XGrabServer(blackbox
->getXDisplay());
1798 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1799 event_mask
& ~StructureNotifyMask
);
1800 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1801 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1802 XUngrabServer(blackbox
->getXDisplay());
1804 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1805 flags
.visible
= False
;
1806 flags
.iconic
= True
;
1808 setState(IconicState
);
1810 screen
->getWorkspace(blackbox_attrib
.workspace
)->removeWindow(this);
1812 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
1813 if (i
!= blackbox_attrib
.workspace
)
1814 screen
->getWorkspace(i
)->removeWindow(this, True
);
1817 if (isTransient()) {
1818 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1819 ! client
.transient_for
->flags
.iconic
) {
1820 // iconify our transient_for
1821 client
.transient_for
->iconify();
1825 screen
->addIcon(this);
1827 if (client
.transientList
.size() > 0) {
1828 // iconify all transients
1829 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1830 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1831 if (! (*it
)->flags
.iconic
) (*it
)->iconify();
1834 screen
->updateStackingList();
1838 void BlackboxWindow::show(void) {
1839 flags
.visible
= True
;
1840 flags
.iconic
= False
;
1842 current_state
= (flags
.shaded
) ? IconicState
: NormalState
;
1843 setState(current_state
);
1845 XMapWindow(blackbox
->getXDisplay(), client
.window
);
1846 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
1847 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
1852 XTranslateCoordinates(blackbox
->getXDisplay(), client
.window
,
1853 screen
->getRootWindow(),
1854 0, 0, &real_x
, &real_y
, &child
);
1855 fprintf(stderr
, "%s -- assumed: (%d, %d), real: (%d, %d)\n", getTitle(),
1856 client
.rect
.left(), client
.rect
.top(), real_x
, real_y
);
1857 assert(client
.rect
.left() == real_x
&& client
.rect
.top() == real_y
);
1862 void BlackboxWindow::deiconify(bool reassoc
, bool raise
) {
1863 if (flags
.iconic
|| reassoc
)
1864 screen
->reassociateWindow(this, BSENTINEL
, False
);
1865 else if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID())
1870 // reassociate and deiconify all transients
1871 if (reassoc
&& client
.transientList
.size() > 0) {
1872 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1873 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1874 (*it
)->deiconify(True
, False
);
1878 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1882 void BlackboxWindow::close(void) {
1883 if (! (functions
& Func_Close
)) return;
1886 ce
.xclient
.type
= ClientMessage
;
1887 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1888 ce
.xclient
.display
= blackbox
->getXDisplay();
1889 ce
.xclient
.window
= client
.window
;
1890 ce
.xclient
.format
= 32;
1891 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_delete_window
);
1892 ce
.xclient
.data
.l
[1] = CurrentTime
;
1893 ce
.xclient
.data
.l
[2] = 0l;
1894 ce
.xclient
.data
.l
[3] = 0l;
1895 ce
.xclient
.data
.l
[4] = 0l;
1896 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
, NoEventMask
, &ce
);
1897 XFlush(blackbox
->getXDisplay());
1901 void BlackboxWindow::withdraw(void) {
1902 // We don't need to worry about resizing because resizing always grabs the X
1903 // server. This should only ever happen if using opaque moving.
1907 flags
.visible
= False
;
1908 flags
.iconic
= False
;
1910 setState(current_state
);
1912 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1914 XGrabServer(blackbox
->getXDisplay());
1916 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1917 StructureNotifyMask
;
1918 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1919 event_mask
& ~StructureNotifyMask
);
1920 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1921 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1923 XUngrabServer(blackbox
->getXDisplay());
1925 if (windowmenu
) windowmenu
->hide();
1929 void BlackboxWindow::maximize(unsigned int button
) {
1930 if (! (functions
& Func_Maximize
)) return;
1932 // We don't need to worry about resizing because resizing always grabs the X
1933 // server. This should only ever happen if using opaque moving.
1937 // handle case where menu is open then the max button is used instead
1938 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
1940 if (flags
.maximized
) {
1941 flags
.maximized
= 0;
1943 blackbox_attrib
.flags
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1944 blackbox_attrib
.attrib
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1947 when a resize finishes, maximize(0) is called to clear any maximization
1948 flags currently set. Otherwise it still thinks it is maximized.
1949 so we do not need to call configure() because resizing will handle it
1951 if (! flags
.resizing
)
1952 configure(blackbox_attrib
.premax_x
, blackbox_attrib
.premax_y
,
1953 blackbox_attrib
.premax_w
, blackbox_attrib
.premax_h
);
1955 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
1956 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
1958 redrawAllButtons(); // in case it is not called in configure()
1959 setState(current_state
);
1963 blackbox_attrib
.premax_x
= frame
.rect
.x();
1964 blackbox_attrib
.premax_y
= frame
.rect
.y();
1965 blackbox_attrib
.premax_w
= frame
.rect
.width();
1966 // use client.rect so that clients can be restored even if shaded
1967 blackbox_attrib
.premax_h
=
1968 client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
;
1971 if (screen
->isXineramaActive() && blackbox
->doXineramaMaximizing()) {
1972 // find the area to use
1973 RectList availableAreas
= screen
->allAvailableAreas();
1974 RectList::iterator it
, end
= availableAreas
.end();
1976 for (it
= availableAreas
.begin(); it
!= end
; ++it
)
1977 if (it
->intersects(frame
.rect
)) break;
1978 if (it
== end
) // the window isn't inside an area
1979 it
= availableAreas
.begin(); // so just default to the first one
1981 frame
.changing
= *it
;
1984 frame
.changing
= screen
->availableArea();
1988 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1989 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1993 blackbox_attrib
.flags
|= AttribMaxVert
;
1994 blackbox_attrib
.attrib
|= AttribMaxVert
;
1996 frame
.changing
.setX(frame
.rect
.x());
1997 frame
.changing
.setWidth(frame
.rect
.width());
2001 blackbox_attrib
.flags
|= AttribMaxHoriz
;
2002 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
2004 frame
.changing
.setY(frame
.rect
.y());
2005 frame
.changing
.setHeight(frame
.rect
.height());
2012 blackbox_attrib
.flags
^= AttribShaded
;
2013 blackbox_attrib
.attrib
^= AttribShaded
;
2014 flags
.shaded
= False
;
2017 flags
.maximized
= button
;
2019 configure(frame
.changing
.x(), frame
.changing
.y(),
2020 frame
.changing
.width(), frame
.changing
.height());
2022 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2023 redrawAllButtons(); // in case it is not called in configure()
2024 setState(current_state
);
2028 // re-maximizes the window to take into account availableArea changes
2029 void BlackboxWindow::remaximize(void) {
2031 // we only update the window's attributes otherwise we lose the shade bit
2032 switch(flags
.maximized
) {
2034 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
2035 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
2039 blackbox_attrib
.flags
|= AttribMaxVert
;
2040 blackbox_attrib
.attrib
|= AttribMaxVert
;
2044 blackbox_attrib
.flags
|= AttribMaxHoriz
;
2045 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
2051 // save the original dimensions because maximize will wipe them out
2052 int premax_x
= blackbox_attrib
.premax_x
,
2053 premax_y
= blackbox_attrib
.premax_y
,
2054 premax_w
= blackbox_attrib
.premax_w
,
2055 premax_h
= blackbox_attrib
.premax_h
;
2057 unsigned int button
= flags
.maximized
;
2058 flags
.maximized
= 0; // trick maximize() into working
2061 // restore saved values
2062 blackbox_attrib
.premax_x
= premax_x
;
2063 blackbox_attrib
.premax_y
= premax_y
;
2064 blackbox_attrib
.premax_w
= premax_w
;
2065 blackbox_attrib
.premax_h
= premax_h
;
2069 void BlackboxWindow::setWorkspace(unsigned int n
) {
2070 blackbox_attrib
.flags
|= AttribWorkspace
;
2071 blackbox_attrib
.workspace
= n
;
2072 if (n
== BSENTINEL
) { // iconified window
2074 we set the workspace to 'all workspaces' so that taskbars will show the
2075 window. otherwise, it made uniconifying a window imposible without the
2076 blackbox workspace menu
2080 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
, n
);
2084 void BlackboxWindow::shade(void) {
2086 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
2087 frame
.inside_w
, frame
.inside_h
);
2088 flags
.shaded
= False
;
2089 blackbox_attrib
.flags
^= AttribShaded
;
2090 blackbox_attrib
.attrib
^= AttribShaded
;
2092 setState(NormalState
);
2094 // set the frame rect to the normal size
2095 frame
.rect
.setHeight(client
.rect
.height() + frame
.margin
.top
+
2096 frame
.margin
.bottom
);
2098 if (! (decorations
& Decor_Titlebar
))
2099 return; // can't shade it without a titlebar!
2101 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
2102 frame
.inside_w
, frame
.title_h
);
2103 flags
.shaded
= True
;
2104 blackbox_attrib
.flags
|= AttribShaded
;
2105 blackbox_attrib
.attrib
|= AttribShaded
;
2107 setState(IconicState
);
2109 // set the frame rect to the shaded size
2110 frame
.rect
.setHeight(frame
.title_h
+ (frame
.border_w
* 2));
2116 * (Un)Sticks a window and its relatives.
2118 void BlackboxWindow::stick(void) {
2120 blackbox_attrib
.flags
^= AttribOmnipresent
;
2121 blackbox_attrib
.attrib
^= AttribOmnipresent
;
2123 flags
.stuck
= False
;
2125 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
2126 if (i
!= blackbox_attrib
.workspace
)
2127 screen
->getWorkspace(i
)->removeWindow(this, True
);
2130 screen
->reassociateWindow(this, BSENTINEL
, True
);
2131 // temporary fix since sticky windows suck. set the hint to what we
2132 // actually hold in our data.
2133 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
2134 blackbox_attrib
.workspace
);
2136 setState(current_state
);
2140 blackbox_attrib
.flags
|= AttribOmnipresent
;
2141 blackbox_attrib
.attrib
|= AttribOmnipresent
;
2143 // temporary fix since sticky windows suck. set the hint to a different
2144 // value than that contained in the class' data.
2145 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
2148 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
2149 if (i
!= blackbox_attrib
.workspace
)
2150 screen
->getWorkspace(i
)->addWindow(this, False
, True
);
2152 setState(current_state
);
2158 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
2159 client
.transient_for
->isStuck() != flags
.stuck
)
2160 client
.transient_for
->stick();
2161 // go down the chain
2162 BlackboxWindowList::iterator it
;
2163 const BlackboxWindowList::iterator end
= client
.transientList
.end();
2164 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
2165 if ((*it
)->isStuck() != flags
.stuck
)
2170 void BlackboxWindow::redrawWindowFrame(void) const {
2171 if (decorations
& Decor_Titlebar
) {
2172 if (flags
.focused
) {
2174 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2175 frame
.title
, frame
.ftitle
);
2177 XSetWindowBackground(blackbox
->getXDisplay(),
2178 frame
.title
, frame
.ftitle_pixel
);
2181 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2182 frame
.title
, frame
.utitle
);
2184 XSetWindowBackground(blackbox
->getXDisplay(),
2185 frame
.title
, frame
.utitle_pixel
);
2187 XClearWindow(blackbox
->getXDisplay(), frame
.title
);
2193 if (decorations
& Decor_Handle
) {
2194 if (flags
.focused
) {
2196 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2197 frame
.handle
, frame
.fhandle
);
2199 XSetWindowBackground(blackbox
->getXDisplay(),
2200 frame
.handle
, frame
.fhandle_pixel
);
2203 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2204 frame
.left_grip
, frame
.fgrip
);
2205 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2206 frame
.right_grip
, frame
.fgrip
);
2208 XSetWindowBackground(blackbox
->getXDisplay(),
2209 frame
.left_grip
, frame
.fgrip_pixel
);
2210 XSetWindowBackground(blackbox
->getXDisplay(),
2211 frame
.right_grip
, frame
.fgrip_pixel
);
2215 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2216 frame
.handle
, frame
.uhandle
);
2218 XSetWindowBackground(blackbox
->getXDisplay(),
2219 frame
.handle
, frame
.uhandle_pixel
);
2222 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2223 frame
.left_grip
, frame
.ugrip
);
2224 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2225 frame
.right_grip
, frame
.ugrip
);
2227 XSetWindowBackground(blackbox
->getXDisplay(),
2228 frame
.left_grip
, frame
.ugrip_pixel
);
2229 XSetWindowBackground(blackbox
->getXDisplay(),
2230 frame
.right_grip
, frame
.ugrip_pixel
);
2233 XClearWindow(blackbox
->getXDisplay(), frame
.handle
);
2234 XClearWindow(blackbox
->getXDisplay(), frame
.left_grip
);
2235 XClearWindow(blackbox
->getXDisplay(), frame
.right_grip
);
2238 if (decorations
& Decor_Border
) {
2240 XSetWindowBorder(blackbox
->getXDisplay(),
2241 frame
.plate
, frame
.fborder_pixel
);
2243 XSetWindowBorder(blackbox
->getXDisplay(),
2244 frame
.plate
, frame
.uborder_pixel
);
2249 void BlackboxWindow::setFocusFlag(bool focus
) {
2250 // only focus a window if it is visible
2251 if (focus
&& ! flags
.visible
)
2254 flags
.focused
= focus
;
2256 redrawWindowFrame();
2259 blackbox
->setFocusedWindow(this);
2261 if (! flags
.iconic
) {
2262 // iconic windows arent in a workspace menu!
2264 screen
->getCurrentWorkspace()->setFocused(this, isFocused());
2266 screen
->getWorkspace(blackbox_attrib
.workspace
)->
2267 setFocused(this, flags
.focused
);
2272 void BlackboxWindow::installColormap(bool install
) {
2273 int i
= 0, ncmap
= 0;
2274 Colormap
*cmaps
= XListInstalledColormaps(blackbox
->getXDisplay(),
2275 client
.window
, &ncmap
);
2277 XWindowAttributes wattrib
;
2278 if (XGetWindowAttributes(blackbox
->getXDisplay(),
2279 client
.window
, &wattrib
)) {
2281 // install the window's colormap
2282 for (i
= 0; i
< ncmap
; i
++) {
2283 if (*(cmaps
+ i
) == wattrib
.colormap
)
2284 // this window is using an installed color map... do not install
2287 // otherwise, install the window's colormap
2289 XInstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2291 // uninstall the window's colormap
2292 for (i
= 0; i
< ncmap
; i
++) {
2293 if (*(cmaps
+ i
) == wattrib
.colormap
)
2294 // we found the colormap to uninstall
2295 XUninstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2305 void BlackboxWindow::setAllowedActions(void) {
2309 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_shade
);
2310 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_change_desktop
);
2311 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_close
);
2313 if (functions
& Func_Move
)
2314 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_move
);
2315 if (functions
& Func_Resize
)
2316 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_resize
);
2317 if (functions
& Func_Maximize
) {
2318 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_horz
);
2319 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_vert
);
2322 xatom
->setValue(client
.window
, XAtom::net_wm_allowed_actions
, XAtom::atom
,
2327 void BlackboxWindow::setState(unsigned long new_state
) {
2328 current_state
= new_state
;
2330 unsigned long state
[2];
2331 state
[0] = current_state
;
2333 xatom
->setValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
, state
, 2);
2335 xatom
->setValue(client
.window
, XAtom::blackbox_attributes
,
2336 XAtom::blackbox_attributes
, (unsigned long *)&blackbox_attrib
,
2337 PropBlackboxAttributesElements
);
2342 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_modal
);
2344 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_shaded
);
2346 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_hidden
);
2347 if (flags
.skip_taskbar
)
2348 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
);
2349 if (flags
.skip_pager
)
2350 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_pager
);
2351 if (flags
.fullscreen
)
2352 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_fullscreen
);
2353 if (flags
.maximized
== 1 || flags
.maximized
== 2)
2354 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_vert
);
2355 if (flags
.maximized
== 1 || flags
.maximized
== 3)
2356 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_horz
);
2357 xatom
->setValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
2362 bool BlackboxWindow::getState(void) {
2363 bool ret
= xatom
->getValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
,
2365 if (! ret
) current_state
= 0;
2370 void BlackboxWindow::restoreAttributes(void) {
2371 unsigned long num
= PropBlackboxAttributesElements
;
2372 BlackboxAttributes
*net
;
2373 if (! xatom
->getValue(client
.window
, XAtom::blackbox_attributes
,
2374 XAtom::blackbox_attributes
, num
,
2375 (unsigned long **)&net
))
2377 if (num
< PropBlackboxAttributesElements
) {
2382 if (net
->flags
& AttribShaded
&& net
->attrib
& AttribShaded
) {
2383 flags
.shaded
= False
;
2384 unsigned long orig_state
= current_state
;
2388 At this point in the life of a window, current_state should only be set
2389 to IconicState if the window was an *icon*, not if it was shaded.
2391 if (orig_state
!= IconicState
)
2392 current_state
= WithdrawnState
;
2395 if (net
->workspace
!= screen
->getCurrentWorkspaceID() &&
2396 net
->workspace
< screen
->getWorkspaceCount())
2397 screen
->reassociateWindow(this, net
->workspace
, True
);
2399 if ((blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID()) &&
2400 (blackbox_attrib
.workspace
< screen
->getWorkspaceCount())) {
2401 // set to WithdrawnState so it will be mapped on the new workspace
2402 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2403 } else if (current_state
== WithdrawnState
) {
2404 // the window is on this workspace and is Withdrawn, so it is waiting to
2406 current_state
= NormalState
;
2409 if (net
->flags
& AttribOmnipresent
&& net
->attrib
& AttribOmnipresent
&&
2413 // if the window was on another workspace, it was going to be hidden. this
2414 // specifies that the window should be mapped since it is sticky.
2415 if (current_state
== WithdrawnState
) current_state
= NormalState
;
2418 if (net
->flags
& AttribMaxHoriz
|| net
->flags
& AttribMaxVert
) {
2419 int x
= net
->premax_x
, y
= net
->premax_y
;
2420 unsigned int w
= net
->premax_w
, h
= net
->premax_h
;
2421 flags
.maximized
= 0;
2424 if ((net
->flags
& AttribMaxHoriz
) &&
2425 (net
->flags
& AttribMaxVert
))
2426 m
= (net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
2427 else if (net
->flags
& AttribMaxVert
)
2428 m
= (net
->attrib
& AttribMaxVert
) ? 2 : 0;
2429 else if (net
->flags
& AttribMaxHoriz
)
2430 m
= (net
->attrib
& AttribMaxHoriz
) ? 3 : 0;
2434 blackbox_attrib
.premax_x
= x
;
2435 blackbox_attrib
.premax_y
= y
;
2436 blackbox_attrib
.premax_w
= w
;
2437 blackbox_attrib
.premax_h
= h
;
2440 if (net
->flags
& AttribDecoration
) {
2441 switch (net
->decoration
) {
2446 /* since tools only let you toggle this anyways, we'll just make that all
2447 it supports for now.
2458 // with the state set it will then be the map event's job to read the
2459 // window's state and behave accordingly
2466 * Positions the Rect r according the the client window position and
2469 void BlackboxWindow::applyGravity(Rect
&r
) {
2470 // apply horizontal window gravity
2471 switch (client
.win_gravity
) {
2473 case NorthWestGravity
:
2474 case SouthWestGravity
:
2476 r
.setX(client
.rect
.x());
2482 r
.setX(client
.rect
.x() - (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2485 case NorthEastGravity
:
2486 case SouthEastGravity
:
2488 r
.setX(client
.rect
.x() - frame
.margin
.left
- frame
.margin
.right
+ 2);
2493 r
.setX(client
.rect
.x() - frame
.margin
.left
);
2497 // apply vertical window gravity
2498 switch (client
.win_gravity
) {
2500 case NorthWestGravity
:
2501 case NorthEastGravity
:
2503 r
.setY(client
.rect
.y());
2509 r
.setY(client
.rect
.y() - (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2512 case SouthWestGravity
:
2513 case SouthEastGravity
:
2515 r
.setY(client
.rect
.y() - frame
.margin
.top
- frame
.margin
.bottom
+ 2);
2520 r
.setY(client
.rect
.y() - frame
.margin
.top
);
2527 * The reverse of the applyGravity function.
2529 * Positions the Rect r according to the frame window position and
2532 void BlackboxWindow::restoreGravity(Rect
&r
) {
2533 // restore horizontal window gravity
2534 switch (client
.win_gravity
) {
2536 case NorthWestGravity
:
2537 case SouthWestGravity
:
2539 r
.setX(frame
.rect
.x());
2545 r
.setX(frame
.rect
.x() + (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2548 case NorthEastGravity
:
2549 case SouthEastGravity
:
2551 r
.setX(frame
.rect
.x() + frame
.margin
.left
+ frame
.margin
.right
- 2);
2556 r
.setX(frame
.rect
.x() + frame
.margin
.left
);
2560 // restore vertical window gravity
2561 switch (client
.win_gravity
) {
2563 case NorthWestGravity
:
2564 case NorthEastGravity
:
2566 r
.setY(frame
.rect
.y());
2572 r
.setY(frame
.rect
.y() + (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2575 case SouthWestGravity
:
2576 case SouthEastGravity
:
2578 r
.setY(frame
.rect
.y() + frame
.margin
.top
+ frame
.margin
.bottom
- 2);
2583 r
.setY(frame
.rect
.y() + frame
.margin
.top
);
2589 void BlackboxWindow::redrawLabel(void) const {
2590 if (flags
.focused
) {
2592 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2593 frame
.label
, frame
.flabel
);
2595 XSetWindowBackground(blackbox
->getXDisplay(),
2596 frame
.label
, frame
.flabel_pixel
);
2599 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2600 frame
.label
, frame
.ulabel
);
2602 XSetWindowBackground(blackbox
->getXDisplay(),
2603 frame
.label
, frame
.ulabel_pixel
);
2605 XClearWindow(blackbox
->getXDisplay(), frame
.label
);
2607 WindowStyle
*style
= screen
->getWindowStyle();
2609 int pos
= frame
.bevel_w
* 2;
2610 style
->doJustify(client
.title
.c_str(), pos
, frame
.label_w
, frame
.bevel_w
* 4);
2611 style
->font
->drawString(frame
.label
, pos
, 1,
2612 (flags
.focused
? style
->l_text_focus
:
2613 style
->l_text_unfocus
),
2618 void BlackboxWindow::redrawAllButtons(void) const {
2619 if (frame
.iconify_button
) redrawIconifyButton(False
);
2620 if (frame
.maximize_button
) redrawMaximizeButton(flags
.maximized
);
2621 if (frame
.close_button
) redrawCloseButton(False
);
2622 if (frame
.stick_button
) redrawStickyButton(flags
.stuck
);
2626 void BlackboxWindow::redrawButton(bool pressed
, Window win
,
2627 Pixmap fppix
, unsigned long fppixel
,
2628 Pixmap uppix
, unsigned long uppixel
,
2629 Pixmap fpix
, unsigned long fpixel
,
2630 Pixmap upix
, unsigned long upixel
) const {
2635 if (flags
.focused
) {
2643 if (flags
.focused
) {
2653 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), win
, p
);
2655 XSetWindowBackground(blackbox
->getXDisplay(), win
, pix
);
2659 void BlackboxWindow::redrawIconifyButton(bool pressed
) const {
2660 redrawButton(pressed
, frame
.iconify_button
,
2661 frame
.pfbutton
, frame
.pfbutton_pixel
,
2662 frame
.pubutton
, frame
.pubutton_pixel
,
2663 frame
.fbutton
, frame
.fbutton_pixel
,
2664 frame
.ubutton
, frame
.ubutton_pixel
);
2666 XClearWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
2667 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2668 screen
->getWindowStyle()->b_pic_unfocus
);
2670 #ifdef BITMAPBUTTONS
2671 PixmapMask pm
= screen
->getWindowStyle()->icon_button
;
2673 if (screen
->getWindowStyle()->icon_button
.mask
!= None
) {
2674 XSetClipMask(blackbox
->getXDisplay(), pen
.gc(), pm
.mask
);
2675 XSetClipOrigin(blackbox
->getXDisplay(), pen
.gc(),
2676 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2);
2678 XFillRectangle(blackbox
->getXDisplay(), frame
.iconify_button
, pen
.gc(),
2679 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2,
2680 (frame
.button_w
+ pm
.w
)/2, (frame
.button_w
+ pm
.h
)/2);
2682 XSetClipMask(blackbox
->getXDisplay(), pen
.gc(), None
);
2683 XSetClipOrigin(blackbox
->getXDisplay(), pen
.gc(), 0, 0);
2685 #endif // BITMAPBUTTONS
2686 XDrawRectangle(blackbox
->getXDisplay(), frame
.iconify_button
, pen
.gc(),
2687 2, (frame
.button_w
- 5), (frame
.button_w
- 5), 2);
2688 #ifdef BITMAPBUTTONS
2690 #endif // BITMAPBUTTONS
2694 void BlackboxWindow::redrawMaximizeButton(bool pressed
) const {
2695 redrawButton(pressed
, frame
.maximize_button
,
2696 frame
.pfbutton
, frame
.pfbutton_pixel
,
2697 frame
.pubutton
, frame
.pubutton_pixel
,
2698 frame
.fbutton
, frame
.fbutton_pixel
,
2699 frame
.ubutton
, frame
.ubutton_pixel
);
2701 XClearWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
2703 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2704 screen
->getWindowStyle()->b_pic_unfocus
);
2706 #ifdef BITMAPBUTTONS
2707 PixmapMask pm
= screen
->getWindowStyle()->max_button
;
2709 if (pm
.mask
!= None
) {
2710 XSetClipMask(blackbox
->getXDisplay(), pen
.gc(), pm
.mask
);
2711 XSetClipOrigin(blackbox
->getXDisplay(), pen
.gc(),
2712 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2);
2714 XFillRectangle(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2715 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2,
2716 (frame
.button_w
+ pm
.w
)/2, (frame
.button_w
+ pm
.h
)/2);
2718 XSetClipOrigin(blackbox
->getXDisplay(), pen
.gc(), 0, 0 );
2719 XSetClipMask( blackbox
->getXDisplay(), pen
.gc(), None
);
2721 #endif // BITMAPBUTTONS
2722 XDrawRectangle(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2723 2, 2, (frame
.button_w
- 5), (frame
.button_w
- 5));
2724 XDrawLine(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2725 2, 3, (frame
.button_w
- 3), 3);
2726 #ifdef BITMAPBUTTONS
2728 #endif // BITMAPBUTTONS
2732 void BlackboxWindow::redrawCloseButton(bool pressed
) const {
2733 redrawButton(pressed
, frame
.close_button
,
2734 frame
.pfbutton
, frame
.pfbutton_pixel
,
2735 frame
.pubutton
, frame
.pubutton_pixel
,
2736 frame
.fbutton
, frame
.fbutton_pixel
,
2737 frame
.ubutton
, frame
.ubutton_pixel
);
2739 XClearWindow(blackbox
->getXDisplay(), frame
.close_button
);
2741 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2742 screen
->getWindowStyle()->b_pic_unfocus
);
2744 #ifdef BITMAPBUTTONS
2745 PixmapMask pm
= screen
->getWindowStyle()->close_button
;
2747 if (pm
.mask
!= None
) {
2748 XSetClipMask(blackbox
->getXDisplay(), pen
.gc(), pm
.mask
);
2749 XSetClipOrigin(blackbox
->getXDisplay(), pen
.gc(),
2750 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2);
2752 XFillRectangle(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2753 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2,
2754 (frame
.button_w
+ pm
.w
)/2, (frame
.button_w
+ pm
.h
)/2);
2757 XSetClipOrigin(blackbox
->getXDisplay(), pen
.gc(), 0, 0 );
2758 XSetClipMask( blackbox
->getXDisplay(), pen
.gc(), None
);
2760 #endif // BITMAPBUTTONS
2761 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2762 2, 2, (frame
.button_w
- 3), (frame
.button_w
- 3));
2763 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2764 2, (frame
.button_w
- 3), (frame
.button_w
- 3), 2);
2765 #ifdef BITMAPBUTTONS
2767 #endif // BITMAPBUTTONS
2770 void BlackboxWindow::redrawStickyButton(bool pressed
) const {
2771 redrawButton(pressed
, frame
.stick_button
,
2772 frame
.pfbutton
, frame
.pfbutton_pixel
,
2773 frame
.pubutton
, frame
.pubutton_pixel
,
2774 frame
.fbutton
, frame
.fbutton_pixel
,
2775 frame
.ubutton
, frame
.ubutton_pixel
);
2777 XClearWindow(blackbox
->getXDisplay(), frame
.stick_button
);
2779 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2780 screen
->getWindowStyle()->b_pic_unfocus
);
2782 #ifdef BITMAPBUTTONS
2783 PixmapMask pm
= screen
->getWindowStyle()->stick_button
;
2785 if (pm
.mask
!= None
) {
2786 XSetClipMask(blackbox
->getXDisplay(), pen
.gc(), pm
.mask
);
2787 XSetClipOrigin(blackbox
->getXDisplay(), pen
.gc(),
2788 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2);
2790 XFillRectangle(blackbox
->getXDisplay(), frame
.stick_button
, pen
.gc(),
2791 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2,
2792 (frame
.button_w
+ pm
.w
)/2, (frame
.button_w
+ pm
.h
)/2);
2795 XSetClipOrigin(blackbox
->getXDisplay(), pen
.gc(), 0, 0 );
2796 XSetClipMask( blackbox
->getXDisplay(), pen
.gc(), None
);
2798 #endif // BITMAPBUTTONS
2799 XFillRectangle(blackbox
->getXDisplay(), frame
.stick_button
, pen
.gc(),
2800 frame
.button_w
/2 - 1, frame
.button_w
/2 -1, 2, 2 );
2801 #ifdef BITMAPBUTTONS
2806 void BlackboxWindow::mapRequestEvent(const XMapRequestEvent
*re
) {
2807 if (re
->window
!= client
.window
)
2811 fprintf(stderr
, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2816 Even though the window wants to be shown, if it is not on the current
2817 workspace, then it isn't going to be shown right now.
2819 if (! flags
.stuck
&&
2820 blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID() &&
2821 blackbox_attrib
.workspace
< screen
->getWorkspaceCount())
2822 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2824 switch (current_state
) {
2829 case WithdrawnState
:
2838 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2840 if (! blackbox
->isStartup()) {
2841 XSync(blackbox
->getXDisplay(), False
); // make sure the frame is mapped
2842 if (screen
->doFocusNew() || (isTransient() && getTransientFor() &&
2843 getTransientFor()->isFocused())) {
2846 if (screen
->getPlacementPolicy() == BScreen::ClickMousePlacement
) {
2850 XQueryPointer(blackbox
->getXDisplay(), screen
->getRootWindow(),
2851 &r
, &c
, &rx
, &ry
, &x
, &y
, &m
);
2861 void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent
*ue
) {
2862 if (ue
->window
!= client
.window
)
2866 fprintf(stderr
, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2870 screen
->unmanageWindow(this, False
);
2874 void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent
*de
) {
2875 if (de
->window
!= client
.window
)
2879 fprintf(stderr
, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2883 screen
->unmanageWindow(this, False
);
2887 void BlackboxWindow::reparentNotifyEvent(const XReparentEvent
*re
) {
2888 if (re
->window
!= client
.window
|| re
->parent
== frame
.plate
)
2892 fprintf(stderr
, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2893 "0x%lx.\n", client
.window
, re
->parent
);
2898 XPutBackEvent(blackbox
->getXDisplay(), &ev
);
2899 screen
->unmanageWindow(this, True
);
2903 void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent
*pe
) {
2904 if (pe
->state
== PropertyDelete
|| ! validateClient())
2908 fprintf(stderr
, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n",
2914 case XA_WM_CLIENT_MACHINE
:
2918 case XA_WM_TRANSIENT_FOR
: {
2919 bool s
= flags
.stuck
;
2921 // determine if this is a transient window
2924 if (flags
.stuck
!= s
) stick();
2926 // adjust the window decorations based on transience
2927 if (isTransient()) {
2928 functions
&= ~Func_Maximize
;
2929 setAllowedActions();
2941 case XA_WM_ICON_NAME
:
2943 if (flags
.iconic
) screen
->propagateWindowName(this);
2946 case XAtom::net_wm_name
:
2950 if (decorations
& Decor_Titlebar
)
2953 screen
->propagateWindowName(this);
2956 case XA_WM_NORMAL_HINTS
: {
2959 if ((client
.normal_hint_flags
& PMinSize
) &&
2960 (client
.normal_hint_flags
& PMaxSize
)) {
2961 // the window now can/can't resize itself, so the buttons need to be
2964 if (client
.max_width
<= client
.min_width
&&
2965 client
.max_height
<= client
.min_height
) {
2966 functions
&= ~(Func_Resize
| Func_Maximize
);
2968 if (! isTransient())
2969 functions
|= Func_Maximize
;
2970 functions
|= Func_Resize
;
2973 setAllowedActions();
2977 Rect old_rect
= frame
.rect
;
2981 if (old_rect
!= frame
.rect
)
2988 if (pe
->atom
== xatom
->getAtom(XAtom::wm_protocols
)) {
2991 if ((decorations
& Decor_Close
) && (! frame
.close_button
)) {
2992 createCloseButton();
2993 if (decorations
& Decor_Titlebar
) {
2994 positionButtons(True
);
2995 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
2997 if (windowmenu
) windowmenu
->reconfigure();
2999 } else if (pe
->atom
== xatom
->getAtom(XAtom::net_wm_strut
)) {
3008 void BlackboxWindow::exposeEvent(const XExposeEvent
*ee
) {
3010 fprintf(stderr
, "BlackboxWindow::exposeEvent() for 0x%lx\n", client
.window
);
3013 if (frame
.label
== ee
->window
&& (decorations
& Decor_Titlebar
))
3015 else if (frame
.close_button
== ee
->window
)
3016 redrawCloseButton(False
);
3017 else if (frame
.maximize_button
== ee
->window
)
3018 redrawMaximizeButton(flags
.maximized
);
3019 else if (frame
.iconify_button
== ee
->window
)
3020 redrawIconifyButton(False
);
3021 else if (frame
.stick_button
== ee
->window
)
3022 redrawStickyButton(flags
.stuck
);
3026 void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent
*cr
) {
3027 if (cr
->window
!= client
.window
|| flags
.iconic
)
3030 if (cr
->value_mask
& CWBorderWidth
)
3031 client
.old_bw
= cr
->border_width
;
3033 if (cr
->value_mask
& (CWX
| CWY
| CWWidth
| CWHeight
)) {
3034 frame
.changing
= frame
.rect
;
3036 if (cr
->value_mask
& (CWX
| CWY
)) {
3037 if (cr
->value_mask
& CWX
)
3038 client
.rect
.setX(cr
->x
);
3039 if (cr
->value_mask
& CWY
)
3040 client
.rect
.setY(cr
->y
);
3042 applyGravity(frame
.changing
);
3045 if (cr
->value_mask
& (CWWidth
| CWHeight
)) {
3046 if (cr
->value_mask
& CWWidth
)
3047 frame
.changing
.setWidth(cr
->width
+
3048 frame
.margin
.left
+ frame
.margin
.right
);
3050 if (cr
->value_mask
& CWHeight
)
3051 frame
.changing
.setHeight(cr
->height
+
3052 frame
.margin
.top
+ frame
.margin
.bottom
);
3055 if a position change has been specified, then that position will be
3056 used instead of determining a position based on the window's gravity.
3058 if (! (cr
->value_mask
& (CWX
| CWY
))) {
3060 switch (client
.win_gravity
) {
3061 case NorthEastGravity
:
3065 case SouthWestGravity
:
3067 corner
= BottomLeft
;
3069 case SouthEastGravity
:
3070 corner
= BottomRight
;
3072 default: // NorthWest, Static, etc
3079 configure(frame
.changing
.x(), frame
.changing
.y(),
3080 frame
.changing
.width(), frame
.changing
.height());
3083 if (cr
->value_mask
& CWStackMode
&& !isDesktop()) {
3084 switch (cr
->detail
) {
3087 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
3093 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3100 void BlackboxWindow::buttonPressEvent(const XButtonEvent
*be
) {
3102 fprintf(stderr
, "BlackboxWindow::buttonPressEvent() for 0x%lx\n",
3106 if (frame
.maximize_button
== be
->window
&& be
->button
<= 3) {
3107 redrawMaximizeButton(True
);
3108 } else if (be
->button
== 1 || (be
->button
== 3 && be
->state
== mod_mask
)) {
3109 if (! flags
.focused
)
3112 if (frame
.iconify_button
== be
->window
) {
3113 redrawIconifyButton(True
);
3114 } else if (frame
.close_button
== be
->window
) {
3115 redrawCloseButton(True
);
3116 } else if (frame
.stick_button
== be
->window
) {
3117 redrawStickyButton(True
);
3118 } else if (frame
.plate
== be
->window
) {
3119 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
3121 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3123 XAllowEvents(blackbox
->getXDisplay(), ReplayPointer
, be
->time
);
3125 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
3126 if (((be
->time
- lastButtonPressTime
) <=
3127 blackbox
->getDoubleClickInterval()) ||
3128 (be
->state
== ControlMask
)) {
3129 lastButtonPressTime
= 0;
3132 lastButtonPressTime
= be
->time
;
3136 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
3138 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3140 } else if (be
->button
== 2 && (be
->window
!= frame
.iconify_button
) &&
3141 (be
->window
!= frame
.close_button
) &&
3142 (be
->window
!= frame
.stick_button
)) {
3143 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
3144 } else if (windowmenu
&& be
->button
== 3 &&
3145 (frame
.title
== be
->window
|| frame
.label
== be
->window
||
3146 frame
.handle
== be
->window
|| frame
.window
== be
->window
)) {
3147 if (windowmenu
->isVisible()) {
3150 int mx
= be
->x_root
- windowmenu
->getWidth() / 2,
3151 my
= be
->y_root
- windowmenu
->getHeight() / 2;
3153 // snap the window menu into a corner/side if necessary
3154 int left_edge
, right_edge
, top_edge
, bottom_edge
;
3157 the " + (frame.border_w * 2) - 1" bits are to get the proper width
3158 and height of the menu, as the sizes returned by it do not include
3161 left_edge
= frame
.rect
.x();
3162 right_edge
= frame
.rect
.right() -
3163 (windowmenu
->getWidth() + (frame
.border_w
* 2) - 1);
3164 top_edge
= client
.rect
.top() - (frame
.border_w
+ frame
.mwm_border_w
);
3165 bottom_edge
= client
.rect
.bottom() -
3166 (windowmenu
->getHeight() + (frame
.border_w
* 2) - 1) +
3167 (frame
.border_w
+ frame
.mwm_border_w
);
3171 else if (mx
> right_edge
)
3175 else if (my
> bottom_edge
)
3178 if (my
+ windowmenu
->getHeight() > screen
->getHeight())
3179 my
= screen
->getHeight() - windowmenu
->getHeight() -
3180 (screen
->getBorderWidth() * 2);
3182 windowmenu
->move(mx
, my
);
3184 XRaiseWindow(blackbox
->getXDisplay(), windowmenu
->getWindowID());
3185 XRaiseWindow(blackbox
->getXDisplay(),
3186 windowmenu
->getSendToMenu()->getWindowID());
3189 } else if (be
->button
== 4) {
3190 if ((be
->window
== frame
.label
||
3191 be
->window
== frame
.title
||
3192 be
->window
== frame
.maximize_button
||
3193 be
->window
== frame
.iconify_button
||
3194 be
->window
== frame
.close_button
||
3195 be
->window
== frame
.stick_button
) &&
3199 } else if (be
->button
== 5) {
3200 if ((be
->window
== frame
.label
||
3201 be
->window
== frame
.title
||
3202 be
->window
== frame
.maximize_button
||
3203 be
->window
== frame
.iconify_button
||
3204 be
->window
== frame
.close_button
||
3205 be
->window
== frame
.stick_button
) &&
3212 void BlackboxWindow::buttonReleaseEvent(const XButtonEvent
*re
) {
3214 fprintf(stderr
, "BlackboxWindow::buttonReleaseEvent() for 0x%lx\n",
3218 if (re
->window
== frame
.maximize_button
&&
3219 re
->button
>= 1 && re
->button
<= 3) {
3220 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3221 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
3222 maximize(re
->button
);
3224 redrawMaximizeButton(flags
.maximized
);
3226 } else if (re
->window
== frame
.iconify_button
&& re
->button
== 1) {
3227 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3228 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
3231 redrawIconifyButton(False
);
3233 } else if (re
->window
== frame
.stick_button
&& re
->button
== 1) {
3234 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3235 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
3238 redrawStickyButton(False
);
3240 } else if (re
->window
== frame
.close_button
& re
->button
== 1) {
3241 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3242 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
)))
3244 redrawCloseButton(False
);
3245 } else if (flags
.moving
) {
3247 } else if (flags
.resizing
) {
3249 } else if (re
->window
== frame
.window
) {
3250 if (re
->button
== 2 && re
->state
== mod_mask
)
3251 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3257 void BlackboxWindow::beginMove(int x_root
, int y_root
) {
3258 if (! (functions
& Func_Move
)) return;
3260 assert(! (flags
.resizing
|| flags
.moving
));
3263 Only one window can be moved/resized at a time. If another window is already
3264 being moved or resized, then stop it before whating to work with this one.
3266 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3267 if (changing
&& changing
!= this) {
3268 if (changing
->flags
.moving
)
3269 changing
->endMove();
3270 else // if (changing->flags.resizing)
3271 changing
->endResize();
3274 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3275 PointerMotionMask
| ButtonReleaseMask
,
3276 GrabModeAsync
, GrabModeAsync
,
3277 None
, blackbox
->getMoveCursor(), CurrentTime
);
3279 if (windowmenu
&& windowmenu
->isVisible())
3282 flags
.moving
= True
;
3283 blackbox
->setChangingWindow(this);
3285 if (! screen
->doOpaqueMove()) {
3286 XGrabServer(blackbox
->getXDisplay());
3288 frame
.changing
= frame
.rect
;
3289 screen
->showPosition(frame
.changing
.x(), frame
.changing
.y());
3291 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3295 frame
.changing
.width() - 1,
3296 frame
.changing
.height() - 1);
3299 frame
.grab_x
= x_root
- frame
.rect
.x() - frame
.border_w
;
3300 frame
.grab_y
= y_root
- frame
.rect
.y() - frame
.border_w
;
3304 void BlackboxWindow::doMove(int x_root
, int y_root
) {
3305 assert(flags
.moving
);
3306 assert(blackbox
->getChangingWindow() == this);
3308 int dx
= x_root
- frame
.grab_x
, dy
= y_root
- frame
.grab_y
;
3309 dx
-= frame
.border_w
;
3310 dy
-= frame
.border_w
;
3312 doWindowSnapping(dx
, dy
);
3314 if (screen
->doOpaqueMove()) {
3315 if (screen
->doWorkspaceWarping())
3316 doWorkspaceWarping(x_root
, y_root
, dx
);
3318 configure(dx
, dy
, frame
.rect
.width(), frame
.rect
.height());
3320 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3324 frame
.changing
.width() - 1,
3325 frame
.changing
.height() - 1);
3327 if (screen
->doWorkspaceWarping())
3328 doWorkspaceWarping(x_root
, y_root
, dx
);
3330 frame
.changing
.setPos(dx
, dy
);
3332 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3336 frame
.changing
.width() - 1,
3337 frame
.changing
.height() - 1);
3340 screen
->showPosition(dx
, dy
);
3344 void BlackboxWindow::doWorkspaceWarping(int x_root
, int y_root
, int &dx
) {
3345 // workspace warping
3347 unsigned int dest
= screen
->getCurrentWorkspaceID();
3351 if (dest
> 0) dest
--;
3352 else dest
= screen
->getNumberOfWorkspaces() - 1;
3354 } else if (x_root
>= screen
->getRect().right()) {
3357 if (dest
< screen
->getNumberOfWorkspaces() - 1) dest
++;
3363 bool focus
= flags
.focused
; // had focus while moving?
3365 int dest_x
= x_root
;
3367 dest_x
+= screen
->getRect().width() - 1;
3368 dx
+= screen
->getRect().width() - 1;
3370 dest_x
-= screen
->getRect().width() - 1;
3371 dx
-= screen
->getRect().width() - 1;
3375 screen
->reassociateWindow(this, dest
, False
);
3376 screen
->changeWorkspaceID(dest
);
3378 if (screen
->doOpaqueMove())
3379 XGrabServer(blackbox
->getXDisplay());
3381 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3382 XWarpPointer(blackbox
->getXDisplay(), None
,
3383 screen
->getRootWindow(), 0, 0, 0, 0,
3385 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3386 PointerMotionMask
| ButtonReleaseMask
,
3387 GrabModeAsync
, GrabModeAsync
,
3388 None
, blackbox
->getMoveCursor(), CurrentTime
);
3390 if (screen
->doOpaqueMove())
3391 XUngrabServer(blackbox
->getXDisplay());
3399 void BlackboxWindow::doWindowSnapping(int &dx
, int &dy
) {
3400 // how much resistance to edges to provide
3401 const int resistance_size
= screen
->getResistanceSize();
3403 // how far away to snap
3404 const int snap_distance
= screen
->getSnapThreshold();
3406 // how to snap windows
3407 const int snap_to_windows
= screen
->getWindowToWindowSnap();
3408 const int snap_to_edges
= screen
->getWindowToEdgeSnap();
3409 // the amount of space away from the edge to provide resistance/snap
3410 const int snap_offset
= screen
->getSnapOffset();
3412 // find the geomeetery where the moving window currently is
3413 const Rect
&moving
= screen
->doOpaqueMove() ? frame
.rect
: frame
.changing
;
3416 const int wleft
= dx
,
3417 wright
= dx
+ frame
.rect
.width() - 1,
3419 wbottom
= dy
+ frame
.rect
.height() - 1;
3421 if (snap_to_windows
) {
3424 Workspace
*w
= screen
->getWorkspace(getWorkspaceNumber());
3427 // add windows on the workspace to the rect list
3428 const BlackboxWindowList
& stack_list
= w
->getStackingList();
3429 BlackboxWindowList::const_iterator st_it
, st_end
= stack_list
.end();
3430 for (st_it
= stack_list
.begin(); st_it
!= st_end
; ++st_it
)
3431 if (*st_it
!= this) // don't snap to ourself
3432 rectlist
.push_back( (*st_it
)->frameRect() );
3434 // add the toolbar and the slit to the rect list.
3435 // (only if they are not hidden)
3436 Toolbar
*tbar
= screen
->getToolbar();
3437 Slit
*slit
= screen
->getSlit();
3438 Rect tbar_rect
, slit_rect
;
3439 unsigned int bwidth
= screen
->getBorderWidth() * 2;
3441 if (! (screen
->doHideToolbar() || tbar
->isHidden())) {
3442 tbar_rect
.setRect(tbar
->getX(), tbar
->getY(), tbar
->getWidth() + bwidth
,
3443 tbar
->getHeight() + bwidth
);
3444 rectlist
.push_back(tbar_rect
);
3447 if (! slit
->isHidden()) {
3448 slit_rect
.setRect(slit
->getX(), slit
->getY(), slit
->getWidth() + bwidth
,
3449 slit
->getHeight() + bwidth
);
3450 rectlist
.push_back(slit_rect
);
3453 RectList::const_iterator it
, end
= rectlist
.end();
3454 for (it
= rectlist
.begin(); it
!= end
; ++it
) {
3455 bool snapped
= False
;
3456 const Rect
&winrect
= *it
;
3458 offsetrect
.setCoords(winrect
.left() - snap_offset
,
3459 winrect
.top() - snap_offset
,
3460 winrect
.right() + snap_offset
,
3461 winrect
.bottom() + snap_offset
);
3463 if (snap_to_windows
== BScreen::WindowResistance
)
3464 // if the window is already over top of this snap target, then
3465 // resistance is futile, so just ignore it
3466 if (winrect
.intersects(moving
))
3469 int dleft
, dright
, dtop
, dbottom
;
3471 // if the windows are in the same plane vertically
3472 if (wtop
>= (signed)(winrect
.y() - frame
.rect
.height() + 1) &&
3473 wtop
< (signed)(winrect
.y() + winrect
.height() - 1)) {
3475 if (snap_to_windows
== BScreen::WindowResistance
) {
3476 dleft
= wright
- offsetrect
.left();
3477 dright
= offsetrect
.right() - wleft
;
3479 // snap left of other window?
3480 if (dleft
>= 0 && dleft
< resistance_size
&&
3481 dleft
< (wright
- wleft
)) {
3482 dx
= offsetrect
.left() - frame
.rect
.width();
3485 // snap right of other window?
3486 else if (dright
>= 0 && dright
< resistance_size
&&
3487 dright
< (wright
- wleft
)) {
3488 dx
= offsetrect
.right() + 1;
3491 } else { // BScreen::WindowSnap
3492 dleft
= abs(wright
- offsetrect
.left());
3493 dright
= abs(wleft
- offsetrect
.right());
3495 // snap left of other window?
3496 if (dleft
< snap_distance
&& dleft
<= dright
) {
3497 dx
= offsetrect
.left() - frame
.rect
.width();
3500 // snap right of other window?
3501 else if (dright
< snap_distance
) {
3502 dx
= offsetrect
.right() + 1;
3508 if (screen
->getWindowCornerSnap()) {
3509 // try corner-snap to its other sides
3510 if (snap_to_windows
== BScreen::WindowResistance
) {
3511 dtop
= winrect
.top() - wtop
;
3512 dbottom
= wbottom
- winrect
.bottom();
3513 if (dtop
> 0 && dtop
< resistance_size
) {
3514 // if we're already past the top edge, then don't provide
3516 if (moving
.top() >= winrect
.top())
3518 } else if (dbottom
> 0 && dbottom
< resistance_size
) {
3519 // if we're already past the bottom edge, then don't provide
3521 if (moving
.bottom() <= winrect
.bottom())
3522 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
3524 } else { // BScreen::WindowSnap
3525 dtop
= abs(wtop
- winrect
.top());
3526 dbottom
= abs(wbottom
- winrect
.bottom());
3527 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3529 else if (dbottom
< snap_distance
)
3530 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
3538 // if the windows are on the same plane horizontally
3539 if (wleft
>= (signed)(winrect
.x() - frame
.rect
.width() + 1) &&
3540 wleft
< (signed)(winrect
.x() + winrect
.width() - 1)) {
3542 if (snap_to_windows
== BScreen::WindowResistance
) {
3543 dtop
= wbottom
- offsetrect
.top();
3544 dbottom
= offsetrect
.bottom() - wtop
;
3546 // snap top of other window?
3547 if (dtop
>= 0 && dtop
< resistance_size
&& dtop
< (wbottom
- wtop
)) {
3548 dy
= offsetrect
.top() - frame
.rect
.height();
3551 // snap bottom of other window?
3552 else if (dbottom
>= 0 && dbottom
< resistance_size
&&
3553 dbottom
< (wbottom
- wtop
)) {
3554 dy
= offsetrect
.bottom() + 1;
3557 } else { // BScreen::WindowSnap
3558 dtop
= abs(wbottom
- offsetrect
.top());
3559 dbottom
= abs(wtop
- offsetrect
.bottom());
3561 // snap top of other window?
3562 if (dtop
< snap_distance
&& dtop
<= dbottom
) {
3563 dy
= offsetrect
.top() - frame
.rect
.height();
3566 // snap bottom of other window?
3567 else if (dbottom
< snap_distance
) {
3568 dy
= offsetrect
.bottom() + 1;
3575 if (screen
->getWindowCornerSnap()) {
3576 // try corner-snap to its other sides
3577 if (snap_to_windows
== BScreen::WindowResistance
) {
3578 dleft
= winrect
.left() - wleft
;
3579 dright
= wright
- winrect
.right();
3580 if (dleft
> 0 && dleft
< resistance_size
) {
3581 // if we're already past the left edge, then don't provide
3583 if (moving
.left() >= winrect
.left())
3584 dx
= winrect
.left();
3585 } else if (dright
> 0 && dright
< resistance_size
) {
3586 // if we're already past the right edge, then don't provide
3588 if (moving
.right() <= winrect
.right())
3589 dx
= winrect
.right() - frame
.rect
.width() + 1;
3591 } else { // BScreen::WindowSnap
3592 dleft
= abs(wleft
- winrect
.left());
3593 dright
= abs(wright
- winrect
.right());
3594 if (dleft
< snap_distance
&& dleft
<= dright
)
3595 dx
= winrect
.left();
3596 else if (dright
< snap_distance
)
3597 dx
= winrect
.right() - frame
.rect
.width() + 1;
3607 if (snap_to_edges
) {
3610 // snap to the screen edges (and screen boundaries for xinerama)
3612 if (screen
->isXineramaActive() && blackbox
->doXineramaSnapping()) {
3613 rectlist
.insert(rectlist
.begin(),
3614 screen
->getXineramaAreas().begin(),
3615 screen
->getXineramaAreas().end());
3618 rectlist
.push_back(screen
->getRect());
3620 RectList::const_iterator it
, end
= rectlist
.end();
3621 for (it
= rectlist
.begin(); it
!= end
; ++it
) {
3622 const Rect
&srect
= *it
;
3624 offsetrect
.setCoords(srect
.left() + snap_offset
,
3625 srect
.top() + snap_offset
,
3626 srect
.right() - snap_offset
,
3627 srect
.bottom() - snap_offset
);
3629 if (snap_to_edges
== BScreen::WindowResistance
) {
3630 // if we're not in the rectangle then don't snap to it.
3631 if (! srect
.contains(moving
))
3633 } else { // BScreen::WindowSnap
3634 // if we're not in the rectangle then don't snap to it.
3635 if (! srect
.intersects(Rect(wleft
, wtop
, frame
.rect
.width(),
3636 frame
.rect
.height())))
3640 if (snap_to_edges
== BScreen::WindowResistance
) {
3641 int dleft
= offsetrect
.left() - wleft
,
3642 dright
= wright
- offsetrect
.right(),
3643 dtop
= offsetrect
.top() - wtop
,
3644 dbottom
= wbottom
- offsetrect
.bottom();
3647 if (dleft
> 0 && dleft
< resistance_size
)
3648 dx
= offsetrect
.left();
3650 else if (dright
> 0 && dright
< resistance_size
)
3651 dx
= offsetrect
.right() - frame
.rect
.width() + 1;
3654 if (dtop
> 0 && dtop
< resistance_size
)
3655 dy
= offsetrect
.top();
3657 else if (dbottom
> 0 && dbottom
< resistance_size
)
3658 dy
= offsetrect
.bottom() - frame
.rect
.height() + 1;
3659 } else { // BScreen::WindowSnap
3660 int dleft
= abs(wleft
- offsetrect
.left()),
3661 dright
= abs(wright
- offsetrect
.right()),
3662 dtop
= abs(wtop
- offsetrect
.top()),
3663 dbottom
= abs(wbottom
- offsetrect
.bottom());
3666 if (dleft
< snap_distance
&& dleft
<= dright
)
3667 dx
= offsetrect
.left();
3669 else if (dright
< snap_distance
)
3670 dx
= offsetrect
.right() - frame
.rect
.width() + 1;
3673 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3674 dy
= offsetrect
.top();
3676 else if (dbottom
< snap_distance
)
3677 dy
= offsetrect
.bottom() - frame
.rect
.height() + 1;
3684 void BlackboxWindow::endMove(void) {
3685 assert(flags
.moving
);
3686 assert(blackbox
->getChangingWindow() == this);
3688 flags
.moving
= False
;
3689 blackbox
->setChangingWindow(0);
3691 if (! screen
->doOpaqueMove()) {
3692 /* when drawing the rubber band, we need to make sure we only draw inside
3693 * the frame... frame.changing_* contain the new coords for the window,
3694 * so we need to subtract 1 from changing_w/changing_h every where we
3695 * draw the rubber band (for both moving and resizing)
3697 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3698 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3699 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3700 XUngrabServer(blackbox
->getXDisplay());
3702 configure(frame
.changing
.x(), frame
.changing
.y(),
3703 frame
.changing
.width(), frame
.changing
.height());
3705 configure(frame
.rect
.x(), frame
.rect
.y(),
3706 frame
.rect
.width(), frame
.rect
.height());
3708 screen
->hideGeometry();
3710 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3712 // if there are any left over motions from the move, drop them now
3713 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3715 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3720 void BlackboxWindow::beginResize(int x_root
, int y_root
, Corner dir
) {
3721 if (! (functions
& Func_Resize
)) return;
3723 assert(! (flags
.resizing
|| flags
.moving
));
3726 Only one window can be moved/resized at a time. If another window is
3727 already being moved or resized, then stop it before whating to work with
3730 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3731 if (changing
&& changing
!= this) {
3732 if (changing
->flags
.moving
)
3733 changing
->endMove();
3734 else // if (changing->flags.resizing)
3735 changing
->endResize();
3743 switch (resize_dir
) {
3746 cursor
= blackbox
->getLowerLeftAngleCursor();
3751 cursor
= blackbox
->getLowerRightAngleCursor();
3755 anchor
= BottomRight
;
3756 cursor
= blackbox
->getUpperLeftAngleCursor();
3760 anchor
= BottomLeft
;
3761 cursor
= blackbox
->getUpperRightAngleCursor();
3765 assert(false); // unhandled Corner
3766 return; // unreachable, for the compiler
3769 XGrabServer(blackbox
->getXDisplay());
3770 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3771 PointerMotionMask
| ButtonReleaseMask
,
3772 GrabModeAsync
, GrabModeAsync
, None
, cursor
, CurrentTime
);
3774 flags
.resizing
= True
;
3775 blackbox
->setChangingWindow(this);
3777 unsigned int gw
, gh
;
3778 frame
.changing
= frame
.rect
;
3780 constrain(anchor
, &gw
, &gh
);
3782 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3783 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3784 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3786 screen
->showGeometry(gw
, gh
);
3788 frame
.grab_x
= x_root
;
3789 frame
.grab_y
= y_root
;
3793 void BlackboxWindow::doResize(int x_root
, int y_root
) {
3794 assert(flags
.resizing
);
3795 assert(blackbox
->getChangingWindow() == this);
3797 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3798 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3799 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3801 unsigned int gw
, gh
;
3803 int dx
, dy
; // the amount of change in the size of the window
3805 switch (resize_dir
) {
3808 dx
= - (x_root
- frame
.grab_x
);
3809 dy
= + (y_root
- frame
.grab_y
);
3813 dx
= + (x_root
- frame
.grab_x
);
3814 dy
= + (y_root
- frame
.grab_y
);
3817 anchor
= BottomRight
;
3818 dx
= - (x_root
- frame
.grab_x
);
3819 dy
= - (y_root
- frame
.grab_y
);
3822 anchor
= BottomLeft
;
3823 dx
= + (x_root
- frame
.grab_x
);
3824 dy
= - (y_root
- frame
.grab_y
);
3828 assert(false); // unhandled Corner
3829 return; // unreachable, for the compiler
3832 // make sure the user cant resize the window smaller than 0, which makes it
3833 // wrap around and become huge
3834 if (dx
< -(signed)client
.rect
.width()) dx
= -(signed)client
.rect
.width();
3835 if (dy
< -(signed)client
.rect
.height()) dy
= -(signed)client
.rect
.height();
3837 frame
.changing
.setSize(frame
.rect
.width() + dx
, frame
.rect
.height() + dy
);
3839 constrain(anchor
, &gw
, &gh
);
3841 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3842 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3843 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3845 screen
->showGeometry(gw
, gh
);
3849 void BlackboxWindow::endResize(void) {
3850 assert(flags
.resizing
);
3851 assert(blackbox
->getChangingWindow() == this);
3853 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3854 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3855 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3856 XUngrabServer(blackbox
->getXDisplay());
3858 // unset maximized state after resized when fully maximized
3859 if (flags
.maximized
== 1)
3862 flags
.resizing
= False
;
3863 blackbox
->setChangingWindow(0);
3865 configure(frame
.changing
.x(), frame
.changing
.y(),
3866 frame
.changing
.width(), frame
.changing
.height());
3867 screen
->hideGeometry();
3869 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3871 // if there are any left over motions from the resize, drop them now
3872 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3874 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3879 void BlackboxWindow::motionNotifyEvent(const XMotionEvent
*me
) {
3881 fprintf(stderr
, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n",
3886 doMove(me
->x_root
, me
->y_root
);
3887 } else if (flags
.resizing
) {
3888 doResize(me
->x_root
, me
->y_root
);
3890 if ((functions
& Func_Move
) &&
3891 (me
->state
& Button1Mask
) &&
3892 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3893 frame
.handle
== me
->window
|| frame
.window
== me
->window
)) {
3894 beginMove(me
->x_root
, me
->y_root
);
3895 } else if ((functions
& Func_Resize
) &&
3896 ((me
->state
& Button1Mask
) &&
3897 (me
->window
== frame
.right_grip
||
3898 me
->window
== frame
.left_grip
)) ||
3899 ((me
->state
& Button3Mask
) && (me
->state
& mod_mask
) &&
3900 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3901 frame
.handle
== me
->window
|| frame
.window
== me
->window
||
3902 frame
.right_grip
== me
->window
||
3903 frame
.left_grip
== me
->window
))) {
3904 unsigned int zones
= screen
->getResizeZones();
3907 if (me
->window
== frame
.left_grip
) {
3908 corner
= BottomLeft
;
3909 } else if (me
->window
== frame
.right_grip
|| zones
== 1) {
3910 corner
= BottomRight
;
3913 bool left
= (me
->x_root
- frame
.rect
.x() <=
3914 static_cast<signed>(frame
.rect
.width() / 2));
3917 else // (zones == 4)
3918 top
= (me
->y_root
- frame
.rect
.y() <=
3919 static_cast<signed>(frame
.rect
.height() / 2));
3920 corner
= (top
? (left
? TopLeft
: TopRight
) :
3921 (left
? BottomLeft
: BottomRight
));
3924 beginResize(me
->x_root
, me
->y_root
, corner
);
3930 void BlackboxWindow::enterNotifyEvent(const XCrossingEvent
* ce
) {
3931 if (! (screen
->isSloppyFocus() && isVisible() && isNormal()))
3935 bool leave
= False
, inferior
= False
;
3937 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), ce
->window
,
3939 if (e
.type
== LeaveNotify
&& e
.xcrossing
.mode
== NotifyNormal
) {
3941 inferior
= (e
.xcrossing
.detail
== NotifyInferior
);
3945 if (! leave
|| inferior
) {
3946 if (! isFocused()) {
3947 bool success
= setInputFocus();
3948 if (success
) // if focus succeeded install the colormap
3949 installColormap(True
); // XXX: shouldnt we honour no install?
3952 We only auto-raise when the window wasn't focused because otherwise
3953 we run into problems with gtk+ drop-down lists. The window ends up
3954 raising over the list.
3956 if (screen
->doAutoRaise())
3963 void BlackboxWindow::leaveNotifyEvent(const XCrossingEvent
*) {
3964 if (! (screen
->isSloppyFocus() && screen
->doAutoRaise() && isNormal()))
3967 installColormap(False
);
3969 if (timer
->isTiming())
3975 void BlackboxWindow::shapeEvent(XShapeEvent
*e
) {
3976 if (blackbox
->hasShapeExtensions()) {
3977 if (! e
->shaped
&& flags
.shaped
) {
3979 flags
.shaped
= False
;
3980 } else if (e
->shaped
) {
3982 flags
.shaped
= True
;
3989 bool BlackboxWindow::validateClient(void) const {
3990 XSync(blackbox
->getXDisplay(), False
);
3993 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3994 DestroyNotify
, &e
) ||
3995 XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3997 XPutBackEvent(blackbox
->getXDisplay(), &e
);
4006 void BlackboxWindow::restore(bool remap
) {
4007 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeDelete
);
4008 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
4009 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, NoEventMask
);
4011 // do not leave a shaded window as an icon unless it was an icon
4012 if (flags
.shaded
&& ! flags
.iconic
)
4013 setState(NormalState
);
4015 // erase the netwm stuff that we read when a window maps, so that it
4016 // doesn't persist between mappings.
4017 // (these are the ones read in getNetWMFlags().)
4018 xatom
->eraseValue(client
.window
, XAtom::net_wm_desktop
);
4019 xatom
->eraseValue(client
.window
, XAtom::net_wm_state
);
4021 restoreGravity(client
.rect
);
4023 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
4024 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
4026 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, client
.old_bw
);
4029 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
4030 ReparentNotify
, &ev
)) {
4033 // according to the ICCCM - if the client doesn't reparent to
4034 // root, then we have to do it for them
4035 XReparentWindow(blackbox
->getXDisplay(), client
.window
,
4036 screen
->getRootWindow(),
4037 client
.rect
.x(), client
.rect
.y());
4040 if (remap
) XMapWindow(blackbox
->getXDisplay(), client
.window
);
4044 // timer for autoraise
4045 void BlackboxWindow::timeout(void) {
4046 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
4050 void BlackboxWindow::changeBlackboxHints(const BlackboxHints
*net
) {
4051 if ((net
->flags
& AttribShaded
) &&
4052 ((blackbox_attrib
.attrib
& AttribShaded
) !=
4053 (net
->attrib
& AttribShaded
)))
4056 if (flags
.visible
&& // watch out for requests when we can not be seen
4057 (net
->flags
& (AttribMaxVert
| AttribMaxHoriz
)) &&
4058 ((blackbox_attrib
.attrib
& (AttribMaxVert
| AttribMaxHoriz
)) !=
4059 (net
->attrib
& (AttribMaxVert
| AttribMaxHoriz
)))) {
4060 if (flags
.maximized
) {
4065 if ((net
->flags
& AttribMaxHoriz
) && (net
->flags
& AttribMaxVert
))
4066 button
= ((net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0);
4067 else if (net
->flags
& AttribMaxVert
)
4068 button
= ((net
->attrib
& AttribMaxVert
) ? 2 : 0);
4069 else if (net
->flags
& AttribMaxHoriz
)
4070 button
= ((net
->attrib
& AttribMaxHoriz
) ? 3 : 0);
4076 if ((net
->flags
& AttribOmnipresent
) &&
4077 ((blackbox_attrib
.attrib
& AttribOmnipresent
) !=
4078 (net
->attrib
& AttribOmnipresent
)))
4081 if ((net
->flags
& AttribWorkspace
) &&
4082 (blackbox_attrib
.workspace
!= net
->workspace
)) {
4083 screen
->reassociateWindow(this, net
->workspace
, True
);
4085 if (screen
->getCurrentWorkspaceID() != net
->workspace
) {
4089 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
4093 if (net
->flags
& AttribDecoration
) {
4094 switch (net
->decoration
) {
4111 * Set the sizes of all components of the window frame
4112 * (the window decorations).
4113 * These values are based upon the current style settings and the client
4114 * window's dimensions.
4116 void BlackboxWindow::upsize(void) {
4117 frame
.bevel_w
= screen
->getBevelWidth();
4119 if (decorations
& Decor_Border
) {
4120 frame
.border_w
= screen
->getBorderWidth();
4121 if (! isTransient())
4122 frame
.mwm_border_w
= screen
->getFrameWidth();
4124 frame
.mwm_border_w
= 0;
4126 frame
.mwm_border_w
= frame
.border_w
= 0;
4129 if (decorations
& Decor_Titlebar
) {
4130 // the height of the titlebar is based upon the height of the font being
4131 // used to display the window's title
4132 WindowStyle
*style
= screen
->getWindowStyle();
4133 frame
.title_h
= style
->font
->height() + (frame
.bevel_w
* 2) + 2;
4135 frame
.label_h
= frame
.title_h
- (frame
.bevel_w
* 2);
4136 frame
.button_w
= (frame
.label_h
- 2);
4138 // set the top frame margin
4139 frame
.margin
.top
= frame
.border_w
+ frame
.title_h
+
4140 frame
.border_w
+ frame
.mwm_border_w
;
4146 // set the top frame margin
4147 frame
.margin
.top
= frame
.border_w
+ frame
.mwm_border_w
;
4150 // set the left/right frame margin
4151 frame
.margin
.left
= frame
.margin
.right
= frame
.border_w
+ frame
.mwm_border_w
;
4153 if (decorations
& Decor_Handle
) {
4154 frame
.grip_w
= frame
.button_w
* 2;
4155 frame
.handle_h
= screen
->getHandleWidth();
4157 // set the bottom frame margin
4158 frame
.margin
.bottom
= frame
.border_w
+ frame
.handle_h
+
4159 frame
.border_w
+ frame
.mwm_border_w
;
4164 // set the bottom frame margin
4165 frame
.margin
.bottom
= frame
.border_w
+ frame
.mwm_border_w
;
4169 We first get the normal dimensions and use this to define the inside_w/h
4170 then we modify the height if shading is in effect.
4171 If the shade state is not considered then frame.rect gets reset to the
4172 normal window size on a reconfigure() call resulting in improper
4173 dimensions appearing in move/resize and other events.
4176 height
= client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
,
4177 width
= client
.rect
.width() + frame
.margin
.left
+ frame
.margin
.right
;
4179 frame
.inside_w
= width
- (frame
.border_w
* 2);
4180 frame
.inside_h
= height
- (frame
.border_w
* 2);
4183 height
= frame
.title_h
+ (frame
.border_w
* 2);
4184 frame
.rect
.setSize(width
, height
);
4189 * Calculate the size of the client window and constrain it to the
4190 * size specified by the size hints of the client window.
4192 * The logical width and height are placed into pw and ph, if they
4193 * are non-zero. Logical size refers to the users perception of
4194 * the window size (for example an xterm resizes in cells, not in pixels).
4195 * pw and ph are then used to display the geometry during window moves, resize,
4198 * The physical geometry is placed into frame.changing_{x,y,width,height}.
4199 * Physical geometry refers to the geometry of the window in pixels.
4201 void BlackboxWindow::constrain(Corner anchor
,
4202 unsigned int *pw
, unsigned int *ph
) {
4203 // frame.changing represents the requested frame size, we need to
4204 // strip the frame margin off and constrain the client size
4205 frame
.changing
.setCoords(frame
.changing
.left() + frame
.margin
.left
,
4206 frame
.changing
.top() + frame
.margin
.top
,
4207 frame
.changing
.right() - frame
.margin
.right
,
4208 frame
.changing
.bottom() - frame
.margin
.bottom
);
4210 unsigned int dw
= frame
.changing
.width(), dh
= frame
.changing
.height(),
4211 base_width
= (client
.base_width
) ? client
.base_width
: client
.min_width
,
4212 base_height
= (client
.base_height
) ? client
.base_height
:
4215 // constrain, but only if the min/max are being used. if they aren't, then
4216 // this resize is going to be from a ConfigureRequest because the window
4217 // isn't allowed to be resized by the user. And in that case, we don't want
4218 // to limit what the app can do
4219 if (client
.max_width
> client
.min_width
||
4220 client
.max_height
> client
.min_height
) {
4221 if (dw
< client
.min_width
) dw
= client
.min_width
;
4222 if (dh
< client
.min_height
) dh
= client
.min_height
;
4223 if (dw
> client
.max_width
) dw
= client
.max_width
;
4224 if (dh
> client
.max_height
) dh
= client
.max_height
;
4227 if (client
.width_inc
> 1) {
4229 dw
/= client
.width_inc
;
4231 if (client
.height_inc
> 1) {
4233 dh
/= client
.height_inc
;
4242 if (client
.width_inc
> 1) {
4243 dw
*= client
.width_inc
;
4246 if (client
.height_inc
> 1) {
4247 dh
*= client
.height_inc
;
4251 frame
.changing
.setSize(dw
, dh
);
4253 // add the frame margin back onto frame.changing
4254 frame
.changing
.setCoords(frame
.changing
.left() - frame
.margin
.left
,
4255 frame
.changing
.top() - frame
.margin
.top
,
4256 frame
.changing
.right() + frame
.margin
.right
,
4257 frame
.changing
.bottom() + frame
.margin
.bottom
);
4259 // move frame.changing to the specified anchor
4267 dx
= frame
.rect
.right() - frame
.changing
.right();
4271 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
4275 dx
= frame
.rect
.right() - frame
.changing
.right();
4276 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
4280 assert(false); // unhandled corner
4282 frame
.changing
.setPos(frame
.changing
.x() + dx
, frame
.changing
.y() + dy
);
4286 void WindowStyle::doJustify(const std::string
&text
, int &start_pos
,
4287 unsigned int max_length
,
4288 unsigned int modifier
) const {
4289 size_t text_len
= text
.size();
4290 unsigned int length
;
4293 length
= font
->measureString(string(text
, 0, text_len
)) + modifier
;
4294 } while (length
> max_length
&& text_len
-- > 0);
4298 start_pos
+= max_length
- length
;
4302 start_pos
+= (max_length
- length
) / 2;
4312 BWindowGroup::BWindowGroup(Blackbox
*b
, Window _group
)
4313 : blackbox(b
), group(_group
) {
4314 XWindowAttributes wattrib
;
4315 if (! XGetWindowAttributes(blackbox
->getXDisplay(), group
, &wattrib
)) {
4316 // group window doesn't seem to exist anymore
4321 XSelectInput(blackbox
->getXDisplay(), group
,
4322 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
4324 blackbox
->saveGroupSearch(group
, this);
4328 BWindowGroup::~BWindowGroup(void) {
4329 blackbox
->removeGroupSearch(group
);
4334 BWindowGroup::find(BScreen
*screen
, bool allow_transients
) const {
4335 BlackboxWindow
*ret
= blackbox
->getFocusedWindow();
4337 // does the focus window match (or any transient_fors)?
4338 for (; ret
; ret
= ret
->getTransientFor()) {
4339 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
&&
4340 (! ret
->isTransient() || allow_transients
))
4344 if (ret
) return ret
;
4346 // the focus window didn't match, look in the group's window list
4347 BlackboxWindowList::const_iterator it
, end
= windowList
.end();
4348 for (it
= windowList
.begin(); it
!= end
; ++it
) {
4350 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
&&
4351 (! ret
->isTransient() || allow_transients
))