1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2 // Window.cc for Blackbox - an X11 Window manager
3 // Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry <shaleh at debian.org>
4 // Copyright (c) 1997 - 2000, 2002 Brad Hughes <bhughes at trolltech.com>
6 // Permission is hereby granted, free of charge, to any person obtaining a
7 // copy of this software and associated documentation files (the "Software"),
8 // to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 // and/or sell copies of the Software, and to permit persons to whom the
11 // Software is furnished to do so, subject to the following conditions:
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 // DEALINGS IN THE SOFTWARE.
25 # include "../config.h"
26 #endif // HAVE_CONFIG_H
29 #include <X11/Xatom.h>
30 #include <X11/keysym.h>
34 #endif // HAVE_STRING_H
39 # endif // HAVE_STDIO_H
44 #endif // HAVE_STDLIB_H
48 #include "blackbox.hh"
49 #include "Clientmenu.hh"
52 #include "Iconmenu.hh"
58 #include "Windowmenu.hh"
59 #include "Workspace.hh"
66 * Initializes the class with default values/the window's set initial values.
68 BlackboxWindow::BlackboxWindow(Blackbox
*b
, Window w
, BScreen
*s
) {
69 // fprintf(stderr, "BlackboxWindow size: %d bytes\n",
70 // sizeof(BlackboxWindow));
73 fprintf(stderr
, "BlackboxWindow::BlackboxWindow(): creating 0x%lx\n", w
);
77 set timer to zero... it is initialized properly later, so we check
78 if timer is zero in the destructor, and assume that the window is not
79 fully constructed if timer is zero...
85 xatom
= blackbox
->getXAtom();
87 if (! validateClient()) {
92 // fetch client size and placement
93 XWindowAttributes wattrib
;
94 if (! XGetWindowAttributes(blackbox
->getXDisplay(),
95 client
.window
, &wattrib
) ||
96 ! wattrib
.screen
|| wattrib
.override_redirect
) {
99 "BlackboxWindow::BlackboxWindow(): XGetWindowAttributes failed\n");
106 // set the eventmask early in the game so that we make sure we get
107 // all the events we are interested in
108 XSetWindowAttributes attrib_set
;
109 attrib_set
.event_mask
= PropertyChangeMask
| FocusChangeMask
|
111 attrib_set
.do_not_propagate_mask
= ButtonPressMask
| ButtonReleaseMask
|
113 XChangeWindowAttributes(blackbox
->getXDisplay(), client
.window
,
114 CWEventMask
|CWDontPropagate
, &attrib_set
);
116 flags
.moving
= flags
.resizing
= flags
.shaded
= flags
.visible
=
117 flags
.iconic
= flags
.focused
= flags
.stuck
= flags
.modal
=
118 flags
.send_focus_message
= flags
.shaped
= flags
.skip_taskbar
=
119 flags
.skip_pager
= flags
.fullscreen
= False
;
122 blackbox_attrib
.workspace
= window_number
= BSENTINEL
;
124 blackbox_attrib
.flags
= blackbox_attrib
.attrib
= blackbox_attrib
.stack
= 0l;
125 blackbox_attrib
.decoration
= DecorNormal
;
126 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
127 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
130 frame
.window
= frame
.plate
= frame
.title
= frame
.handle
= None
;
131 frame
.close_button
= frame
.iconify_button
= frame
.maximize_button
=
132 frame
.stick_button
= None
;
133 frame
.right_grip
= frame
.left_grip
= None
;
135 frame
.ulabel_pixel
= frame
.flabel_pixel
= frame
.utitle_pixel
=
136 frame
.ftitle_pixel
= frame
.uhandle_pixel
= frame
.fhandle_pixel
=
137 frame
.ubutton_pixel
= frame
.fbutton_pixel
= frame
.pbutton_pixel
=
138 frame
.uborder_pixel
= frame
.fborder_pixel
= frame
.ugrip_pixel
=
139 frame
.fgrip_pixel
= 0;
140 frame
.utitle
= frame
.ftitle
= frame
.uhandle
= frame
.fhandle
= None
;
141 frame
.ulabel
= frame
.flabel
= frame
.ubutton
= frame
.fbutton
= None
;
142 frame
.pbutton
= frame
.ugrip
= frame
.fgrip
= None
;
144 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
145 mwm_decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
146 Decor_Iconify
| Decor_Maximize
;
148 client
.normal_hint_flags
= 0;
149 client
.window_group
= None
;
150 client
.transient_for
= 0;
152 current_state
= NormalState
;
157 set the initial size and location of client window (relative to the
158 _root window_). This position is the reference point used with the
159 window's gravity to find the window's initial position.
161 client
.rect
.setRect(wattrib
.x
, wattrib
.y
, wattrib
.width
, wattrib
.height
);
162 client
.old_bw
= wattrib
.border_width
;
164 lastButtonPressTime
= 0;
166 timer
= new BTimer(blackbox
, this);
167 timer
->setTimeout(blackbox
->getAutoRaiseDelay());
169 // get size, aspect, minimum/maximum size and other hints set by the
172 if (! getBlackboxHints())
179 frame
.window
= createToplevelWindow();
181 blackbox
->saveWindowSearch(frame
.window
, this);
183 frame
.plate
= createChildWindow(frame
.window
, ExposureMask
);
184 blackbox
->saveWindowSearch(frame
.plate
, this);
186 // determine if this is a transient window
189 // determine the window's type, so we can decide its decorations and
190 // functionality, or if we should not manage it at all
191 if (getWindowType()) {
192 // adjust the window decorations/behavior based on the window type
193 switch (window_type
) {
197 blackbox_attrib
.workspace
= 0; // we do need to belong to a workspace
198 flags
.stuck
= True
; // we show up on all workspaces
200 // none of these windows are manipulated by the window manager
206 // these windows get less functionality
207 functions
&= ~(Func_Maximize
| Func_Resize
| Func_Iconify
);
211 // dialogs cannot be maximized
212 functions
&= ~Func_Maximize
;
216 // normal windows retain all of the possible decorations and
224 // further adjeust the window's decorations/behavior based on window sizes
225 if ((client
.normal_hint_flags
& PMinSize
) &&
226 (client
.normal_hint_flags
& PMaxSize
) &&
227 client
.max_width
<= client
.min_width
&&
228 client
.max_height
<= client
.min_height
) {
229 functions
&= ~(Func_Resize
| Func_Maximize
);
236 if (decorations
& Decor_Titlebar
)
239 if (decorations
& Decor_Handle
)
242 // apply the size and gravity hint to the frame
246 bool place_window
= True
;
247 if (blackbox
->isStartup() || isTransient() ||
248 client
.normal_hint_flags
& (PPosition
|USPosition
)) {
249 applyGravity(frame
.rect
);
251 if (blackbox
->isStartup() || client
.rect
.intersects(screen
->getRect()))
252 place_window
= False
;
255 // add the window's strut. note this is done *after* placing the window.
256 screen
->addStrut(&client
.strut
);
260 the server needs to be grabbed here to prevent client's from sending
261 events while we are in the process of configuring their window.
262 We hold the grab until after we are done moving the window around.
265 XGrabServer(blackbox
->getXDisplay());
267 associateClientWindow();
269 blackbox
->saveWindowSearch(client
.window
, this);
271 if (blackbox_attrib
.workspace
>= screen
->getWorkspaceCount())
272 screen
->getCurrentWorkspace()->addWindow(this, place_window
);
274 screen
->getWorkspace(blackbox_attrib
.workspace
)->
275 addWindow(this, place_window
);
277 if (! place_window
) {
278 // don't need to call configure if we are letting the workspace
280 configure(frame
.rect
.x(), frame
.rect
.y(),
281 frame
.rect
.width(), frame
.rect
.height());
287 XUngrabServer(blackbox
->getXDisplay());
290 if (blackbox
->hasShapeExtensions() && flags
.shaped
)
294 // now that we know where to put the window and what it should look like
295 // we apply the decorations
300 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
302 // this ensures the title, buttons, and other decor are properly displayed
305 // preserve the window's initial state on first map, and its current state
307 unsigned long initial_state
= current_state
;
309 current_state
= initial_state
;
311 // get sticky state from our parent window if we've got one
312 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
313 client
.transient_for
->isStuck() != flags
.stuck
)
317 flags
.shaded
= False
;
318 initial_state
= current_state
;
322 At this point in the life of a window, current_state should only be set
323 to IconicState if the window was an *icon*, not if it was shaded.
325 if (initial_state
!= IconicState
)
326 current_state
= NormalState
;
334 if (flags
.maximized
&& (functions
& Func_Maximize
))
337 // create this last so it only needs to be configured once
338 windowmenu
= new Windowmenu(this);
342 BlackboxWindow::~BlackboxWindow(void) {
344 fprintf(stderr
, "BlackboxWindow::~BlackboxWindow: destroying 0x%lx\n",
348 if (! timer
) // window not managed...
354 screen
->removeStrut(&client
.strut
);
355 screen
->updateAvailableArea();
357 // We don't need to worry about resizing because resizing always grabs the X
358 // server. This should only ever happen if using opaque moving.
366 if (client
.window_group
) {
367 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
368 if (group
) group
->removeWindow(this);
371 // remove ourselves from our transient_for
373 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul)
374 client
.transient_for
->client
.transientList
.remove(this);
375 client
.transient_for
= (BlackboxWindow
*) 0;
378 if (client
.transientList
.size() > 0) {
379 // reset transient_for for all transients
380 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
381 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
382 (*it
)->client
.transient_for
= (BlackboxWindow
*) 0;
392 blackbox
->removeWindowSearch(frame
.plate
);
393 XDestroyWindow(blackbox
->getXDisplay(), frame
.plate
);
397 blackbox
->removeWindowSearch(frame
.window
);
398 XDestroyWindow(blackbox
->getXDisplay(), frame
.window
);
401 blackbox
->removeWindowSearch(client
.window
);
405 void BlackboxWindow::enableDecor(bool enable
) {
406 blackbox_attrib
.flags
|= AttribDecoration
;
407 blackbox_attrib
.decoration
= enable
? DecorNormal
: DecorNone
;
410 // we can not be shaded if we lack a titlebar
411 if (! (decorations
& Decor_Titlebar
) && flags
.shaded
)
414 if (flags
.visible
&& frame
.window
) {
415 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
416 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
420 setState(current_state
);
424 void BlackboxWindow::setupDecor() {
425 if (blackbox_attrib
.decoration
!= DecorNone
) {
426 // start with everything on
427 decorations
= Decor_Close
|
428 (mwm_decorations
& Decor_Titlebar
? Decor_Titlebar
: 0) |
429 (mwm_decorations
& Decor_Border
? Decor_Border
: 0) |
430 (mwm_decorations
& Decor_Handle
? Decor_Handle
: 0) |
431 (mwm_decorations
& Decor_Iconify
? Decor_Iconify
: 0) |
432 (mwm_decorations
& Decor_Maximize
? Decor_Maximize
: 0);
434 if (! (functions
& Func_Close
)) decorations
&= ~Decor_Close
;
435 if (! (functions
& Func_Maximize
)) decorations
&= ~Decor_Maximize
;
436 if (! (functions
& Func_Iconify
)) decorations
&= ~Decor_Iconify
;
437 if (! (functions
& Func_Resize
)) decorations
&= ~Decor_Handle
;
439 switch (window_type
) {
444 // none of these windows are decorated by the window manager at all
450 decorations
&= ~(Decor_Border
);
454 decorations
&= ~Decor_Handle
;
466 * Creates a new top level window, with a given location, size, and border
468 * Returns: the newly created window
470 Window
BlackboxWindow::createToplevelWindow(void) {
471 XSetWindowAttributes attrib_create
;
472 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
| CWColormap
|
473 CWOverrideRedirect
| CWEventMask
;
475 attrib_create
.background_pixmap
= None
;
476 attrib_create
.colormap
= screen
->getColormap();
477 attrib_create
.override_redirect
= True
;
478 attrib_create
.event_mask
= EnterWindowMask
| LeaveWindowMask
|
481 We catch button presses because other wise they get passed down to the
482 root window, which will then cause root menus to show when you click the
486 return XCreateWindow(blackbox
->getXDisplay(), screen
->getRootWindow(),
487 0, 0, 1, 1, frame
.border_w
, screen
->getDepth(),
488 InputOutput
, screen
->getVisual(), create_mask
,
494 * Creates a child window, and optionally associates a given cursor with
497 Window
BlackboxWindow::createChildWindow(Window parent
,
498 unsigned long event_mask
,
500 XSetWindowAttributes attrib_create
;
501 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
|
504 attrib_create
.background_pixmap
= None
;
505 attrib_create
.event_mask
= event_mask
;
508 create_mask
|= CWCursor
;
509 attrib_create
.cursor
= cursor
;
512 return XCreateWindow(blackbox
->getXDisplay(), parent
, 0, 0, 1, 1, 0,
513 screen
->getDepth(), InputOutput
, screen
->getVisual(),
514 create_mask
, &attrib_create
);
518 void BlackboxWindow::associateClientWindow(void) {
519 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, 0);
523 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeInsert
);
525 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, SubstructureRedirectMask
);
528 note we used to grab around this call to XReparentWindow however the
529 server is now grabbed before this method is called
531 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
533 XSelectInput(blackbox
->getXDisplay(), client
.window
,
534 event_mask
& ~StructureNotifyMask
);
535 XReparentWindow(blackbox
->getXDisplay(), client
.window
, frame
.plate
, 0, 0);
536 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
538 XRaiseWindow(blackbox
->getXDisplay(), frame
.plate
);
539 XMapSubwindows(blackbox
->getXDisplay(), frame
.plate
);
542 if (blackbox
->hasShapeExtensions()) {
543 XShapeSelectInput(blackbox
->getXDisplay(), client
.window
,
550 XShapeQueryExtents(blackbox
->getXDisplay(), client
.window
, &shaped
,
551 &foo
, &foo
, &ufoo
, &ufoo
, &foo
, &foo
, &foo
,
553 flags
.shaped
= shaped
;
559 void BlackboxWindow::decorate(void) {
562 texture
= &(screen
->getWindowStyle()->b_focus
);
563 frame
.fbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
566 frame
.fbutton_pixel
= texture
->color().pixel();
568 texture
= &(screen
->getWindowStyle()->b_unfocus
);
569 frame
.ubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
572 frame
.ubutton_pixel
= texture
->color().pixel();
574 texture
= &(screen
->getWindowStyle()->b_pressed
);
575 frame
.pbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
578 frame
.pbutton_pixel
= texture
->color().pixel();
580 if (decorations
& Decor_Titlebar
) {
581 texture
= &(screen
->getWindowStyle()->t_focus
);
582 frame
.ftitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
585 frame
.ftitle_pixel
= texture
->color().pixel();
587 texture
= &(screen
->getWindowStyle()->t_unfocus
);
588 frame
.utitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
591 frame
.utitle_pixel
= texture
->color().pixel();
593 XSetWindowBorder(blackbox
->getXDisplay(), frame
.title
,
594 screen
->getBorderColor()->pixel());
599 if (decorations
& Decor_Border
) {
600 frame
.fborder_pixel
= screen
->getWindowStyle()->f_focus
.color().pixel();
601 frame
.uborder_pixel
= screen
->getWindowStyle()->f_unfocus
.color().pixel();
604 if (decorations
& Decor_Handle
) {
605 texture
= &(screen
->getWindowStyle()->h_focus
);
606 frame
.fhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
609 frame
.fhandle_pixel
= texture
->color().pixel();
611 texture
= &(screen
->getWindowStyle()->h_unfocus
);
612 frame
.uhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
615 frame
.uhandle_pixel
= texture
->color().pixel();
617 texture
= &(screen
->getWindowStyle()->g_focus
);
618 frame
.fgrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.fgrip
);
620 frame
.fgrip_pixel
= texture
->color().pixel();
622 texture
= &(screen
->getWindowStyle()->g_unfocus
);
623 frame
.ugrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.ugrip
);
625 frame
.ugrip_pixel
= texture
->color().pixel();
627 XSetWindowBorder(blackbox
->getXDisplay(), frame
.handle
,
628 screen
->getBorderColor()->pixel());
629 XSetWindowBorder(blackbox
->getXDisplay(), frame
.left_grip
,
630 screen
->getBorderColor()->pixel());
631 XSetWindowBorder(blackbox
->getXDisplay(), frame
.right_grip
,
632 screen
->getBorderColor()->pixel());
635 XSetWindowBorder(blackbox
->getXDisplay(), frame
.window
,
636 screen
->getBorderColor()->pixel());
640 void BlackboxWindow::decorateLabel(void) {
643 texture
= &(screen
->getWindowStyle()->l_focus
);
644 frame
.flabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.flabel
);
646 frame
.flabel_pixel
= texture
->color().pixel();
648 texture
= &(screen
->getWindowStyle()->l_unfocus
);
649 frame
.ulabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.ulabel
);
651 frame
.ulabel_pixel
= texture
->color().pixel();
655 void BlackboxWindow::createHandle(void) {
656 frame
.handle
= createChildWindow(frame
.window
,
657 ButtonPressMask
| ButtonReleaseMask
|
658 ButtonMotionMask
| ExposureMask
);
659 blackbox
->saveWindowSearch(frame
.handle
, this);
662 createChildWindow(frame
.handle
,
663 ButtonPressMask
| ButtonReleaseMask
|
664 ButtonMotionMask
| ExposureMask
,
665 blackbox
->getLowerLeftAngleCursor());
666 blackbox
->saveWindowSearch(frame
.left_grip
, this);
669 createChildWindow(frame
.handle
,
670 ButtonPressMask
| ButtonReleaseMask
|
671 ButtonMotionMask
| ExposureMask
,
672 blackbox
->getLowerRightAngleCursor());
673 blackbox
->saveWindowSearch(frame
.right_grip
, this);
677 void BlackboxWindow::destroyHandle(void) {
679 screen
->getImageControl()->removeImage(frame
.fhandle
);
682 screen
->getImageControl()->removeImage(frame
.uhandle
);
685 screen
->getImageControl()->removeImage(frame
.fgrip
);
688 screen
->getImageControl()->removeImage(frame
.ugrip
);
690 blackbox
->removeWindowSearch(frame
.left_grip
);
691 blackbox
->removeWindowSearch(frame
.right_grip
);
693 XDestroyWindow(blackbox
->getXDisplay(), frame
.left_grip
);
694 XDestroyWindow(blackbox
->getXDisplay(), frame
.right_grip
);
695 frame
.left_grip
= frame
.right_grip
= None
;
697 blackbox
->removeWindowSearch(frame
.handle
);
698 XDestroyWindow(blackbox
->getXDisplay(), frame
.handle
);
703 void BlackboxWindow::createTitlebar(void) {
704 frame
.title
= createChildWindow(frame
.window
,
705 ButtonPressMask
| ButtonReleaseMask
|
706 ButtonMotionMask
| ExposureMask
);
707 frame
.label
= createChildWindow(frame
.title
,
708 ButtonPressMask
| ButtonReleaseMask
|
709 ButtonMotionMask
| ExposureMask
);
710 blackbox
->saveWindowSearch(frame
.title
, this);
711 blackbox
->saveWindowSearch(frame
.label
, this);
713 if (decorations
& Decor_Iconify
) createIconifyButton();
714 if (decorations
& Decor_Maximize
) createMaximizeButton();
715 if (decorations
& Decor_Close
) createCloseButton();
719 void BlackboxWindow::destroyTitlebar(void) {
720 if (frame
.close_button
)
721 destroyCloseButton();
723 if (frame
.iconify_button
)
724 destroyIconifyButton();
726 if (frame
.maximize_button
)
727 destroyMaximizeButton();
729 if (frame
.stick_button
)
730 destroyStickyButton();
733 screen
->getImageControl()->removeImage(frame
.ftitle
);
736 screen
->getImageControl()->removeImage(frame
.utitle
);
739 screen
->getImageControl()->removeImage(frame
.flabel
);
742 screen
->getImageControl()->removeImage(frame
.ulabel
);
745 screen
->getImageControl()->removeImage(frame
.fbutton
);
748 screen
->getImageControl()->removeImage(frame
.ubutton
);
751 screen
->getImageControl()->removeImage(frame
.pbutton
);
753 blackbox
->removeWindowSearch(frame
.title
);
754 blackbox
->removeWindowSearch(frame
.label
);
756 XDestroyWindow(blackbox
->getXDisplay(), frame
.label
);
757 XDestroyWindow(blackbox
->getXDisplay(), frame
.title
);
758 frame
.title
= frame
.label
= None
;
762 void BlackboxWindow::createCloseButton(void) {
763 if (frame
.title
!= None
) {
764 frame
.close_button
= createChildWindow(frame
.title
,
767 ButtonMotionMask
| ExposureMask
);
768 blackbox
->saveWindowSearch(frame
.close_button
, this);
773 void BlackboxWindow::destroyCloseButton(void) {
774 blackbox
->removeWindowSearch(frame
.close_button
);
775 XDestroyWindow(blackbox
->getXDisplay(), frame
.close_button
);
776 frame
.close_button
= None
;
780 void BlackboxWindow::createIconifyButton(void) {
781 if (frame
.title
!= None
) {
782 frame
.iconify_button
= createChildWindow(frame
.title
,
785 ButtonMotionMask
| ExposureMask
);
786 blackbox
->saveWindowSearch(frame
.iconify_button
, this);
791 void BlackboxWindow::destroyIconifyButton(void) {
792 blackbox
->removeWindowSearch(frame
.iconify_button
);
793 XDestroyWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
794 frame
.iconify_button
= None
;
798 void BlackboxWindow::createMaximizeButton(void) {
799 if (frame
.title
!= None
) {
800 frame
.maximize_button
= createChildWindow(frame
.title
,
803 ButtonMotionMask
| ExposureMask
);
804 blackbox
->saveWindowSearch(frame
.maximize_button
, this);
809 void BlackboxWindow::destroyMaximizeButton(void) {
810 blackbox
->removeWindowSearch(frame
.maximize_button
);
811 XDestroyWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
812 frame
.maximize_button
= None
;
815 void BlackboxWindow::createStickyButton(void) {
816 if (frame
.title
!= None
) {
817 frame
.stick_button
= createChildWindow(frame
.title
,
820 ButtonMotionMask
| ExposureMask
);
821 blackbox
->saveWindowSearch(frame
.stick_button
, this);
825 void BlackboxWindow::destroyStickyButton(void) {
826 blackbox
->removeWindowSearch(frame
.stick_button
);
827 XDestroyWindow(blackbox
->getXDisplay(), frame
.stick_button
);
828 frame
.stick_button
= None
;
831 void BlackboxWindow::positionButtons(bool redecorate_label
) {
832 string layout
= blackbox
->getTitlebarLayout();
835 bool hasclose
, hasiconify
, hasmaximize
, haslabel
, hasstick
;
836 hasclose
= hasiconify
= hasmaximize
= haslabel
= hasstick
= false;
838 string::const_iterator it
, end
;
839 for (it
= layout
.begin(), end
= layout
.end(); it
!= end
; ++it
) {
842 if (! hasclose
&& (decorations
& Decor_Close
)) {
848 if (! hasiconify
&& (decorations
& Decor_Iconify
)) {
860 if (! hasmaximize
&& (decorations
& Decor_Maximize
)) {
874 if (! hasclose
&& frame
.close_button
)
875 destroyCloseButton();
876 if (! hasiconify
&& frame
.iconify_button
)
877 destroyIconifyButton();
878 if (! hasmaximize
&& frame
.maximize_button
)
879 destroyMaximizeButton();
880 if (! hasstick
&& frame
.stick_button
)
881 destroyStickyButton();
883 parsed
+= 'L'; // require that the label be in the layout
885 const unsigned int bsep
= frame
.bevel_w
+ 1; // separation between elements
886 const unsigned int by
= frame
.bevel_w
+ 1;
887 const unsigned int ty
= frame
.bevel_w
;
889 frame
.label_w
= frame
.inside_w
- bsep
* 2 -
890 (frame
.button_w
+ bsep
) * (parsed
.size() - 1);
892 unsigned int x
= bsep
;
893 for (it
= parsed
.begin(), end
= parsed
.end(); it
!= end
; ++it
) {
896 if (! frame
.close_button
) createCloseButton();
897 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.close_button
, x
, by
,
898 frame
.button_w
, frame
.button_w
);
899 x
+= frame
.button_w
+ bsep
;
902 if (! frame
.iconify_button
) createIconifyButton();
903 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.iconify_button
, x
, by
,
904 frame
.button_w
, frame
.button_w
);
905 x
+= frame
.button_w
+ bsep
;
908 if (! frame
.stick_button
) createStickyButton();
909 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.stick_button
, x
, by
,
910 frame
.button_w
, frame
.button_w
);
911 x
+= frame
.button_w
+ bsep
;
914 if (! frame
.maximize_button
) createMaximizeButton();
915 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.maximize_button
, x
, by
,
916 frame
.button_w
, frame
.button_w
);
917 x
+= frame
.button_w
+ bsep
;
920 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.label
, x
, ty
,
921 frame
.label_w
, frame
.label_h
);
922 x
+= frame
.label_w
+ bsep
;
927 if (redecorate_label
) decorateLabel();
933 void BlackboxWindow::reconfigure(void) {
934 restoreGravity(client
.rect
);
936 applyGravity(frame
.rect
);
945 windowmenu
->move(windowmenu
->getX(), frame
.rect
.y() + frame
.title_h
);
946 windowmenu
->reconfigure();
951 void BlackboxWindow::grabButtons(void) {
952 mod_mask
= blackbox
->getMouseModMask();
954 if (! screen
->isSloppyFocus() || screen
->doClickRaise())
955 // grab button 1 for changing focus/raising
956 blackbox
->grabButton(Button1
, 0, frame
.plate
, True
, ButtonPressMask
,
957 GrabModeSync
, GrabModeSync
, frame
.plate
, None
,
958 screen
->allowScrollLock());
960 if (functions
& Func_Move
)
961 blackbox
->grabButton(Button1
, mod_mask
, frame
.window
, True
,
962 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
963 GrabModeAsync
, frame
.window
, None
,
964 screen
->allowScrollLock());
965 if (functions
& Func_Resize
)
966 blackbox
->grabButton(Button3
, mod_mask
, frame
.window
, True
,
967 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
968 GrabModeAsync
, frame
.window
, None
,
969 screen
->allowScrollLock());
970 // alt+middle lowers the window
971 blackbox
->grabButton(Button2
, mod_mask
, frame
.window
, True
,
972 ButtonReleaseMask
, GrabModeAsync
, GrabModeAsync
,
973 frame
.window
, None
, screen
->allowScrollLock());
977 void BlackboxWindow::ungrabButtons(void) {
978 blackbox
->ungrabButton(Button1
, 0, frame
.plate
);
979 blackbox
->ungrabButton(Button1
, mod_mask
, frame
.window
);
980 blackbox
->ungrabButton(Button2
, mod_mask
, frame
.window
);
981 blackbox
->ungrabButton(Button3
, mod_mask
, frame
.window
);
985 void BlackboxWindow::positionWindows(void) {
986 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.window
,
987 frame
.rect
.x(), frame
.rect
.y(), frame
.inside_w
,
988 (flags
.shaded
) ? frame
.title_h
: frame
.inside_h
);
989 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.window
,
991 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.plate
,
993 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.plate
,
994 frame
.margin
.left
- frame
.mwm_border_w
- frame
.border_w
,
995 frame
.margin
.top
- frame
.mwm_border_w
- frame
.border_w
,
996 client
.rect
.width(), client
.rect
.height());
997 XMoveResizeWindow(blackbox
->getXDisplay(), client
.window
,
998 0, 0, client
.rect
.width(), client
.rect
.height());
999 // ensure client.rect contains the real location
1000 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1001 frame
.rect
.top() + frame
.margin
.top
);
1003 if (decorations
& Decor_Titlebar
) {
1004 if (frame
.title
== None
) createTitlebar();
1006 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.title
,
1008 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.title
, -frame
.border_w
,
1009 -frame
.border_w
, frame
.inside_w
, frame
.title_h
);
1012 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
1013 XMapWindow(blackbox
->getXDisplay(), frame
.title
);
1014 } else if (frame
.title
) {
1017 if (decorations
& Decor_Handle
) {
1018 if (frame
.handle
== None
) createHandle();
1019 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.handle
,
1021 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.left_grip
,
1023 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.right_grip
,
1026 // use client.rect here so the value is correct even if shaded
1027 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.handle
,
1029 client
.rect
.height() + frame
.margin
.top
+
1030 frame
.mwm_border_w
- frame
.border_w
,
1031 frame
.inside_w
, frame
.handle_h
);
1032 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.left_grip
,
1033 -frame
.border_w
, -frame
.border_w
,
1034 frame
.grip_w
, frame
.handle_h
);
1035 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.right_grip
,
1036 frame
.inside_w
- frame
.grip_w
- frame
.border_w
,
1037 -frame
.border_w
, frame
.grip_w
, frame
.handle_h
);
1039 XMapSubwindows(blackbox
->getXDisplay(), frame
.handle
);
1040 XMapWindow(blackbox
->getXDisplay(), frame
.handle
);
1041 } else if (frame
.handle
) {
1044 XSync(blackbox
->getXDisplay(), False
);
1048 void BlackboxWindow::updateStrut(void) {
1049 unsigned long num
= 4;
1050 unsigned long *data
;
1051 if (! xatom
->getValue(client
.window
, XAtom::net_wm_strut
, XAtom::cardinal
,
1056 client
.strut
.left
= data
[0];
1057 client
.strut
.right
= data
[1];
1058 client
.strut
.top
= data
[2];
1059 client
.strut
.bottom
= data
[3];
1061 screen
->updateAvailableArea();
1068 bool BlackboxWindow::getWindowType(void) {
1069 window_type
= (WindowType
) -1;
1072 unsigned long num
= (unsigned) -1;
1073 if (xatom
->getValue(client
.window
, XAtom::net_wm_window_type
, XAtom::atom
,
1075 for (unsigned long i
= 0; i
< num
; ++i
) {
1076 if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_desktop
))
1077 window_type
= Type_Desktop
;
1078 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_dock
))
1079 window_type
= Type_Dock
;
1080 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_toolbar
))
1081 window_type
= Type_Toolbar
;
1082 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_menu
))
1083 window_type
= Type_Menu
;
1084 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_utility
))
1085 window_type
= Type_Utility
;
1086 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_splash
))
1087 window_type
= Type_Splash
;
1088 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_dialog
))
1089 window_type
= Type_Dialog
;
1090 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_normal
))
1091 window_type
= Type_Normal
;
1093 xatom
->getAtom(XAtom::kde_net_wm_window_type_override
))
1094 mwm_decorations
= 0; // prevent this window from getting any decor
1099 if (window_type
== (WindowType
) -1) {
1101 * the window type hint was not set, which means we either classify ourself
1102 * as a normal window or a dialog, depending on if we are a transient.
1105 window_type
= Type_Dialog
;
1107 window_type
= Type_Normal
;
1116 void BlackboxWindow::getWMName(void) {
1117 if (xatom
->getValue(client
.window
, XAtom::net_wm_name
,
1118 XAtom::utf8
, client
.title
) &&
1119 !client
.title
.empty()) {
1120 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
1123 //fall through to using WM_NAME
1124 if (xatom
->getValue(client
.window
, XAtom::wm_name
, XAtom::ansi
, client
.title
)
1125 && !client
.title
.empty()) {
1126 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
1129 // fall back to an internal default
1130 client
.title
= i18n(WindowSet
, WindowUnnamed
, "Unnamed");
1131 xatom
->setValue(client
.window
, XAtom::net_wm_visible_name
, XAtom::utf8
,
1134 #ifdef DEBUG_WITH_ID
1135 // the 16 is the 8 chars of the debug text plus the number
1136 char *tmp
= new char[client
.title
.length() + 16];
1137 sprintf(tmp
, "%s; id: 0x%lx", client
.title
.c_str(), client
.window
);
1144 void BlackboxWindow::getWMIconName(void) {
1145 if (xatom
->getValue(client
.window
, XAtom::net_wm_icon_name
,
1146 XAtom::utf8
, client
.icon_title
) &&
1147 !client
.icon_title
.empty()) {
1148 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1151 //fall through to using WM_ICON_NAME
1152 if (xatom
->getValue(client
.window
, XAtom::wm_icon_name
, XAtom::ansi
,
1153 client
.icon_title
) &&
1154 !client
.icon_title
.empty()) {
1155 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1158 // fall back to using the main name
1159 client
.icon_title
= client
.title
;
1160 xatom
->setValue(client
.window
, XAtom::net_wm_visible_icon_name
, XAtom::utf8
,
1166 * Retrieve which WM Protocols are supported by the client window.
1167 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
1168 * window's decorations and allow the close behavior.
1169 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
1172 void BlackboxWindow::getWMProtocols(void) {
1176 if (XGetWMProtocols(blackbox
->getXDisplay(), client
.window
,
1177 &proto
, &num_return
)) {
1178 for (int i
= 0; i
< num_return
; ++i
) {
1179 if (proto
[i
] == xatom
->getAtom(XAtom::wm_delete_window
)) {
1180 decorations
|= Decor_Close
;
1181 functions
|= Func_Close
;
1182 } else if (proto
[i
] == xatom
->getAtom(XAtom::wm_take_focus
))
1183 flags
.send_focus_message
= True
;
1184 else if (proto
[i
] == xatom
->getAtom(XAtom::blackbox_structure_messages
))
1185 screen
->addNetizen(new Netizen(screen
, client
.window
));
1194 * Gets the value of the WM_HINTS property.
1195 * If the property is not set, then use a set of default values.
1197 void BlackboxWindow::getWMHints(void) {
1198 focus_mode
= F_Passive
;
1200 // remove from current window group
1201 if (client
.window_group
) {
1202 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1203 if (group
) group
->removeWindow(this);
1205 client
.window_group
= None
;
1207 XWMHints
*wmhint
= XGetWMHints(blackbox
->getXDisplay(), client
.window
);
1212 if (wmhint
->flags
& InputHint
) {
1213 if (wmhint
->input
== True
) {
1214 if (flags
.send_focus_message
)
1215 focus_mode
= F_LocallyActive
;
1217 if (flags
.send_focus_message
)
1218 focus_mode
= F_GloballyActive
;
1220 focus_mode
= F_NoInput
;
1224 if (wmhint
->flags
& StateHint
)
1225 current_state
= wmhint
->initial_state
;
1227 if (wmhint
->flags
& WindowGroupHint
) {
1228 client
.window_group
= wmhint
->window_group
;
1230 // add window to the appropriate group
1231 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1232 if (! group
) { // no group found, create it!
1233 new BWindowGroup(blackbox
, client
.window_group
);
1234 group
= blackbox
->searchGroup(client
.window_group
);
1237 group
->addWindow(this);
1245 * Gets the value of the WM_NORMAL_HINTS property.
1246 * If the property is not set, then use a set of default values.
1248 void BlackboxWindow::getWMNormalHints(void) {
1250 XSizeHints sizehint
;
1252 client
.min_width
= client
.min_height
=
1253 client
.width_inc
= client
.height_inc
= 1;
1254 client
.base_width
= client
.base_height
= 0;
1255 client
.win_gravity
= NorthWestGravity
;
1257 client
.min_aspect_x
= client
.min_aspect_y
=
1258 client
.max_aspect_x
= client
.max_aspect_y
= 1;
1261 // don't limit the size of a window, the default max width is the biggest
1263 client
.max_width
= (unsigned) -1;
1264 client
.max_height
= (unsigned) -1;
1267 if (! XGetWMNormalHints(blackbox
->getXDisplay(), client
.window
,
1268 &sizehint
, &icccm_mask
))
1271 client
.normal_hint_flags
= sizehint
.flags
;
1273 if (sizehint
.flags
& PMinSize
) {
1274 if (sizehint
.min_width
>= 0)
1275 client
.min_width
= sizehint
.min_width
;
1276 if (sizehint
.min_height
>= 0)
1277 client
.min_height
= sizehint
.min_height
;
1280 if (sizehint
.flags
& PMaxSize
) {
1281 if (sizehint
.max_width
> static_cast<signed>(client
.min_width
))
1282 client
.max_width
= sizehint
.max_width
;
1284 client
.max_width
= client
.min_width
;
1286 if (sizehint
.max_height
> static_cast<signed>(client
.min_height
))
1287 client
.max_height
= sizehint
.max_height
;
1289 client
.max_height
= client
.min_height
;
1292 if (sizehint
.flags
& PResizeInc
) {
1293 client
.width_inc
= sizehint
.width_inc
;
1294 client
.height_inc
= sizehint
.height_inc
;
1297 #if 0 // we do not support this at the moment
1298 if (sizehint
.flags
& PAspect
) {
1299 client
.min_aspect_x
= sizehint
.min_aspect
.x
;
1300 client
.min_aspect_y
= sizehint
.min_aspect
.y
;
1301 client
.max_aspect_x
= sizehint
.max_aspect
.x
;
1302 client
.max_aspect_y
= sizehint
.max_aspect
.y
;
1306 if (sizehint
.flags
& PBaseSize
) {
1307 client
.base_width
= sizehint
.base_width
;
1308 client
.base_height
= sizehint
.base_height
;
1311 if (sizehint
.flags
& PWinGravity
)
1312 client
.win_gravity
= sizehint
.win_gravity
;
1317 * Gets the NETWM hints for the class' contained window.
1319 void BlackboxWindow::getNetWMHints(void) {
1320 unsigned long workspace
;
1322 if (xatom
->getValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1324 if (workspace
== 0xffffffff)
1327 blackbox_attrib
.workspace
= workspace
;
1330 unsigned long *state
;
1331 unsigned long num
= (unsigned) -1;
1332 if (xatom
->getValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
1336 for (unsigned long i
= 0; i
< num
; ++i
) {
1337 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
))
1339 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_shaded
))
1340 flags
.shaded
= True
;
1341 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
))
1342 flags
.skip_taskbar
= True
;
1343 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_pager
))
1344 flags
.skip_pager
= True
;
1345 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_fullscreen
))
1346 flags
.fullscreen
= True
;
1347 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_hidden
))
1348 setState(IconicState
);
1349 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_vert
))
1351 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_horz
))
1355 flags
.maximized
= 1;
1357 flags
.maximized
= 2;
1359 flags
.maximized
= 3;
1367 * Gets the MWM hints for the class' contained window.
1368 * This is used while initializing the window to its first state, and not
1370 * Returns: true if the MWM hints are successfully retreived and applied;
1371 * false if they are not.
1373 void BlackboxWindow::getMWMHints(void) {
1377 num
= PropMwmHintsElements
;
1378 if (! xatom
->getValue(client
.window
, XAtom::motif_wm_hints
,
1379 XAtom::motif_wm_hints
, num
,
1380 (unsigned long **)&mwm_hint
))
1382 if (num
< PropMwmHintsElements
) {
1387 if (mwm_hint
->flags
& MwmHintsDecorations
) {
1388 if (mwm_hint
->decorations
& MwmDecorAll
) {
1389 mwm_decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
1390 Decor_Iconify
| Decor_Maximize
;
1392 mwm_decorations
= 0;
1394 if (mwm_hint
->decorations
& MwmDecorBorder
)
1395 mwm_decorations
|= Decor_Border
;
1396 if (mwm_hint
->decorations
& MwmDecorHandle
)
1397 mwm_decorations
|= Decor_Handle
;
1398 if (mwm_hint
->decorations
& MwmDecorTitle
)
1399 mwm_decorations
|= Decor_Titlebar
;
1400 if (mwm_hint
->decorations
& MwmDecorIconify
)
1401 mwm_decorations
|= Decor_Iconify
;
1402 if (mwm_hint
->decorations
& MwmDecorMaximize
)
1403 mwm_decorations
|= Decor_Maximize
;
1407 if (mwm_hint
->flags
& MwmHintsFunctions
) {
1408 if (mwm_hint
->functions
& MwmFuncAll
) {
1409 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
|
1414 if (mwm_hint
->functions
& MwmFuncResize
)
1415 functions
|= Func_Resize
;
1416 if (mwm_hint
->functions
& MwmFuncMove
)
1417 functions
|= Func_Move
;
1418 if (mwm_hint
->functions
& MwmFuncIconify
)
1419 functions
|= Func_Iconify
;
1420 if (mwm_hint
->functions
& MwmFuncMaximize
)
1421 functions
|= Func_Maximize
;
1422 if (mwm_hint
->functions
& MwmFuncClose
)
1423 functions
|= Func_Close
;
1431 * Gets the blackbox hints from the class' contained window.
1432 * This is used while initializing the window to its first state, and not
1434 * Returns: true if the hints are successfully retreived and applied; false if
1437 bool BlackboxWindow::getBlackboxHints(void) {
1439 BlackboxHints
*blackbox_hint
;
1441 num
= PropBlackboxHintsElements
;
1442 if (! xatom
->getValue(client
.window
, XAtom::blackbox_hints
,
1443 XAtom::blackbox_hints
, num
,
1444 (unsigned long **)&blackbox_hint
))
1446 if (num
< PropBlackboxHintsElements
) {
1447 delete [] blackbox_hint
;
1451 if (blackbox_hint
->flags
& AttribShaded
)
1452 flags
.shaded
= (blackbox_hint
->attrib
& AttribShaded
);
1454 if ((blackbox_hint
->flags
& AttribMaxHoriz
) &&
1455 (blackbox_hint
->flags
& AttribMaxVert
))
1456 flags
.maximized
= (blackbox_hint
->attrib
&
1457 (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1458 else if (blackbox_hint
->flags
& AttribMaxVert
)
1459 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxVert
) ? 2 : 0;
1460 else if (blackbox_hint
->flags
& AttribMaxHoriz
)
1461 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1463 if (blackbox_hint
->flags
& AttribOmnipresent
)
1464 flags
.stuck
= (blackbox_hint
->attrib
& AttribOmnipresent
);
1466 if (blackbox_hint
->flags
& AttribWorkspace
)
1467 blackbox_attrib
.workspace
= blackbox_hint
->workspace
;
1469 // if (blackbox_hint->flags & AttribStack)
1470 // don't yet have always on top/bottom for blackbox yet... working
1473 if (blackbox_hint
->flags
& AttribDecoration
) {
1474 switch (blackbox_hint
->decoration
) {
1476 blackbox_attrib
.decoration
= DecorNone
;
1483 // blackbox_attrib.decoration defaults to DecorNormal
1488 delete [] blackbox_hint
;
1494 void BlackboxWindow::getTransientInfo(void) {
1495 if (client
.transient_for
&&
1496 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1497 // reset transient_for in preparation of looking for a new owner
1498 client
.transient_for
->client
.transientList
.remove(this);
1501 // we have no transient_for until we find a new one
1502 client
.transient_for
= (BlackboxWindow
*) 0;
1505 if (! XGetTransientForHint(blackbox
->getXDisplay(), client
.window
,
1507 // transient_for hint not set
1511 if (trans_for
== client
.window
) {
1512 // wierd client... treat this window as a normal window
1516 if (trans_for
== None
|| trans_for
== screen
->getRootWindow()) {
1517 // this is an undocumented interpretation of the ICCCM. a transient
1518 // associated with None/Root/itself is assumed to be a modal root
1519 // transient. we don't support the concept of a global transient,
1520 // so we just associate this transient with nothing, and perhaps
1521 // we will add support later for global modality.
1522 client
.transient_for
= (BlackboxWindow
*) ~0ul;
1527 client
.transient_for
= blackbox
->searchWindow(trans_for
);
1528 if (! client
.transient_for
&&
1529 client
.window_group
&& trans_for
== client
.window_group
) {
1530 // no direct transient_for, perhaps this is a group transient?
1531 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1532 if (group
) client
.transient_for
= group
->find(screen
);
1535 if (! client
.transient_for
|| client
.transient_for
== this) {
1536 // no transient_for found, or we have a wierd client that wants to be
1537 // a transient for itself, so we treat this window as a normal window
1538 client
.transient_for
= (BlackboxWindow
*) 0;
1542 // Check for a circular transient state: this can lock up Blackbox
1543 // when it tries to find the non-transient window for a transient.
1544 BlackboxWindow
*w
= this;
1545 while(w
->client
.transient_for
&&
1546 w
->client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1547 if(w
->client
.transient_for
== this) {
1548 client
.transient_for
= (BlackboxWindow
*) 0;
1551 w
= w
->client
.transient_for
;
1554 if (client
.transient_for
&&
1555 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1556 // register ourselves with our new transient_for
1557 client
.transient_for
->client
.transientList
.push_back(this);
1558 flags
.stuck
= client
.transient_for
->flags
.stuck
;
1563 BlackboxWindow
*BlackboxWindow::getTransientFor(void) const {
1564 if (client
.transient_for
&&
1565 client
.transient_for
!= (BlackboxWindow
*) ~0ul)
1566 return client
.transient_for
;
1572 * This function is responsible for updating both the client and the frame
1574 * According to the ICCCM a client message is not sent for a resize, only a
1577 void BlackboxWindow::configure(int dx
, int dy
,
1578 unsigned int dw
, unsigned int dh
) {
1579 bool send_event
= ((frame
.rect
.x() != dx
|| frame
.rect
.y() != dy
) &&
1582 if (dw
!= frame
.rect
.width() || dh
!= frame
.rect
.height()) {
1583 frame
.rect
.setRect(dx
, dy
, dw
, dh
);
1584 frame
.inside_w
= frame
.rect
.width() - (frame
.border_w
* 2);
1585 frame
.inside_h
= frame
.rect
.height() - (frame
.border_w
* 2);
1587 if (frame
.rect
.right() <= 0 || frame
.rect
.bottom() <= 0)
1588 frame
.rect
.setPos(0, 0);
1590 client
.rect
.setCoords(frame
.rect
.left() + frame
.margin
.left
,
1591 frame
.rect
.top() + frame
.margin
.top
,
1592 frame
.rect
.right() - frame
.margin
.right
,
1593 frame
.rect
.bottom() - frame
.margin
.bottom
);
1596 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
1603 redrawWindowFrame();
1605 frame
.rect
.setPos(dx
, dy
);
1607 XMoveWindow(blackbox
->getXDisplay(), frame
.window
,
1608 frame
.rect
.x(), frame
.rect
.y());
1610 we may have been called just after an opaque window move, so even though
1611 the old coords match the new ones no ConfigureNotify has been sent yet.
1612 There are likely other times when this will be relevant as well.
1614 if (! flags
.moving
) send_event
= True
;
1618 // if moving, the update and event will occur when the move finishes
1619 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1620 frame
.rect
.top() + frame
.margin
.top
);
1623 event
.type
= ConfigureNotify
;
1625 event
.xconfigure
.display
= blackbox
->getXDisplay();
1626 event
.xconfigure
.event
= client
.window
;
1627 event
.xconfigure
.window
= client
.window
;
1628 event
.xconfigure
.x
= client
.rect
.x();
1629 event
.xconfigure
.y
= client
.rect
.y();
1630 event
.xconfigure
.width
= client
.rect
.width();
1631 event
.xconfigure
.height
= client
.rect
.height();
1632 event
.xconfigure
.border_width
= client
.old_bw
;
1633 event
.xconfigure
.above
= frame
.window
;
1634 event
.xconfigure
.override_redirect
= False
;
1636 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1637 StructureNotifyMask
, &event
);
1638 screen
->updateNetizenConfigNotify(&event
);
1639 XFlush(blackbox
->getXDisplay());
1645 void BlackboxWindow::configureShape(void) {
1646 XShapeCombineShape(blackbox
->getXDisplay(), frame
.window
, ShapeBounding
,
1647 frame
.margin
.left
- frame
.border_w
,
1648 frame
.margin
.top
- frame
.border_w
,
1649 client
.window
, ShapeBounding
, ShapeSet
);
1652 XRectangle xrect
[2];
1654 if (decorations
& Decor_Titlebar
) {
1655 xrect
[0].x
= xrect
[0].y
= -frame
.border_w
;
1656 xrect
[0].width
= frame
.rect
.width();
1657 xrect
[0].height
= frame
.title_h
+ (frame
.border_w
* 2);
1661 if (decorations
& Decor_Handle
) {
1662 xrect
[1].x
= -frame
.border_w
;
1663 xrect
[1].y
= frame
.rect
.height() - frame
.margin
.bottom
+
1664 frame
.mwm_border_w
- frame
.border_w
;
1665 xrect
[1].width
= frame
.rect
.width();
1666 xrect
[1].height
= frame
.handle_h
+ (frame
.border_w
* 2);
1670 XShapeCombineRectangles(blackbox
->getXDisplay(), frame
.window
,
1671 ShapeBounding
, 0, 0, xrect
, num
,
1672 ShapeUnion
, Unsorted
);
1676 void BlackboxWindow::clearShape(void) {
1677 XShapeCombineMask(blackbox
->getXDisplay(), frame
.window
, ShapeBounding
,
1678 frame
.margin
.left
- frame
.border_w
,
1679 frame
.margin
.top
- frame
.border_w
,
1685 bool BlackboxWindow::setInputFocus(void) {
1686 if (flags
.focused
) return True
;
1688 assert(flags
.stuck
|| // window must be on the current workspace or sticky
1689 blackbox_attrib
.workspace
== screen
->getCurrentWorkspaceID());
1692 We only do this check for normal windows and dialogs because other windows
1693 do this on purpose, such as kde's kicker, and we don't want to go moving
1696 if (window_type
== Type_Normal
|| window_type
== Type_Dialog
)
1697 if (! frame
.rect
.intersects(screen
->getRect())) {
1698 // client is outside the screen, move it to the center
1699 configure((screen
->getWidth() - frame
.rect
.width()) / 2,
1700 (screen
->getHeight() - frame
.rect
.height()) / 2,
1701 frame
.rect
.width(), frame
.rect
.height());
1704 if (client
.transientList
.size() > 0) {
1705 // transfer focus to any modal transients
1706 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1707 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1708 if ((*it
)->flags
.modal
) return (*it
)->setInputFocus();
1712 if (focus_mode
== F_LocallyActive
|| focus_mode
== F_Passive
) {
1713 XSetInputFocus(blackbox
->getXDisplay(), client
.window
,
1714 RevertToPointerRoot
, CurrentTime
);
1716 /* we could set the focus to none, since the window doesn't accept focus,
1717 * but we shouldn't set focus to nothing since this would surely make
1723 if (flags
.send_focus_message
) {
1725 ce
.xclient
.type
= ClientMessage
;
1726 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1727 ce
.xclient
.display
= blackbox
->getXDisplay();
1728 ce
.xclient
.window
= client
.window
;
1729 ce
.xclient
.format
= 32;
1730 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_take_focus
);
1731 ce
.xclient
.data
.l
[1] = blackbox
->getLastTime();
1732 ce
.xclient
.data
.l
[2] = 0l;
1733 ce
.xclient
.data
.l
[3] = 0l;
1734 ce
.xclient
.data
.l
[4] = 0l;
1735 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1737 XFlush(blackbox
->getXDisplay());
1744 void BlackboxWindow::iconify(void) {
1745 if (flags
.iconic
|| ! (functions
& Func_Iconify
)) return;
1747 // We don't need to worry about resizing because resizing always grabs the X
1748 // server. This should only ever happen if using opaque moving.
1752 if (windowmenu
) windowmenu
->hide();
1755 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1756 * we need to clear the event mask on client.window for a split second.
1757 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1758 * split second, leaving us with a ghost window... so, we need to do this
1759 * while the X server is grabbed
1761 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1762 StructureNotifyMask
;
1763 XGrabServer(blackbox
->getXDisplay());
1764 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1765 event_mask
& ~StructureNotifyMask
);
1766 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1767 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1768 XUngrabServer(blackbox
->getXDisplay());
1770 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1771 flags
.visible
= False
;
1772 flags
.iconic
= True
;
1774 setState(IconicState
);
1776 screen
->getWorkspace(blackbox_attrib
.workspace
)->removeWindow(this);
1778 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
1779 if (i
!= blackbox_attrib
.workspace
)
1780 screen
->getWorkspace(i
)->removeWindow(this, True
);
1783 if (isTransient()) {
1784 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1785 ! client
.transient_for
->flags
.iconic
) {
1786 // iconify our transient_for
1787 client
.transient_for
->iconify();
1791 screen
->addIcon(this);
1793 if (client
.transientList
.size() > 0) {
1794 // iconify all transients
1795 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1796 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1797 if (! (*it
)->flags
.iconic
) (*it
)->iconify();
1800 screen
->updateStackingList();
1804 void BlackboxWindow::show(void) {
1805 flags
.visible
= True
;
1806 flags
.iconic
= False
;
1808 current_state
= (flags
.shaded
) ? IconicState
: NormalState
;
1809 setState(current_state
);
1811 XMapWindow(blackbox
->getXDisplay(), client
.window
);
1812 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
1813 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
1818 XTranslateCoordinates(blackbox
->getXDisplay(), client
.window
,
1819 screen
->getRootWindow(),
1820 0, 0, &real_x
, &real_y
, &child
);
1821 fprintf(stderr
, "%s -- assumed: (%d, %d), real: (%d, %d)\n", getTitle(),
1822 client
.rect
.left(), client
.rect
.top(), real_x
, real_y
);
1823 assert(client
.rect
.left() == real_x
&& client
.rect
.top() == real_y
);
1828 void BlackboxWindow::deiconify(bool reassoc
, bool raise
) {
1829 if (flags
.iconic
|| reassoc
)
1830 screen
->reassociateWindow(this, BSENTINEL
, False
);
1831 else if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID())
1836 // reassociate and deiconify all transients
1837 if (reassoc
&& client
.transientList
.size() > 0) {
1838 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1839 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1840 (*it
)->deiconify(True
, False
);
1844 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1848 void BlackboxWindow::close(void) {
1849 if (! (functions
& Func_Close
)) return;
1852 ce
.xclient
.type
= ClientMessage
;
1853 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1854 ce
.xclient
.display
= blackbox
->getXDisplay();
1855 ce
.xclient
.window
= client
.window
;
1856 ce
.xclient
.format
= 32;
1857 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_delete_window
);
1858 ce
.xclient
.data
.l
[1] = CurrentTime
;
1859 ce
.xclient
.data
.l
[2] = 0l;
1860 ce
.xclient
.data
.l
[3] = 0l;
1861 ce
.xclient
.data
.l
[4] = 0l;
1862 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
, NoEventMask
, &ce
);
1863 XFlush(blackbox
->getXDisplay());
1867 void BlackboxWindow::withdraw(void) {
1868 // We don't need to worry about resizing because resizing always grabs the X
1869 // server. This should only ever happen if using opaque moving.
1873 flags
.visible
= False
;
1874 flags
.iconic
= False
;
1876 setState(current_state
);
1878 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1880 XGrabServer(blackbox
->getXDisplay());
1882 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1883 StructureNotifyMask
;
1884 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1885 event_mask
& ~StructureNotifyMask
);
1886 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1887 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1889 XUngrabServer(blackbox
->getXDisplay());
1891 if (windowmenu
) windowmenu
->hide();
1895 void BlackboxWindow::maximize(unsigned int button
) {
1896 if (! (functions
& Func_Maximize
)) return;
1898 // We don't need to worry about resizing because resizing always grabs the X
1899 // server. This should only ever happen if using opaque moving.
1903 // handle case where menu is open then the max button is used instead
1904 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
1906 if (flags
.maximized
) {
1907 flags
.maximized
= 0;
1909 blackbox_attrib
.flags
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1910 blackbox_attrib
.attrib
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1913 when a resize finishes, maximize(0) is called to clear any maximization
1914 flags currently set. Otherwise it still thinks it is maximized.
1915 so we do not need to call configure() because resizing will handle it
1917 if (! flags
.resizing
)
1918 configure(blackbox_attrib
.premax_x
, blackbox_attrib
.premax_y
,
1919 blackbox_attrib
.premax_w
, blackbox_attrib
.premax_h
);
1921 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
1922 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
1924 redrawAllButtons(); // in case it is not called in configure()
1925 setState(current_state
);
1929 blackbox_attrib
.premax_x
= frame
.rect
.x();
1930 blackbox_attrib
.premax_y
= frame
.rect
.y();
1931 blackbox_attrib
.premax_w
= frame
.rect
.width();
1932 // use client.rect so that clients can be restored even if shaded
1933 blackbox_attrib
.premax_h
=
1934 client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
;
1937 if (screen
->isXineramaActive() && blackbox
->doXineramaMaximizing()) {
1938 // find the area to use
1939 RectList availableAreas
= screen
->allAvailableAreas();
1940 RectList::iterator it
, end
= availableAreas
.end();
1942 for (it
= availableAreas
.begin(); it
!= end
; ++it
)
1943 if (it
->intersects(frame
.rect
)) break;
1944 if (it
== end
) // the window isn't inside an area
1945 it
= availableAreas
.begin(); // so just default to the first one
1947 frame
.changing
= *it
;
1950 frame
.changing
= screen
->availableArea();
1954 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1955 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1959 blackbox_attrib
.flags
|= AttribMaxVert
;
1960 blackbox_attrib
.attrib
|= AttribMaxVert
;
1962 frame
.changing
.setX(frame
.rect
.x());
1963 frame
.changing
.setWidth(frame
.rect
.width());
1967 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1968 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1970 frame
.changing
.setY(frame
.rect
.y());
1971 frame
.changing
.setHeight(frame
.rect
.height());
1978 blackbox_attrib
.flags
^= AttribShaded
;
1979 blackbox_attrib
.attrib
^= AttribShaded
;
1980 flags
.shaded
= False
;
1983 flags
.maximized
= button
;
1985 configure(frame
.changing
.x(), frame
.changing
.y(),
1986 frame
.changing
.width(), frame
.changing
.height());
1988 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1989 redrawAllButtons(); // in case it is not called in configure()
1990 setState(current_state
);
1994 // re-maximizes the window to take into account availableArea changes
1995 void BlackboxWindow::remaximize(void) {
1997 // we only update the window's attributes otherwise we lose the shade bit
1998 switch(flags
.maximized
) {
2000 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
2001 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
2005 blackbox_attrib
.flags
|= AttribMaxVert
;
2006 blackbox_attrib
.attrib
|= AttribMaxVert
;
2010 blackbox_attrib
.flags
|= AttribMaxHoriz
;
2011 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
2017 // save the original dimensions because maximize will wipe them out
2018 int premax_x
= blackbox_attrib
.premax_x
,
2019 premax_y
= blackbox_attrib
.premax_y
,
2020 premax_w
= blackbox_attrib
.premax_w
,
2021 premax_h
= blackbox_attrib
.premax_h
;
2023 unsigned int button
= flags
.maximized
;
2024 flags
.maximized
= 0; // trick maximize() into working
2027 // restore saved values
2028 blackbox_attrib
.premax_x
= premax_x
;
2029 blackbox_attrib
.premax_y
= premax_y
;
2030 blackbox_attrib
.premax_w
= premax_w
;
2031 blackbox_attrib
.premax_h
= premax_h
;
2035 void BlackboxWindow::setWorkspace(unsigned int n
) {
2036 blackbox_attrib
.flags
|= AttribWorkspace
;
2037 blackbox_attrib
.workspace
= n
;
2038 if (n
== BSENTINEL
) { // iconified window
2040 we set the workspace to 'all workspaces' so that taskbars will show the
2041 window. otherwise, it made uniconifying a window imposible without the
2042 blackbox workspace menu
2046 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
, n
);
2050 void BlackboxWindow::shade(void) {
2052 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
2053 frame
.inside_w
, frame
.inside_h
);
2054 flags
.shaded
= False
;
2055 blackbox_attrib
.flags
^= AttribShaded
;
2056 blackbox_attrib
.attrib
^= AttribShaded
;
2058 setState(NormalState
);
2060 // set the frame rect to the normal size
2061 frame
.rect
.setHeight(client
.rect
.height() + frame
.margin
.top
+
2062 frame
.margin
.bottom
);
2064 if (! (decorations
& Decor_Titlebar
))
2065 return; // can't shade it without a titlebar!
2067 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
2068 frame
.inside_w
, frame
.title_h
);
2069 flags
.shaded
= True
;
2070 blackbox_attrib
.flags
|= AttribShaded
;
2071 blackbox_attrib
.attrib
|= AttribShaded
;
2073 setState(IconicState
);
2075 // set the frame rect to the shaded size
2076 frame
.rect
.setHeight(frame
.title_h
+ (frame
.border_w
* 2));
2082 * (Un)Sticks a window and its relatives.
2084 void BlackboxWindow::stick(void) {
2086 blackbox_attrib
.flags
^= AttribOmnipresent
;
2087 blackbox_attrib
.attrib
^= AttribOmnipresent
;
2089 flags
.stuck
= False
;
2091 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
2092 if (i
!= blackbox_attrib
.workspace
)
2093 screen
->getWorkspace(i
)->removeWindow(this, True
);
2096 screen
->reassociateWindow(this, BSENTINEL
, True
);
2097 // temporary fix since sticky windows suck. set the hint to what we
2098 // actually hold in our data.
2099 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
2100 blackbox_attrib
.workspace
);
2102 setState(current_state
);
2106 blackbox_attrib
.flags
|= AttribOmnipresent
;
2107 blackbox_attrib
.attrib
|= AttribOmnipresent
;
2109 // temporary fix since sticky windows suck. set the hint to a different
2110 // value than that contained in the class' data.
2111 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
2114 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
2115 if (i
!= blackbox_attrib
.workspace
)
2116 screen
->getWorkspace(i
)->addWindow(this, False
, True
);
2118 setState(current_state
);
2124 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
2125 client
.transient_for
->isStuck() != flags
.stuck
)
2126 client
.transient_for
->stick();
2127 // go down the chain
2128 BlackboxWindowList::iterator it
;
2129 const BlackboxWindowList::iterator end
= client
.transientList
.end();
2130 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
2131 if ((*it
)->isStuck() != flags
.stuck
)
2136 void BlackboxWindow::redrawWindowFrame(void) const {
2137 if (decorations
& Decor_Titlebar
) {
2138 if (flags
.focused
) {
2140 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2141 frame
.title
, frame
.ftitle
);
2143 XSetWindowBackground(blackbox
->getXDisplay(),
2144 frame
.title
, frame
.ftitle_pixel
);
2147 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2148 frame
.title
, frame
.utitle
);
2150 XSetWindowBackground(blackbox
->getXDisplay(),
2151 frame
.title
, frame
.utitle_pixel
);
2153 XClearWindow(blackbox
->getXDisplay(), frame
.title
);
2159 if (decorations
& Decor_Handle
) {
2160 if (flags
.focused
) {
2162 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2163 frame
.handle
, frame
.fhandle
);
2165 XSetWindowBackground(blackbox
->getXDisplay(),
2166 frame
.handle
, frame
.fhandle_pixel
);
2169 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2170 frame
.left_grip
, frame
.fgrip
);
2171 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2172 frame
.right_grip
, frame
.fgrip
);
2174 XSetWindowBackground(blackbox
->getXDisplay(),
2175 frame
.left_grip
, frame
.fgrip_pixel
);
2176 XSetWindowBackground(blackbox
->getXDisplay(),
2177 frame
.right_grip
, frame
.fgrip_pixel
);
2181 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2182 frame
.handle
, frame
.uhandle
);
2184 XSetWindowBackground(blackbox
->getXDisplay(),
2185 frame
.handle
, frame
.uhandle_pixel
);
2188 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2189 frame
.left_grip
, frame
.ugrip
);
2190 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2191 frame
.right_grip
, frame
.ugrip
);
2193 XSetWindowBackground(blackbox
->getXDisplay(),
2194 frame
.left_grip
, frame
.ugrip_pixel
);
2195 XSetWindowBackground(blackbox
->getXDisplay(),
2196 frame
.right_grip
, frame
.ugrip_pixel
);
2199 XClearWindow(blackbox
->getXDisplay(), frame
.handle
);
2200 XClearWindow(blackbox
->getXDisplay(), frame
.left_grip
);
2201 XClearWindow(blackbox
->getXDisplay(), frame
.right_grip
);
2204 if (decorations
& Decor_Border
) {
2206 XSetWindowBorder(blackbox
->getXDisplay(),
2207 frame
.plate
, frame
.fborder_pixel
);
2209 XSetWindowBorder(blackbox
->getXDisplay(),
2210 frame
.plate
, frame
.uborder_pixel
);
2215 void BlackboxWindow::setFocusFlag(bool focus
) {
2216 // only focus a window if it is visible
2217 if (focus
&& ! flags
.visible
)
2220 flags
.focused
= focus
;
2222 redrawWindowFrame();
2225 blackbox
->setFocusedWindow(this);
2227 if (! flags
.iconic
) {
2228 // iconic windows arent in a workspace menu!
2230 screen
->getCurrentWorkspace()->setFocused(this, isFocused());
2232 screen
->getWorkspace(blackbox_attrib
.workspace
)->
2233 setFocused(this, flags
.focused
);
2238 void BlackboxWindow::installColormap(bool install
) {
2239 int i
= 0, ncmap
= 0;
2240 Colormap
*cmaps
= XListInstalledColormaps(blackbox
->getXDisplay(),
2241 client
.window
, &ncmap
);
2243 XWindowAttributes wattrib
;
2244 if (XGetWindowAttributes(blackbox
->getXDisplay(),
2245 client
.window
, &wattrib
)) {
2247 // install the window's colormap
2248 for (i
= 0; i
< ncmap
; i
++) {
2249 if (*(cmaps
+ i
) == wattrib
.colormap
)
2250 // this window is using an installed color map... do not install
2253 // otherwise, install the window's colormap
2255 XInstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2257 // uninstall the window's colormap
2258 for (i
= 0; i
< ncmap
; i
++) {
2259 if (*(cmaps
+ i
) == wattrib
.colormap
)
2260 // we found the colormap to uninstall
2261 XUninstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2271 void BlackboxWindow::setAllowedActions(void) {
2275 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_shade
);
2276 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_change_desktop
);
2277 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_close
);
2279 if (functions
& Func_Move
)
2280 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_move
);
2281 if (functions
& Func_Resize
)
2282 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_resize
);
2283 if (functions
& Func_Maximize
) {
2284 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_horz
);
2285 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_vert
);
2288 xatom
->setValue(client
.window
, XAtom::net_wm_allowed_actions
, XAtom::atom
,
2293 void BlackboxWindow::setState(unsigned long new_state
) {
2294 current_state
= new_state
;
2296 unsigned long state
[2];
2297 state
[0] = current_state
;
2299 xatom
->setValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
, state
, 2);
2301 xatom
->setValue(client
.window
, XAtom::blackbox_attributes
,
2302 XAtom::blackbox_attributes
, (unsigned long *)&blackbox_attrib
,
2303 PropBlackboxAttributesElements
);
2308 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_modal
);
2310 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_shaded
);
2312 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_hidden
);
2313 if (flags
.skip_taskbar
)
2314 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
);
2315 if (flags
.skip_pager
)
2316 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_pager
);
2317 if (flags
.fullscreen
)
2318 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_fullscreen
);
2319 if (flags
.maximized
== 1 || flags
.maximized
== 2)
2320 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_vert
);
2321 if (flags
.maximized
== 1 || flags
.maximized
== 3)
2322 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_horz
);
2323 xatom
->setValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
2328 bool BlackboxWindow::getState(void) {
2329 bool ret
= xatom
->getValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
,
2331 if (! ret
) current_state
= 0;
2336 void BlackboxWindow::restoreAttributes(void) {
2337 unsigned long num
= PropBlackboxAttributesElements
;
2338 BlackboxAttributes
*net
;
2339 if (! xatom
->getValue(client
.window
, XAtom::blackbox_attributes
,
2340 XAtom::blackbox_attributes
, num
,
2341 (unsigned long **)&net
))
2343 if (num
< PropBlackboxAttributesElements
) {
2348 if (net
->flags
& AttribShaded
&& net
->attrib
& AttribShaded
) {
2349 flags
.shaded
= False
;
2350 unsigned long orig_state
= current_state
;
2354 At this point in the life of a window, current_state should only be set
2355 to IconicState if the window was an *icon*, not if it was shaded.
2357 if (orig_state
!= IconicState
)
2358 current_state
= WithdrawnState
;
2361 if (net
->workspace
!= screen
->getCurrentWorkspaceID() &&
2362 net
->workspace
< screen
->getWorkspaceCount())
2363 screen
->reassociateWindow(this, net
->workspace
, True
);
2365 if ((blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID()) &&
2366 (blackbox_attrib
.workspace
< screen
->getWorkspaceCount())) {
2367 // set to WithdrawnState so it will be mapped on the new workspace
2368 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2369 } else if (current_state
== WithdrawnState
) {
2370 // the window is on this workspace and is Withdrawn, so it is waiting to
2372 current_state
= NormalState
;
2375 if (net
->flags
& AttribOmnipresent
&& net
->attrib
& AttribOmnipresent
&&
2379 // if the window was on another workspace, it was going to be hidden. this
2380 // specifies that the window should be mapped since it is sticky.
2381 if (current_state
== WithdrawnState
) current_state
= NormalState
;
2384 if (net
->flags
& AttribMaxHoriz
|| net
->flags
& AttribMaxVert
) {
2385 int x
= net
->premax_x
, y
= net
->premax_y
;
2386 unsigned int w
= net
->premax_w
, h
= net
->premax_h
;
2387 flags
.maximized
= 0;
2390 if ((net
->flags
& AttribMaxHoriz
) &&
2391 (net
->flags
& AttribMaxVert
))
2392 m
= (net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
2393 else if (net
->flags
& AttribMaxVert
)
2394 m
= (net
->attrib
& AttribMaxVert
) ? 2 : 0;
2395 else if (net
->flags
& AttribMaxHoriz
)
2396 m
= (net
->attrib
& AttribMaxHoriz
) ? 3 : 0;
2400 blackbox_attrib
.premax_x
= x
;
2401 blackbox_attrib
.premax_y
= y
;
2402 blackbox_attrib
.premax_w
= w
;
2403 blackbox_attrib
.premax_h
= h
;
2406 if (net
->flags
& AttribDecoration
) {
2407 switch (net
->decoration
) {
2412 /* since tools only let you toggle this anyways, we'll just make that all
2413 it supports for now.
2424 // with the state set it will then be the map event's job to read the
2425 // window's state and behave accordingly
2432 * Positions the Rect r according the the client window position and
2435 void BlackboxWindow::applyGravity(Rect
&r
) {
2436 // apply horizontal window gravity
2437 switch (client
.win_gravity
) {
2439 case NorthWestGravity
:
2440 case SouthWestGravity
:
2442 r
.setX(client
.rect
.x());
2448 r
.setX(client
.rect
.x() - (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2451 case NorthEastGravity
:
2452 case SouthEastGravity
:
2454 r
.setX(client
.rect
.x() - frame
.margin
.left
- frame
.margin
.right
+ 2);
2459 r
.setX(client
.rect
.x() - frame
.margin
.left
);
2463 // apply vertical window gravity
2464 switch (client
.win_gravity
) {
2466 case NorthWestGravity
:
2467 case NorthEastGravity
:
2469 r
.setY(client
.rect
.y());
2475 r
.setY(client
.rect
.y() - (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2478 case SouthWestGravity
:
2479 case SouthEastGravity
:
2481 r
.setY(client
.rect
.y() - frame
.margin
.top
- frame
.margin
.bottom
+ 2);
2486 r
.setY(client
.rect
.y() - frame
.margin
.top
);
2493 * The reverse of the applyGravity function.
2495 * Positions the Rect r according to the frame window position and
2498 void BlackboxWindow::restoreGravity(Rect
&r
) {
2499 // restore horizontal window gravity
2500 switch (client
.win_gravity
) {
2502 case NorthWestGravity
:
2503 case SouthWestGravity
:
2505 r
.setX(frame
.rect
.x());
2511 r
.setX(frame
.rect
.x() + (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2514 case NorthEastGravity
:
2515 case SouthEastGravity
:
2517 r
.setX(frame
.rect
.x() + frame
.margin
.left
+ frame
.margin
.right
- 2);
2522 r
.setX(frame
.rect
.x() + frame
.margin
.left
);
2526 // restore vertical window gravity
2527 switch (client
.win_gravity
) {
2529 case NorthWestGravity
:
2530 case NorthEastGravity
:
2532 r
.setY(frame
.rect
.y());
2538 r
.setY(frame
.rect
.y() + (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2541 case SouthWestGravity
:
2542 case SouthEastGravity
:
2544 r
.setY(frame
.rect
.y() + frame
.margin
.top
+ frame
.margin
.bottom
- 2);
2549 r
.setY(frame
.rect
.y() + frame
.margin
.top
);
2555 void BlackboxWindow::redrawLabel(void) const {
2556 if (flags
.focused
) {
2558 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2559 frame
.label
, frame
.flabel
);
2561 XSetWindowBackground(blackbox
->getXDisplay(),
2562 frame
.label
, frame
.flabel_pixel
);
2565 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2566 frame
.label
, frame
.ulabel
);
2568 XSetWindowBackground(blackbox
->getXDisplay(),
2569 frame
.label
, frame
.ulabel_pixel
);
2571 XClearWindow(blackbox
->getXDisplay(), frame
.label
);
2573 WindowStyle
*style
= screen
->getWindowStyle();
2575 int pos
= frame
.bevel_w
* 2;
2576 style
->doJustify(client
.title
.c_str(), pos
, frame
.label_w
, frame
.bevel_w
* 4);
2577 style
->font
->drawString(frame
.label
, pos
, 1,
2578 (flags
.focused
? style
->l_text_focus
:
2579 style
->l_text_unfocus
),
2584 void BlackboxWindow::redrawAllButtons(void) const {
2585 if (frame
.iconify_button
) redrawIconifyButton(False
);
2586 if (frame
.maximize_button
) redrawMaximizeButton(flags
.maximized
);
2587 if (frame
.close_button
) redrawCloseButton(False
);
2588 if (frame
.stick_button
) redrawStickyButton(flags
.stuck
);
2592 void BlackboxWindow::redrawIconifyButton(bool pressed
) const {
2594 if (flags
.focused
) {
2596 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2597 frame
.iconify_button
, frame
.fbutton
);
2599 XSetWindowBackground(blackbox
->getXDisplay(),
2600 frame
.iconify_button
, frame
.fbutton_pixel
);
2603 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2604 frame
.iconify_button
, frame
.ubutton
);
2606 XSetWindowBackground(blackbox
->getXDisplay(), frame
.iconify_button
,
2607 frame
.ubutton_pixel
);
2611 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2612 frame
.iconify_button
, frame
.pbutton
);
2614 XSetWindowBackground(blackbox
->getXDisplay(),
2615 frame
.iconify_button
, frame
.pbutton_pixel
);
2618 XClearWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
2619 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2620 screen
->getWindowStyle()->b_pic_unfocus
);
2621 #ifdef BITMAPBUTTONS
2622 PixmapMask pm
= screen
->getWindowStyle()->icon_button
;
2624 if (screen
->getWindowStyle()->icon_button
.mask
!= None
) {
2625 XSetClipMask(blackbox
->getXDisplay(), pen
.gc(), pm
.mask
);
2626 XSetClipOrigin(blackbox
->getXDisplay(), pen
.gc(),
2627 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2);
2629 XFillRectangle(blackbox
->getXDisplay(), frame
.iconify_button
, pen
.gc(),
2630 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2,
2631 (frame
.button_w
+ pm
.w
)/2, (frame
.button_w
+ pm
.h
)/2);
2633 XSetClipMask(blackbox
->getXDisplay(), pen
.gc(), None
);
2634 XSetClipOrigin(blackbox
->getXDisplay(), pen
.gc(), 0, 0);
2636 #endif // BITMAPBUTTONS
2637 XDrawRectangle(blackbox
->getXDisplay(), frame
.iconify_button
, pen
.gc(),
2638 2, (frame
.button_w
- 5), (frame
.button_w
- 5), 2);
2639 #ifdef BITMAPBUTTONS
2641 #endif // BITMAPBUTTONS
2645 void BlackboxWindow::redrawMaximizeButton(bool pressed
) const {
2647 if (flags
.focused
) {
2649 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2650 frame
.maximize_button
, frame
.fbutton
);
2652 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2653 frame
.fbutton_pixel
);
2656 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2657 frame
.maximize_button
, frame
.ubutton
);
2659 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2660 frame
.ubutton_pixel
);
2664 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2665 frame
.maximize_button
, frame
.pbutton
);
2667 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2668 frame
.pbutton_pixel
);
2670 XClearWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
2672 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2673 screen
->getWindowStyle()->b_pic_unfocus
);
2675 #ifdef BITMAPBUTTONS
2676 PixmapMask pm
= screen
->getWindowStyle()->max_button
;
2678 if (pm
.mask
!= None
) {
2679 XSetClipMask(blackbox
->getXDisplay(), pen
.gc(), pm
.mask
);
2680 XSetClipOrigin(blackbox
->getXDisplay(), pen
.gc(),
2681 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2);
2683 XFillRectangle(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2684 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2,
2685 (frame
.button_w
+ pm
.w
)/2, (frame
.button_w
+ pm
.h
)/2);
2687 XSetClipOrigin(blackbox
->getXDisplay(), pen
.gc(), 0, 0 );
2688 XSetClipMask( blackbox
->getXDisplay(), pen
.gc(), None
);
2690 #endif // BITMAPBUTTONS
2691 XDrawRectangle(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2692 2, 2, (frame
.button_w
- 5), (frame
.button_w
- 5));
2693 XDrawLine(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2694 2, 3, (frame
.button_w
- 3), 3);
2695 #ifdef BITMAPBUTTONS
2697 #endif // BITMAPBUTTONS
2701 void BlackboxWindow::redrawCloseButton(bool pressed
) const {
2703 if (flags
.focused
) {
2705 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2706 frame
.close_button
, frame
.fbutton
);
2708 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2709 frame
.fbutton_pixel
);
2712 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2715 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2716 frame
.ubutton_pixel
);
2720 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2721 frame
.close_button
, frame
.pbutton
);
2723 XSetWindowBackground(blackbox
->getXDisplay(),
2724 frame
.close_button
, frame
.pbutton_pixel
);
2726 XClearWindow(blackbox
->getXDisplay(), frame
.close_button
);
2728 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2729 screen
->getWindowStyle()->b_pic_unfocus
);
2731 #ifdef BITMAPBUTTONS
2732 PixmapMask pm
= screen
->getWindowStyle()->close_button
;
2734 if (pm
.mask
!= None
) {
2735 XSetClipMask(blackbox
->getXDisplay(), pen
.gc(), pm
.mask
);
2736 XSetClipOrigin(blackbox
->getXDisplay(), pen
.gc(),
2737 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2);
2739 XFillRectangle(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2740 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2,
2741 (frame
.button_w
+ pm
.w
)/2, (frame
.button_w
+ pm
.h
)/2);
2744 XSetClipOrigin(blackbox
->getXDisplay(), pen
.gc(), 0, 0 );
2745 XSetClipMask( blackbox
->getXDisplay(), pen
.gc(), None
);
2747 #endif // BITMAPBUTTONS
2748 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2749 2, 2, (frame
.button_w
- 3), (frame
.button_w
- 3));
2750 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2751 2, (frame
.button_w
- 3), (frame
.button_w
- 3), 2);
2752 #ifdef BITMAPBUTTONS
2754 #endif // BITMAPBUTTONS
2757 void BlackboxWindow::redrawStickyButton(bool pressed
) const {
2759 if (flags
.focused
) {
2761 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2762 frame
.stick_button
, frame
.fbutton
);
2764 XSetWindowBackground(blackbox
->getXDisplay(), frame
.stick_button
,
2765 frame
.fbutton_pixel
);
2768 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2769 frame
.stick_button
, frame
.ubutton
);
2771 XSetWindowBackground(blackbox
->getXDisplay(), frame
.stick_button
,
2772 frame
.ubutton_pixel
);
2776 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2777 frame
.stick_button
, frame
.pbutton
);
2779 XSetWindowBackground(blackbox
->getXDisplay(), frame
.stick_button
,
2780 frame
.pbutton_pixel
);
2782 XClearWindow(blackbox
->getXDisplay(), frame
.stick_button
);
2784 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2785 screen
->getWindowStyle()->b_pic_unfocus
);
2787 #ifdef BITMAPBUTTONS
2788 PixmapMask pm
= screen
->getWindowStyle()->stick_button
;
2790 if (pm
.mask
!= None
) {
2791 XSetClipMask(blackbox
->getXDisplay(), pen
.gc(), pm
.mask
);
2792 XSetClipOrigin(blackbox
->getXDisplay(), pen
.gc(),
2793 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2);
2795 XFillRectangle(blackbox
->getXDisplay(), frame
.stick_button
, pen
.gc(),
2796 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2,
2797 (frame
.button_w
+ pm
.w
)/2, (frame
.button_w
+ pm
.h
)/2);
2800 XSetClipOrigin(blackbox
->getXDisplay(), pen
.gc(), 0, 0 );
2801 XSetClipMask( blackbox
->getXDisplay(), pen
.gc(), None
);
2803 #endif // BITMAPBUTTONS
2804 XFillRectangle(blackbox
->getXDisplay(), frame
.stick_button
, pen
.gc(),
2805 frame
.button_w
/2 - 1, frame
.button_w
/2 -1, 2, 2 );
2806 #ifdef BITMAPBUTTONS
2811 void BlackboxWindow::mapRequestEvent(const XMapRequestEvent
*re
) {
2812 if (re
->window
!= client
.window
)
2816 fprintf(stderr
, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2821 Even though the window wants to be shown, if it is not on the current
2822 workspace, then it isn't going to be shown right now.
2824 if (! flags
.stuck
&&
2825 blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID() &&
2826 blackbox_attrib
.workspace
< screen
->getWorkspaceCount())
2827 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2829 switch (current_state
) {
2834 case WithdrawnState
:
2843 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2845 if (! blackbox
->isStartup()) {
2846 XSync(blackbox
->getXDisplay(), False
); // make sure the frame is mapped
2847 if (screen
->doFocusNew() || (isTransient() && getTransientFor() &&
2848 getTransientFor()->isFocused())) {
2851 if (screen
->getPlacementPolicy() == BScreen::ClickMousePlacement
) {
2855 XQueryPointer(blackbox
->getXDisplay(), screen
->getRootWindow(),
2856 &r
, &c
, &rx
, &ry
, &x
, &y
, &m
);
2866 void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent
*ue
) {
2867 if (ue
->window
!= client
.window
)
2871 fprintf(stderr
, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2875 screen
->unmanageWindow(this, False
);
2879 void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent
*de
) {
2880 if (de
->window
!= client
.window
)
2884 fprintf(stderr
, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2888 screen
->unmanageWindow(this, False
);
2892 void BlackboxWindow::reparentNotifyEvent(const XReparentEvent
*re
) {
2893 if (re
->window
!= client
.window
|| re
->parent
== frame
.plate
)
2897 fprintf(stderr
, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2898 "0x%lx.\n", client
.window
, re
->parent
);
2903 XPutBackEvent(blackbox
->getXDisplay(), &ev
);
2904 screen
->unmanageWindow(this, True
);
2908 void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent
*pe
) {
2909 if (pe
->state
== PropertyDelete
|| ! validateClient())
2913 fprintf(stderr
, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n",
2919 case XA_WM_CLIENT_MACHINE
:
2923 case XA_WM_TRANSIENT_FOR
: {
2924 bool s
= flags
.stuck
;
2926 // determine if this is a transient window
2929 if (flags
.stuck
!= s
) stick();
2931 // adjust the window decorations based on transience
2932 if (isTransient()) {
2933 functions
&= ~Func_Maximize
;
2934 setAllowedActions();
2946 case XA_WM_ICON_NAME
:
2948 if (flags
.iconic
) screen
->propagateWindowName(this);
2951 case XAtom::net_wm_name
:
2955 if (decorations
& Decor_Titlebar
)
2958 screen
->propagateWindowName(this);
2961 case XA_WM_NORMAL_HINTS
: {
2964 if ((client
.normal_hint_flags
& PMinSize
) &&
2965 (client
.normal_hint_flags
& PMaxSize
)) {
2966 // the window now can/can't resize itself, so the buttons need to be
2969 if (client
.max_width
<= client
.min_width
&&
2970 client
.max_height
<= client
.min_height
) {
2971 functions
&= ~(Func_Resize
| Func_Maximize
);
2973 if (! isTransient())
2974 functions
|= Func_Maximize
;
2975 functions
|= Func_Resize
;
2978 setAllowedActions();
2982 Rect old_rect
= frame
.rect
;
2986 if (old_rect
!= frame
.rect
)
2993 if (pe
->atom
== xatom
->getAtom(XAtom::wm_protocols
)) {
2996 if ((decorations
& Decor_Close
) && (! frame
.close_button
)) {
2997 createCloseButton();
2998 if (decorations
& Decor_Titlebar
) {
2999 positionButtons(True
);
3000 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
3002 if (windowmenu
) windowmenu
->reconfigure();
3004 } else if (pe
->atom
== xatom
->getAtom(XAtom::net_wm_strut
)) {
3013 void BlackboxWindow::exposeEvent(const XExposeEvent
*ee
) {
3015 fprintf(stderr
, "BlackboxWindow::exposeEvent() for 0x%lx\n", client
.window
);
3018 if (frame
.label
== ee
->window
&& (decorations
& Decor_Titlebar
))
3020 else if (frame
.close_button
== ee
->window
)
3021 redrawCloseButton(False
);
3022 else if (frame
.maximize_button
== ee
->window
)
3023 redrawMaximizeButton(flags
.maximized
);
3024 else if (frame
.iconify_button
== ee
->window
)
3025 redrawIconifyButton(False
);
3026 else if (frame
.stick_button
== ee
->window
)
3027 redrawStickyButton(flags
.stuck
);
3031 void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent
*cr
) {
3032 if (cr
->window
!= client
.window
|| flags
.iconic
)
3035 if (cr
->value_mask
& CWBorderWidth
)
3036 client
.old_bw
= cr
->border_width
;
3038 if (cr
->value_mask
& (CWX
| CWY
| CWWidth
| CWHeight
)) {
3039 frame
.changing
= frame
.rect
;
3041 if (cr
->value_mask
& (CWX
| CWY
)) {
3042 if (cr
->value_mask
& CWX
)
3043 client
.rect
.setX(cr
->x
);
3044 if (cr
->value_mask
& CWY
)
3045 client
.rect
.setY(cr
->y
);
3047 applyGravity(frame
.changing
);
3050 if (cr
->value_mask
& (CWWidth
| CWHeight
)) {
3051 if (cr
->value_mask
& CWWidth
)
3052 frame
.changing
.setWidth(cr
->width
+
3053 frame
.margin
.left
+ frame
.margin
.right
);
3055 if (cr
->value_mask
& CWHeight
)
3056 frame
.changing
.setHeight(cr
->height
+
3057 frame
.margin
.top
+ frame
.margin
.bottom
);
3060 if a position change has been specified, then that position will be
3061 used instead of determining a position based on the window's gravity.
3063 if (! (cr
->value_mask
& (CWX
| CWY
))) {
3065 switch (client
.win_gravity
) {
3066 case NorthEastGravity
:
3070 case SouthWestGravity
:
3072 corner
= BottomLeft
;
3074 case SouthEastGravity
:
3075 corner
= BottomRight
;
3077 default: // NorthWest, Static, etc
3084 configure(frame
.changing
.x(), frame
.changing
.y(),
3085 frame
.changing
.width(), frame
.changing
.height());
3088 if (cr
->value_mask
& CWStackMode
&& !isDesktop()) {
3089 switch (cr
->detail
) {
3092 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
3098 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3105 void BlackboxWindow::buttonPressEvent(const XButtonEvent
*be
) {
3107 fprintf(stderr
, "BlackboxWindow::buttonPressEvent() for 0x%lx\n",
3111 if (frame
.maximize_button
== be
->window
&& be
->button
<= 3) {
3112 redrawMaximizeButton(True
);
3113 } else if (be
->button
== 1 || (be
->button
== 3 && be
->state
== mod_mask
)) {
3114 if (! flags
.focused
)
3117 if (frame
.iconify_button
== be
->window
) {
3118 redrawIconifyButton(True
);
3119 } else if (frame
.close_button
== be
->window
) {
3120 redrawCloseButton(True
);
3121 } else if (frame
.stick_button
== be
->window
) {
3122 redrawStickyButton(True
);
3123 } else if (frame
.plate
== be
->window
) {
3124 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
3126 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3128 XAllowEvents(blackbox
->getXDisplay(), ReplayPointer
, be
->time
);
3130 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
3131 if (((be
->time
- lastButtonPressTime
) <=
3132 blackbox
->getDoubleClickInterval()) ||
3133 (be
->state
== ControlMask
)) {
3134 lastButtonPressTime
= 0;
3137 lastButtonPressTime
= be
->time
;
3141 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
3143 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3145 } else if (be
->button
== 2 && (be
->window
!= frame
.iconify_button
) &&
3146 (be
->window
!= frame
.close_button
) &&
3147 (be
->window
!= frame
.stick_button
)) {
3148 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
3149 } else if (windowmenu
&& be
->button
== 3 &&
3150 (frame
.title
== be
->window
|| frame
.label
== be
->window
||
3151 frame
.handle
== be
->window
|| frame
.window
== be
->window
)) {
3152 if (windowmenu
->isVisible()) {
3155 int mx
= be
->x_root
- windowmenu
->getWidth() / 2,
3156 my
= be
->y_root
- windowmenu
->getHeight() / 2;
3158 // snap the window menu into a corner/side if necessary
3159 int left_edge
, right_edge
, top_edge
, bottom_edge
;
3162 the " + (frame.border_w * 2) - 1" bits are to get the proper width
3163 and height of the menu, as the sizes returned by it do not include
3166 left_edge
= frame
.rect
.x();
3167 right_edge
= frame
.rect
.right() -
3168 (windowmenu
->getWidth() + (frame
.border_w
* 2) - 1);
3169 top_edge
= client
.rect
.top() - (frame
.border_w
+ frame
.mwm_border_w
);
3170 bottom_edge
= client
.rect
.bottom() -
3171 (windowmenu
->getHeight() + (frame
.border_w
* 2) - 1) +
3172 (frame
.border_w
+ frame
.mwm_border_w
);
3176 else if (mx
> right_edge
)
3180 else if (my
> bottom_edge
)
3183 if (my
+ windowmenu
->getHeight() > screen
->getHeight())
3184 my
= screen
->getHeight() - windowmenu
->getHeight() -
3185 (screen
->getBorderWidth() * 2);
3187 windowmenu
->move(mx
, my
);
3189 XRaiseWindow(blackbox
->getXDisplay(), windowmenu
->getWindowID());
3190 XRaiseWindow(blackbox
->getXDisplay(),
3191 windowmenu
->getSendToMenu()->getWindowID());
3194 } else if (be
->button
== 4) {
3195 if ((be
->window
== frame
.label
||
3196 be
->window
== frame
.title
||
3197 be
->window
== frame
.maximize_button
||
3198 be
->window
== frame
.iconify_button
||
3199 be
->window
== frame
.close_button
||
3200 be
->window
== frame
.stick_button
) &&
3204 } else if (be
->button
== 5) {
3205 if ((be
->window
== frame
.label
||
3206 be
->window
== frame
.title
||
3207 be
->window
== frame
.maximize_button
||
3208 be
->window
== frame
.iconify_button
||
3209 be
->window
== frame
.close_button
||
3210 be
->window
== frame
.stick_button
) &&
3217 void BlackboxWindow::buttonReleaseEvent(const XButtonEvent
*re
) {
3219 fprintf(stderr
, "BlackboxWindow::buttonReleaseEvent() for 0x%lx\n",
3223 if (re
->window
== frame
.maximize_button
&&
3224 re
->button
>= 1 && re
->button
<= 3) {
3225 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3226 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
3227 maximize(re
->button
);
3229 redrawMaximizeButton(flags
.maximized
);
3231 } else if (re
->window
== frame
.iconify_button
&& re
->button
== 1) {
3232 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3233 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
3236 redrawIconifyButton(False
);
3238 } else if (re
->window
== frame
.stick_button
&& re
->button
== 1) {
3239 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3240 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
3243 redrawStickyButton(False
);
3245 } else if (re
->window
== frame
.close_button
& re
->button
== 1) {
3246 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3247 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
)))
3249 redrawCloseButton(False
);
3250 } else if (flags
.moving
) {
3252 } else if (flags
.resizing
) {
3254 } else if (re
->window
== frame
.window
) {
3255 if (re
->button
== 2 && re
->state
== mod_mask
)
3256 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3262 void BlackboxWindow::beginMove(int x_root
, int y_root
) {
3263 if (! (functions
& Func_Move
)) return;
3265 assert(! (flags
.resizing
|| flags
.moving
));
3268 Only one window can be moved/resized at a time. If another window is already
3269 being moved or resized, then stop it before whating to work with this one.
3271 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3272 if (changing
&& changing
!= this) {
3273 if (changing
->flags
.moving
)
3274 changing
->endMove();
3275 else // if (changing->flags.resizing)
3276 changing
->endResize();
3279 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3280 PointerMotionMask
| ButtonReleaseMask
,
3281 GrabModeAsync
, GrabModeAsync
,
3282 None
, blackbox
->getMoveCursor(), CurrentTime
);
3284 if (windowmenu
&& windowmenu
->isVisible())
3287 flags
.moving
= True
;
3288 blackbox
->setChangingWindow(this);
3290 if (! screen
->doOpaqueMove()) {
3291 XGrabServer(blackbox
->getXDisplay());
3293 frame
.changing
= frame
.rect
;
3294 screen
->showPosition(frame
.changing
.x(), frame
.changing
.y());
3296 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3300 frame
.changing
.width() - 1,
3301 frame
.changing
.height() - 1);
3304 frame
.grab_x
= x_root
- frame
.rect
.x() - frame
.border_w
;
3305 frame
.grab_y
= y_root
- frame
.rect
.y() - frame
.border_w
;
3309 void BlackboxWindow::doMove(int x_root
, int y_root
) {
3310 assert(flags
.moving
);
3311 assert(blackbox
->getChangingWindow() == this);
3313 int dx
= x_root
- frame
.grab_x
, dy
= y_root
- frame
.grab_y
;
3314 dx
-= frame
.border_w
;
3315 dy
-= frame
.border_w
;
3317 doWindowSnapping(dx
, dy
);
3319 if (screen
->doOpaqueMove()) {
3320 if (screen
->doWorkspaceWarping())
3321 doWorkspaceWarping(x_root
, y_root
, dx
);
3323 configure(dx
, dy
, frame
.rect
.width(), frame
.rect
.height());
3325 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3329 frame
.changing
.width() - 1,
3330 frame
.changing
.height() - 1);
3332 if (screen
->doWorkspaceWarping())
3333 doWorkspaceWarping(x_root
, y_root
, dx
);
3335 frame
.changing
.setPos(dx
, dy
);
3337 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3341 frame
.changing
.width() - 1,
3342 frame
.changing
.height() - 1);
3345 screen
->showPosition(dx
, dy
);
3349 void BlackboxWindow::doWorkspaceWarping(int x_root
, int y_root
, int &dx
) {
3350 // workspace warping
3352 unsigned int dest
= screen
->getCurrentWorkspaceID();
3356 if (dest
> 0) dest
--;
3357 else dest
= screen
->getNumberOfWorkspaces() - 1;
3359 } else if (x_root
>= screen
->getRect().right()) {
3362 if (dest
< screen
->getNumberOfWorkspaces() - 1) dest
++;
3368 bool focus
= flags
.focused
; // had focus while moving?
3370 int dest_x
= x_root
;
3372 dest_x
+= screen
->getRect().width() - 1;
3373 dx
+= screen
->getRect().width() - 1;
3375 dest_x
-= screen
->getRect().width() - 1;
3376 dx
-= screen
->getRect().width() - 1;
3380 screen
->reassociateWindow(this, dest
, False
);
3381 screen
->changeWorkspaceID(dest
);
3383 if (screen
->doOpaqueMove())
3384 XGrabServer(blackbox
->getXDisplay());
3386 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3387 XWarpPointer(blackbox
->getXDisplay(), None
,
3388 screen
->getRootWindow(), 0, 0, 0, 0,
3390 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3391 PointerMotionMask
| ButtonReleaseMask
,
3392 GrabModeAsync
, GrabModeAsync
,
3393 None
, blackbox
->getMoveCursor(), CurrentTime
);
3395 if (screen
->doOpaqueMove())
3396 XUngrabServer(blackbox
->getXDisplay());
3404 void BlackboxWindow::doWindowSnapping(int &dx
, int &dy
) {
3405 // how much resistance to edges to provide
3406 const int resistance_size
= screen
->getResistanceSize();
3408 // how far away to snap
3409 const int snap_distance
= screen
->getSnapThreshold();
3411 // how to snap windows
3412 const int snap_to_windows
= screen
->getWindowToWindowSnap();
3413 const int snap_to_edges
= screen
->getWindowToEdgeSnap();
3414 // the amount of space away from the edge to provide resistance/snap
3415 const int snap_offset
= screen
->getSnapOffset();
3417 // find the geomeetery where the moving window currently is
3418 const Rect
&moving
= screen
->doOpaqueMove() ? frame
.rect
: frame
.changing
;
3421 const int wleft
= dx
,
3422 wright
= dx
+ frame
.rect
.width() - 1,
3424 wbottom
= dy
+ frame
.rect
.height() - 1;
3426 if (snap_to_windows
) {
3429 Workspace
*w
= screen
->getWorkspace(getWorkspaceNumber());
3432 // add windows on the workspace to the rect list
3433 const BlackboxWindowList
& stack_list
= w
->getStackingList();
3434 BlackboxWindowList::const_iterator st_it
, st_end
= stack_list
.end();
3435 for (st_it
= stack_list
.begin(); st_it
!= st_end
; ++st_it
)
3436 if (*st_it
!= this) // don't snap to ourself
3437 rectlist
.push_back( (*st_it
)->frameRect() );
3439 // add the toolbar and the slit to the rect list.
3440 // (only if they are not hidden)
3441 Toolbar
*tbar
= screen
->getToolbar();
3442 Slit
*slit
= screen
->getSlit();
3443 Rect tbar_rect
, slit_rect
;
3444 unsigned int bwidth
= screen
->getBorderWidth() * 2;
3446 if (! (screen
->doHideToolbar() || tbar
->isHidden())) {
3447 tbar_rect
.setRect(tbar
->getX(), tbar
->getY(), tbar
->getWidth() + bwidth
,
3448 tbar
->getHeight() + bwidth
);
3449 rectlist
.push_back(tbar_rect
);
3452 if (! slit
->isHidden()) {
3453 slit_rect
.setRect(slit
->getX(), slit
->getY(), slit
->getWidth() + bwidth
,
3454 slit
->getHeight() + bwidth
);
3455 rectlist
.push_back(slit_rect
);
3458 RectList::const_iterator it
, end
= rectlist
.end();
3459 for (it
= rectlist
.begin(); it
!= end
; ++it
) {
3460 bool snapped
= False
;
3461 const Rect
&winrect
= *it
;
3463 offsetrect
.setCoords(winrect
.left() - snap_offset
,
3464 winrect
.top() - snap_offset
,
3465 winrect
.right() + snap_offset
,
3466 winrect
.bottom() + snap_offset
);
3468 if (snap_to_windows
== BScreen::WindowResistance
)
3469 // if the window is already over top of this snap target, then
3470 // resistance is futile, so just ignore it
3471 if (winrect
.intersects(moving
))
3474 int dleft
, dright
, dtop
, dbottom
;
3476 // if the windows are in the same plane vertically
3477 if (wtop
>= (signed)(winrect
.y() - frame
.rect
.height() + 1) &&
3478 wtop
< (signed)(winrect
.y() + winrect
.height() - 1)) {
3480 if (snap_to_windows
== BScreen::WindowResistance
) {
3481 dleft
= wright
- offsetrect
.left();
3482 dright
= offsetrect
.right() - wleft
;
3484 // snap left of other window?
3485 if (dleft
>= 0 && dleft
< resistance_size
&&
3486 dleft
< (wright
- wleft
)) {
3487 dx
= offsetrect
.left() - frame
.rect
.width();
3490 // snap right of other window?
3491 else if (dright
>= 0 && dright
< resistance_size
&&
3492 dright
< (wright
- wleft
)) {
3493 dx
= offsetrect
.right() + 1;
3496 } else { // BScreen::WindowSnap
3497 dleft
= abs(wright
- offsetrect
.left());
3498 dright
= abs(wleft
- offsetrect
.right());
3500 // snap left of other window?
3501 if (dleft
< snap_distance
&& dleft
<= dright
) {
3502 dx
= offsetrect
.left() - frame
.rect
.width();
3505 // snap right of other window?
3506 else if (dright
< snap_distance
) {
3507 dx
= offsetrect
.right() + 1;
3513 if (screen
->getWindowCornerSnap()) {
3514 // try corner-snap to its other sides
3515 if (snap_to_windows
== BScreen::WindowResistance
) {
3516 dtop
= winrect
.top() - wtop
;
3517 dbottom
= wbottom
- winrect
.bottom();
3518 if (dtop
> 0 && dtop
< resistance_size
) {
3519 // if we're already past the top edge, then don't provide
3521 if (moving
.top() >= winrect
.top())
3523 } else if (dbottom
> 0 && dbottom
< resistance_size
) {
3524 // if we're already past the bottom edge, then don't provide
3526 if (moving
.bottom() <= winrect
.bottom())
3527 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
3529 } else { // BScreen::WindowSnap
3530 dtop
= abs(wtop
- winrect
.top());
3531 dbottom
= abs(wbottom
- winrect
.bottom());
3532 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3534 else if (dbottom
< snap_distance
)
3535 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
3543 // if the windows are on the same plane horizontally
3544 if (wleft
>= (signed)(winrect
.x() - frame
.rect
.width() + 1) &&
3545 wleft
< (signed)(winrect
.x() + winrect
.width() - 1)) {
3547 if (snap_to_windows
== BScreen::WindowResistance
) {
3548 dtop
= wbottom
- offsetrect
.top();
3549 dbottom
= offsetrect
.bottom() - wtop
;
3551 // snap top of other window?
3552 if (dtop
>= 0 && dtop
< resistance_size
&& dtop
< (wbottom
- wtop
)) {
3553 dy
= offsetrect
.top() - frame
.rect
.height();
3556 // snap bottom of other window?
3557 else if (dbottom
>= 0 && dbottom
< resistance_size
&&
3558 dbottom
< (wbottom
- wtop
)) {
3559 dy
= offsetrect
.bottom() + 1;
3562 } else { // BScreen::WindowSnap
3563 dtop
= abs(wbottom
- offsetrect
.top());
3564 dbottom
= abs(wtop
- offsetrect
.bottom());
3566 // snap top of other window?
3567 if (dtop
< snap_distance
&& dtop
<= dbottom
) {
3568 dy
= offsetrect
.top() - frame
.rect
.height();
3571 // snap bottom of other window?
3572 else if (dbottom
< snap_distance
) {
3573 dy
= offsetrect
.bottom() + 1;
3580 if (screen
->getWindowCornerSnap()) {
3581 // try corner-snap to its other sides
3582 if (snap_to_windows
== BScreen::WindowResistance
) {
3583 dleft
= winrect
.left() - wleft
;
3584 dright
= wright
- winrect
.right();
3585 if (dleft
> 0 && dleft
< resistance_size
) {
3586 // if we're already past the left edge, then don't provide
3588 if (moving
.left() >= winrect
.left())
3589 dx
= winrect
.left();
3590 } else if (dright
> 0 && dright
< resistance_size
) {
3591 // if we're already past the right edge, then don't provide
3593 if (moving
.right() <= winrect
.right())
3594 dx
= winrect
.right() - frame
.rect
.width() + 1;
3596 } else { // BScreen::WindowSnap
3597 dleft
= abs(wleft
- winrect
.left());
3598 dright
= abs(wright
- winrect
.right());
3599 if (dleft
< snap_distance
&& dleft
<= dright
)
3600 dx
= winrect
.left();
3601 else if (dright
< snap_distance
)
3602 dx
= winrect
.right() - frame
.rect
.width() + 1;
3612 if (snap_to_edges
) {
3615 // snap to the screen edges (and screen boundaries for xinerama)
3617 if (screen
->isXineramaActive() && blackbox
->doXineramaSnapping()) {
3618 rectlist
.insert(rectlist
.begin(),
3619 screen
->getXineramaAreas().begin(),
3620 screen
->getXineramaAreas().end());
3623 rectlist
.push_back(screen
->getRect());
3625 RectList::const_iterator it
, end
= rectlist
.end();
3626 for (it
= rectlist
.begin(); it
!= end
; ++it
) {
3627 const Rect
&srect
= *it
;
3629 offsetrect
.setCoords(srect
.left() + snap_offset
,
3630 srect
.top() + snap_offset
,
3631 srect
.right() - snap_offset
,
3632 srect
.bottom() - snap_offset
);
3634 if (snap_to_edges
== BScreen::WindowResistance
) {
3635 // if we're not in the rectangle then don't snap to it.
3636 if (! srect
.contains(moving
))
3638 } else { // BScreen::WindowSnap
3639 // if we're not in the rectangle then don't snap to it.
3640 if (! srect
.intersects(Rect(wleft
, wtop
, frame
.rect
.width(),
3641 frame
.rect
.height())))
3645 if (snap_to_edges
== BScreen::WindowResistance
) {
3646 int dleft
= offsetrect
.left() - wleft
,
3647 dright
= wright
- offsetrect
.right(),
3648 dtop
= offsetrect
.top() - wtop
,
3649 dbottom
= wbottom
- offsetrect
.bottom();
3652 if (dleft
> 0 && dleft
< resistance_size
)
3653 dx
= offsetrect
.left();
3655 else if (dright
> 0 && dright
< resistance_size
)
3656 dx
= offsetrect
.right() - frame
.rect
.width() + 1;
3659 if (dtop
> 0 && dtop
< resistance_size
)
3660 dy
= offsetrect
.top();
3662 else if (dbottom
> 0 && dbottom
< resistance_size
)
3663 dy
= offsetrect
.bottom() - frame
.rect
.height() + 1;
3664 } else { // BScreen::WindowSnap
3665 int dleft
= abs(wleft
- offsetrect
.left()),
3666 dright
= abs(wright
- offsetrect
.right()),
3667 dtop
= abs(wtop
- offsetrect
.top()),
3668 dbottom
= abs(wbottom
- offsetrect
.bottom());
3671 if (dleft
< snap_distance
&& dleft
<= dright
)
3672 dx
= offsetrect
.left();
3674 else if (dright
< snap_distance
)
3675 dx
= offsetrect
.right() - frame
.rect
.width() + 1;
3678 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3679 dy
= offsetrect
.top();
3681 else if (dbottom
< snap_distance
)
3682 dy
= offsetrect
.bottom() - frame
.rect
.height() + 1;
3689 void BlackboxWindow::endMove(void) {
3690 assert(flags
.moving
);
3691 assert(blackbox
->getChangingWindow() == this);
3693 flags
.moving
= False
;
3694 blackbox
->setChangingWindow(0);
3696 if (! screen
->doOpaqueMove()) {
3697 /* when drawing the rubber band, we need to make sure we only draw inside
3698 * the frame... frame.changing_* contain the new coords for the window,
3699 * so we need to subtract 1 from changing_w/changing_h every where we
3700 * draw the rubber band (for both moving and resizing)
3702 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3703 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3704 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3705 XUngrabServer(blackbox
->getXDisplay());
3707 configure(frame
.changing
.x(), frame
.changing
.y(),
3708 frame
.changing
.width(), frame
.changing
.height());
3710 configure(frame
.rect
.x(), frame
.rect
.y(),
3711 frame
.rect
.width(), frame
.rect
.height());
3713 screen
->hideGeometry();
3715 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3717 // if there are any left over motions from the move, drop them now
3718 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3720 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3725 void BlackboxWindow::beginResize(int x_root
, int y_root
, Corner dir
) {
3726 if (! (functions
& Func_Resize
)) return;
3728 assert(! (flags
.resizing
|| flags
.moving
));
3731 Only one window can be moved/resized at a time. If another window is
3732 already being moved or resized, then stop it before whating to work with
3735 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3736 if (changing
&& changing
!= this) {
3737 if (changing
->flags
.moving
)
3738 changing
->endMove();
3739 else // if (changing->flags.resizing)
3740 changing
->endResize();
3748 switch (resize_dir
) {
3751 cursor
= blackbox
->getLowerLeftAngleCursor();
3756 cursor
= blackbox
->getLowerRightAngleCursor();
3760 anchor
= BottomRight
;
3761 cursor
= blackbox
->getUpperLeftAngleCursor();
3765 anchor
= BottomLeft
;
3766 cursor
= blackbox
->getUpperRightAngleCursor();
3770 assert(false); // unhandled Corner
3771 return; // unreachable, for the compiler
3774 XGrabServer(blackbox
->getXDisplay());
3775 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3776 PointerMotionMask
| ButtonReleaseMask
,
3777 GrabModeAsync
, GrabModeAsync
, None
, cursor
, CurrentTime
);
3779 flags
.resizing
= True
;
3780 blackbox
->setChangingWindow(this);
3782 unsigned int gw
, gh
;
3783 frame
.changing
= frame
.rect
;
3785 constrain(anchor
, &gw
, &gh
);
3787 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3788 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3789 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3791 screen
->showGeometry(gw
, gh
);
3793 frame
.grab_x
= x_root
;
3794 frame
.grab_y
= y_root
;
3798 void BlackboxWindow::doResize(int x_root
, int y_root
) {
3799 assert(flags
.resizing
);
3800 assert(blackbox
->getChangingWindow() == this);
3802 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3803 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3804 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3806 unsigned int gw
, gh
;
3808 int dx
, dy
; // the amount of change in the size of the window
3810 switch (resize_dir
) {
3813 dx
= - (x_root
- frame
.grab_x
);
3814 dy
= + (y_root
- frame
.grab_y
);
3818 dx
= + (x_root
- frame
.grab_x
);
3819 dy
= + (y_root
- frame
.grab_y
);
3822 anchor
= BottomRight
;
3823 dx
= - (x_root
- frame
.grab_x
);
3824 dy
= - (y_root
- frame
.grab_y
);
3827 anchor
= BottomLeft
;
3828 dx
= + (x_root
- frame
.grab_x
);
3829 dy
= - (y_root
- frame
.grab_y
);
3833 assert(false); // unhandled Corner
3834 return; // unreachable, for the compiler
3837 // make sure the user cant resize the window smaller than 0, which makes it
3838 // wrap around and become huge
3839 if (dx
< -(signed)client
.rect
.width()) dx
= -(signed)client
.rect
.width();
3840 if (dy
< -(signed)client
.rect
.height()) dy
= -(signed)client
.rect
.height();
3842 frame
.changing
.setSize(frame
.rect
.width() + dx
, frame
.rect
.height() + dy
);
3844 constrain(anchor
, &gw
, &gh
);
3846 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3847 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3848 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3850 screen
->showGeometry(gw
, gh
);
3854 void BlackboxWindow::endResize(void) {
3855 assert(flags
.resizing
);
3856 assert(blackbox
->getChangingWindow() == this);
3858 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3859 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3860 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3861 XUngrabServer(blackbox
->getXDisplay());
3863 // unset maximized state after resized when fully maximized
3864 if (flags
.maximized
== 1)
3867 flags
.resizing
= False
;
3868 blackbox
->setChangingWindow(0);
3870 configure(frame
.changing
.x(), frame
.changing
.y(),
3871 frame
.changing
.width(), frame
.changing
.height());
3872 screen
->hideGeometry();
3874 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3876 // if there are any left over motions from the resize, drop them now
3877 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3879 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3884 void BlackboxWindow::motionNotifyEvent(const XMotionEvent
*me
) {
3886 fprintf(stderr
, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n",
3891 doMove(me
->x_root
, me
->y_root
);
3892 } else if (flags
.resizing
) {
3893 doResize(me
->x_root
, me
->y_root
);
3895 if ((functions
& Func_Move
) &&
3896 (me
->state
& Button1Mask
) &&
3897 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3898 frame
.handle
== me
->window
|| frame
.window
== me
->window
)) {
3899 beginMove(me
->x_root
, me
->y_root
);
3900 } else if ((functions
& Func_Resize
) &&
3901 ((me
->state
& Button1Mask
) &&
3902 (me
->window
== frame
.right_grip
||
3903 me
->window
== frame
.left_grip
)) ||
3904 ((me
->state
& Button3Mask
) && (me
->state
& mod_mask
) &&
3905 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3906 frame
.handle
== me
->window
|| frame
.window
== me
->window
||
3907 frame
.right_grip
== me
->window
||
3908 frame
.left_grip
== me
->window
))) {
3909 unsigned int zones
= screen
->getResizeZones();
3912 if (me
->window
== frame
.left_grip
) {
3913 corner
= BottomLeft
;
3914 } else if (me
->window
== frame
.right_grip
|| zones
== 1) {
3915 corner
= BottomRight
;
3918 bool left
= (me
->x_root
- frame
.rect
.x() <=
3919 static_cast<signed>(frame
.rect
.width() / 2));
3922 else // (zones == 4)
3923 top
= (me
->y_root
- frame
.rect
.y() <=
3924 static_cast<signed>(frame
.rect
.height() / 2));
3925 corner
= (top
? (left
? TopLeft
: TopRight
) :
3926 (left
? BottomLeft
: BottomRight
));
3929 beginResize(me
->x_root
, me
->y_root
, corner
);
3935 void BlackboxWindow::enterNotifyEvent(const XCrossingEvent
* ce
) {
3936 if (! (screen
->isSloppyFocus() && isVisible() && isNormal()))
3940 bool leave
= False
, inferior
= False
;
3942 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), ce
->window
,
3944 if (e
.type
== LeaveNotify
&& e
.xcrossing
.mode
== NotifyNormal
) {
3946 inferior
= (e
.xcrossing
.detail
== NotifyInferior
);
3950 if (! leave
|| inferior
) {
3951 if (! isFocused()) {
3952 bool success
= setInputFocus();
3953 if (success
) // if focus succeeded install the colormap
3954 installColormap(True
); // XXX: shouldnt we honour no install?
3957 We only auto-raise when the window wasn't focused because otherwise
3958 we run into problems with gtk+ drop-down lists. The window ends up
3959 raising over the list.
3961 if (screen
->doAutoRaise())
3968 void BlackboxWindow::leaveNotifyEvent(const XCrossingEvent
*) {
3969 if (! (screen
->isSloppyFocus() && screen
->doAutoRaise() && isNormal()))
3972 installColormap(False
);
3974 if (timer
->isTiming())
3980 void BlackboxWindow::shapeEvent(XShapeEvent
*e
) {
3981 if (blackbox
->hasShapeExtensions()) {
3982 if (! e
->shaped
&& flags
.shaped
) {
3984 flags
.shaped
= False
;
3985 } else if (e
->shaped
) {
3987 flags
.shaped
= True
;
3994 bool BlackboxWindow::validateClient(void) const {
3995 XSync(blackbox
->getXDisplay(), False
);
3998 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3999 DestroyNotify
, &e
) ||
4000 XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
4002 XPutBackEvent(blackbox
->getXDisplay(), &e
);
4011 void BlackboxWindow::restore(bool remap
) {
4012 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeDelete
);
4013 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
4014 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, NoEventMask
);
4016 // do not leave a shaded window as an icon unless it was an icon
4017 if (flags
.shaded
&& ! flags
.iconic
)
4018 setState(NormalState
);
4020 // erase the netwm stuff that we read when a window maps, so that it
4021 // doesn't persist between mappings.
4022 // (these are the ones read in getNetWMFlags().)
4023 xatom
->eraseValue(client
.window
, XAtom::net_wm_desktop
);
4024 xatom
->eraseValue(client
.window
, XAtom::net_wm_state
);
4026 restoreGravity(client
.rect
);
4028 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
4029 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
4031 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, client
.old_bw
);
4034 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
4035 ReparentNotify
, &ev
)) {
4038 // according to the ICCCM - if the client doesn't reparent to
4039 // root, then we have to do it for them
4040 XReparentWindow(blackbox
->getXDisplay(), client
.window
,
4041 screen
->getRootWindow(),
4042 client
.rect
.x(), client
.rect
.y());
4045 if (remap
) XMapWindow(blackbox
->getXDisplay(), client
.window
);
4049 // timer for autoraise
4050 void BlackboxWindow::timeout(void) {
4051 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
4055 void BlackboxWindow::changeBlackboxHints(const BlackboxHints
*net
) {
4056 if ((net
->flags
& AttribShaded
) &&
4057 ((blackbox_attrib
.attrib
& AttribShaded
) !=
4058 (net
->attrib
& AttribShaded
)))
4061 if (flags
.visible
&& // watch out for requests when we can not be seen
4062 (net
->flags
& (AttribMaxVert
| AttribMaxHoriz
)) &&
4063 ((blackbox_attrib
.attrib
& (AttribMaxVert
| AttribMaxHoriz
)) !=
4064 (net
->attrib
& (AttribMaxVert
| AttribMaxHoriz
)))) {
4065 if (flags
.maximized
) {
4070 if ((net
->flags
& AttribMaxHoriz
) && (net
->flags
& AttribMaxVert
))
4071 button
= ((net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0);
4072 else if (net
->flags
& AttribMaxVert
)
4073 button
= ((net
->attrib
& AttribMaxVert
) ? 2 : 0);
4074 else if (net
->flags
& AttribMaxHoriz
)
4075 button
= ((net
->attrib
& AttribMaxHoriz
) ? 3 : 0);
4081 if ((net
->flags
& AttribOmnipresent
) &&
4082 ((blackbox_attrib
.attrib
& AttribOmnipresent
) !=
4083 (net
->attrib
& AttribOmnipresent
)))
4086 if ((net
->flags
& AttribWorkspace
) &&
4087 (blackbox_attrib
.workspace
!= net
->workspace
)) {
4088 screen
->reassociateWindow(this, net
->workspace
, True
);
4090 if (screen
->getCurrentWorkspaceID() != net
->workspace
) {
4094 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
4098 if (net
->flags
& AttribDecoration
) {
4099 switch (net
->decoration
) {
4116 * Set the sizes of all components of the window frame
4117 * (the window decorations).
4118 * These values are based upon the current style settings and the client
4119 * window's dimensions.
4121 void BlackboxWindow::upsize(void) {
4122 frame
.bevel_w
= screen
->getBevelWidth();
4124 if (decorations
& Decor_Border
) {
4125 frame
.border_w
= screen
->getBorderWidth();
4126 if (! isTransient())
4127 frame
.mwm_border_w
= screen
->getFrameWidth();
4129 frame
.mwm_border_w
= 0;
4131 frame
.mwm_border_w
= frame
.border_w
= 0;
4134 if (decorations
& Decor_Titlebar
) {
4135 // the height of the titlebar is based upon the height of the font being
4136 // used to display the window's title
4137 WindowStyle
*style
= screen
->getWindowStyle();
4138 frame
.title_h
= style
->font
->height() + (frame
.bevel_w
* 2) + 2;
4140 frame
.label_h
= frame
.title_h
- (frame
.bevel_w
* 2);
4141 frame
.button_w
= (frame
.label_h
- 2);
4143 // set the top frame margin
4144 frame
.margin
.top
= frame
.border_w
+ frame
.title_h
+
4145 frame
.border_w
+ frame
.mwm_border_w
;
4151 // set the top frame margin
4152 frame
.margin
.top
= frame
.border_w
+ frame
.mwm_border_w
;
4155 // set the left/right frame margin
4156 frame
.margin
.left
= frame
.margin
.right
= frame
.border_w
+ frame
.mwm_border_w
;
4158 if (decorations
& Decor_Handle
) {
4159 frame
.grip_w
= frame
.button_w
* 2;
4160 frame
.handle_h
= screen
->getHandleWidth();
4162 // set the bottom frame margin
4163 frame
.margin
.bottom
= frame
.border_w
+ frame
.handle_h
+
4164 frame
.border_w
+ frame
.mwm_border_w
;
4169 // set the bottom frame margin
4170 frame
.margin
.bottom
= frame
.border_w
+ frame
.mwm_border_w
;
4174 We first get the normal dimensions and use this to define the inside_w/h
4175 then we modify the height if shading is in effect.
4176 If the shade state is not considered then frame.rect gets reset to the
4177 normal window size on a reconfigure() call resulting in improper
4178 dimensions appearing in move/resize and other events.
4181 height
= client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
,
4182 width
= client
.rect
.width() + frame
.margin
.left
+ frame
.margin
.right
;
4184 frame
.inside_w
= width
- (frame
.border_w
* 2);
4185 frame
.inside_h
= height
- (frame
.border_w
* 2);
4188 height
= frame
.title_h
+ (frame
.border_w
* 2);
4189 frame
.rect
.setSize(width
, height
);
4194 * Calculate the size of the client window and constrain it to the
4195 * size specified by the size hints of the client window.
4197 * The logical width and height are placed into pw and ph, if they
4198 * are non-zero. Logical size refers to the users perception of
4199 * the window size (for example an xterm resizes in cells, not in pixels).
4200 * pw and ph are then used to display the geometry during window moves, resize,
4203 * The physical geometry is placed into frame.changing_{x,y,width,height}.
4204 * Physical geometry refers to the geometry of the window in pixels.
4206 void BlackboxWindow::constrain(Corner anchor
,
4207 unsigned int *pw
, unsigned int *ph
) {
4208 // frame.changing represents the requested frame size, we need to
4209 // strip the frame margin off and constrain the client size
4210 frame
.changing
.setCoords(frame
.changing
.left() + frame
.margin
.left
,
4211 frame
.changing
.top() + frame
.margin
.top
,
4212 frame
.changing
.right() - frame
.margin
.right
,
4213 frame
.changing
.bottom() - frame
.margin
.bottom
);
4215 unsigned int dw
= frame
.changing
.width(), dh
= frame
.changing
.height(),
4216 base_width
= (client
.base_width
) ? client
.base_width
: client
.min_width
,
4217 base_height
= (client
.base_height
) ? client
.base_height
:
4220 // constrain, but only if the min/max are being used. if they aren't, then
4221 // this resize is going to be from a ConfigureRequest because the window
4222 // isn't allowed to be resized by the user. And in that case, we don't want
4223 // to limit what the app can do
4224 if (client
.max_width
> client
.min_width
||
4225 client
.max_height
> client
.min_height
) {
4226 if (dw
< client
.min_width
) dw
= client
.min_width
;
4227 if (dh
< client
.min_height
) dh
= client
.min_height
;
4228 if (dw
> client
.max_width
) dw
= client
.max_width
;
4229 if (dh
> client
.max_height
) dh
= client
.max_height
;
4232 assert(dw
>= base_width
&& dh
>= base_height
);
4234 if (client
.width_inc
> 1) {
4236 dw
/= client
.width_inc
;
4238 if (client
.height_inc
> 1) {
4240 dh
/= client
.height_inc
;
4249 if (client
.width_inc
> 1) {
4250 dw
*= client
.width_inc
;
4253 if (client
.height_inc
> 1) {
4254 dh
*= client
.height_inc
;
4258 frame
.changing
.setSize(dw
, dh
);
4260 // add the frame margin back onto frame.changing
4261 frame
.changing
.setCoords(frame
.changing
.left() - frame
.margin
.left
,
4262 frame
.changing
.top() - frame
.margin
.top
,
4263 frame
.changing
.right() + frame
.margin
.right
,
4264 frame
.changing
.bottom() + frame
.margin
.bottom
);
4266 // move frame.changing to the specified anchor
4274 dx
= frame
.rect
.right() - frame
.changing
.right();
4278 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
4282 dx
= frame
.rect
.right() - frame
.changing
.right();
4283 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
4287 assert(false); // unhandled corner
4289 frame
.changing
.setPos(frame
.changing
.x() + dx
, frame
.changing
.y() + dy
);
4293 void WindowStyle::doJustify(const std::string
&text
, int &start_pos
,
4294 unsigned int max_length
,
4295 unsigned int modifier
) const {
4296 size_t text_len
= text
.size();
4297 unsigned int length
;
4300 length
= font
->measureString(string(text
, 0, text_len
)) + modifier
;
4301 } while (length
> max_length
&& text_len
-- > 0);
4305 start_pos
+= max_length
- length
;
4309 start_pos
+= (max_length
- length
) / 2;
4319 BWindowGroup::BWindowGroup(Blackbox
*b
, Window _group
)
4320 : blackbox(b
), group(_group
) {
4321 XWindowAttributes wattrib
;
4322 if (! XGetWindowAttributes(blackbox
->getXDisplay(), group
, &wattrib
)) {
4323 // group window doesn't seem to exist anymore
4328 XSelectInput(blackbox
->getXDisplay(), group
,
4329 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
4331 blackbox
->saveGroupSearch(group
, this);
4335 BWindowGroup::~BWindowGroup(void) {
4336 blackbox
->removeGroupSearch(group
);
4341 BWindowGroup::find(BScreen
*screen
, bool allow_transients
) const {
4342 BlackboxWindow
*ret
= blackbox
->getFocusedWindow();
4344 // does the focus window match (or any transient_fors)?
4345 for (; ret
; ret
= ret
->getTransientFor()) {
4346 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
&&
4347 (! ret
->isTransient() || allow_transients
))
4351 if (ret
) return ret
;
4353 // the focus window didn't match, look in the group's window list
4354 BlackboxWindowList::const_iterator it
, end
= windowList
.end();
4355 for (it
= windowList
.begin(); it
!= end
; ++it
) {
4357 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
&&
4358 (! ret
->isTransient() || allow_transients
))