1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2 // Window.cc for Blackbox - an X11 Window manager
3 // Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry <shaleh at debian.org>
4 // Copyright (c) 1997 - 2000, 2002 Brad Hughes <bhughes at trolltech.com>
6 // Permission is hereby granted, free of charge, to any person obtaining a
7 // copy of this software and associated documentation files (the "Software"),
8 // to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 // and/or sell copies of the Software, and to permit persons to whom the
11 // Software is furnished to do so, subject to the following conditions:
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 // DEALINGS IN THE SOFTWARE.
25 # include "../config.h"
26 #endif // HAVE_CONFIG_H
29 #include <X11/Xatom.h>
30 #include <X11/keysym.h>
34 #endif // HAVE_STRING_H
39 # endif // HAVE_STDIO_H
46 #include "blackbox.hh"
47 #include "Clientmenu.hh"
50 #include "Iconmenu.hh"
56 #include "Windowmenu.hh"
57 #include "Workspace.hh"
63 * Initializes the class with default values/the window's set initial values.
65 BlackboxWindow::BlackboxWindow(Blackbox
*b
, Window w
, BScreen
*s
) {
66 // fprintf(stderr, "BlackboxWindow size: %d bytes\n",
67 // sizeof(BlackboxWindow));
70 fprintf(stderr
, "BlackboxWindow::BlackboxWindow(): creating 0x%lx\n", w
);
74 set timer to zero... it is initialized properly later, so we check
75 if timer is zero in the destructor, and assume that the window is not
76 fully constructed if timer is zero...
82 xatom
= blackbox
->getXAtom();
84 if (! validateClient()) {
89 // set the eventmask early in the game so that we make sure we get
90 // all the events we are interested in
91 XSetWindowAttributes attrib_set
;
92 attrib_set
.event_mask
= PropertyChangeMask
| FocusChangeMask
|
94 attrib_set
.do_not_propagate_mask
= ButtonPressMask
| ButtonReleaseMask
|
96 XChangeWindowAttributes(blackbox
->getXDisplay(), client
.window
,
97 CWEventMask
|CWDontPropagate
, &attrib_set
);
99 // fetch client size and placement
100 XWindowAttributes wattrib
;
101 if ((! XGetWindowAttributes(blackbox
->getXDisplay(),
102 client
.window
, &wattrib
)) ||
103 (! wattrib
.screen
) || wattrib
.override_redirect
) {
106 "BlackboxWindow::BlackboxWindow(): XGetWindowAttributes failed\n");
113 flags
.moving
= flags
.resizing
= flags
.shaded
= flags
.visible
=
114 flags
.iconic
= flags
.focused
= flags
.stuck
= flags
.modal
=
115 flags
.send_focus_message
= flags
.shaped
= flags
.skip_taskbar
=
116 flags
.skip_pager
= flags
.fullscreen
= False
;
119 blackbox_attrib
.workspace
= window_number
= BSENTINEL
;
121 blackbox_attrib
.flags
= blackbox_attrib
.attrib
= blackbox_attrib
.stack
122 = blackbox_attrib
.decoration
= 0l;
123 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
124 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
127 frame
.window
= frame
.plate
= frame
.title
= frame
.handle
= None
;
128 frame
.close_button
= frame
.iconify_button
= frame
.maximize_button
= None
;
129 frame
.right_grip
= frame
.left_grip
= None
;
131 frame
.ulabel_pixel
= frame
.flabel_pixel
= frame
.utitle_pixel
=
132 frame
.ftitle_pixel
= frame
.uhandle_pixel
= frame
.fhandle_pixel
=
133 frame
.ubutton_pixel
= frame
.fbutton_pixel
= frame
.pbutton_pixel
=
134 frame
.uborder_pixel
= frame
.fborder_pixel
= frame
.ugrip_pixel
=
135 frame
.fgrip_pixel
= 0;
136 frame
.utitle
= frame
.ftitle
= frame
.uhandle
= frame
.fhandle
= None
;
137 frame
.ulabel
= frame
.flabel
= frame
.ubutton
= frame
.fbutton
= None
;
138 frame
.pbutton
= frame
.ugrip
= frame
.fgrip
= None
;
140 decorations
= Decor_Titlebar
| Decor_Border
| Decor_Handle
|
141 Decor_Iconify
| Decor_Maximize
;
142 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
144 client
.wm_hint_flags
= client
.normal_hint_flags
= 0;
145 client
.window_group
= None
;
146 client
.transient_for
= 0;
149 get the initial size and location of client window (relative to the
150 _root window_). This position is the reference point used with the
151 window's gravity to find the window's initial position.
153 client
.rect
.setRect(wattrib
.x
, wattrib
.y
, wattrib
.width
, wattrib
.height
);
154 client
.old_bw
= wattrib
.border_width
;
157 lastButtonPressTime
= 0;
159 timer
= new BTimer(blackbox
, this);
160 timer
->setTimeout(blackbox
->getAutoRaiseDelay());
162 if (! getBlackboxHints()) {
167 // get size, aspect, minimum/maximum size and other hints set by the
173 if (client
.initial_state
== WithdrawnState
) {
174 screen
->getSlit()->addClient(client
.window
);
179 frame
.window
= createToplevelWindow();
180 frame
.plate
= createChildWindow(frame
.window
);
181 associateClientWindow();
183 blackbox
->saveWindowSearch(frame
.window
, this);
184 blackbox
->saveWindowSearch(frame
.plate
, this);
185 blackbox
->saveWindowSearch(client
.window
, this);
187 // determine if this is a transient window
190 // determine the window's type, so we can decide its decorations and
191 // functionality, or if we should not manage it at all
194 // adjust the window decorations/behavior based on the window type
195 switch (window_type
) {
202 // none of these windows are decorated or manipulated by the window manager
205 blackbox_attrib
.workspace
= 0; // we do need to belong to a workspace
206 flags
.stuck
= True
; // we show up on all workspaces
210 // dialogs cannot be maximized, and don't display a handle
211 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
212 functions
&= ~Func_Maximize
;
216 // normal windows retain all of the possible decorations and functionality
220 // further adjeust the window's decorations/behavior based on window sizes
221 if ((client
.normal_hint_flags
& PMinSize
) &&
222 (client
.normal_hint_flags
& PMaxSize
) &&
223 client
.max_width
<= client
.min_width
&&
224 client
.max_height
<= client
.min_height
) {
225 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
226 functions
&= ~(Func_Resize
| Func_Maximize
);
232 bool place_window
= True
;
233 if (blackbox
->isStartup() || isTransient() ||
234 client
.normal_hint_flags
& (PPosition
|USPosition
)) {
235 applyGravity(frame
.rect
);
237 if (blackbox
->isStartup() || client
.rect
.intersects(screen
->getRect()))
238 place_window
= False
;
241 // add the window's strut. note this is done *after* placing the window.
242 screen
->addStrut(&client
.strut
);
245 if (decorations
& Decor_Titlebar
)
248 if (decorations
& Decor_Handle
)
252 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
257 windowmenu
= new Windowmenu(this);
259 if (blackbox_attrib
.workspace
>= screen
->getWorkspaceCount())
260 screen
->getCurrentWorkspace()->addWindow(this, place_window
);
262 screen
->getWorkspace(blackbox_attrib
.workspace
)->
263 addWindow(this, place_window
);
265 if (! place_window
) {
266 // don't need to call configure if we are letting the workspace
268 configure(frame
.rect
.x(), frame
.rect
.y(),
269 frame
.rect
.width(), frame
.rect
.height());
272 // preserve the window's initial state on first map, and its current state
275 if (client
.wm_hint_flags
& StateHint
)
276 current_state
= client
.initial_state
;
278 current_state
= NormalState
;
281 // get sticky state from our parent window if we've got one
282 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
283 client
.transient_for
->isStuck() != flags
.stuck
)
287 flags
.shaded
= False
;
288 unsigned long orig_state
= current_state
;
292 At this point in the life of a window, current_state should only be set
293 to IconicState if the window was an *icon*, not if it was shaded.
295 if (orig_state
!= IconicState
)
296 current_state
= NormalState
;
304 if (flags
.maximized
&& (functions
& Func_Maximize
)) {
309 When the window is mapped (and also when its attributes are restored), the
310 current_state that was set here will be used.
311 It is set to Normal if the window is to be mapped or it is set to Iconic
312 if the window is to be iconified.
313 *Note* that for sticky windows, the same rules apply here, they are in
314 fact never set to Iconic since there is no way for us to tell if a sticky
315 window was iconified previously.
322 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
328 BlackboxWindow::~BlackboxWindow(void) {
330 fprintf(stderr
, "BlackboxWindow::~BlackboxWindow: destroying 0x%lx\n",
334 if (! timer
) // window not managed...
337 screen
->removeStrut(&client
.strut
);
338 screen
->updateAvailableArea();
340 // We don't need to worry about resizing because resizing always grabs the X
341 // server. This should only ever happen if using opaque moving.
349 if (client
.window_group
) {
350 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
351 if (group
) group
->removeWindow(this);
354 // remove ourselves from our transient_for
356 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
357 client
.transient_for
->client
.transientList
.remove(this);
359 client
.transient_for
= (BlackboxWindow
*) 0;
362 if (client
.transientList
.size() > 0) {
363 // reset transient_for for all transients
364 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
365 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
366 (*it
)->client
.transient_for
= (BlackboxWindow
*) 0;
377 blackbox
->removeWindowSearch(frame
.plate
);
378 XDestroyWindow(blackbox
->getXDisplay(), frame
.plate
);
382 blackbox
->removeWindowSearch(frame
.window
);
383 XDestroyWindow(blackbox
->getXDisplay(), frame
.window
);
386 blackbox
->removeWindowSearch(client
.window
);
391 * Creates a new top level window, with a given location, size, and border
393 * Returns: the newly created window
395 Window
BlackboxWindow::createToplevelWindow(void) {
396 XSetWindowAttributes attrib_create
;
397 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
| CWColormap
|
398 CWOverrideRedirect
| CWEventMask
;
400 attrib_create
.background_pixmap
= None
;
401 attrib_create
.colormap
= screen
->getColormap();
402 attrib_create
.override_redirect
= True
;
403 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
404 ButtonMotionMask
| EnterWindowMask
;
406 return XCreateWindow(blackbox
->getXDisplay(), screen
->getRootWindow(),
407 0, 0, 1, 1, frame
.border_w
, screen
->getDepth(),
408 InputOutput
, screen
->getVisual(), create_mask
,
414 * Creates a child window, and optionally associates a given cursor with
417 Window
BlackboxWindow::createChildWindow(Window parent
, Cursor cursor
) {
418 XSetWindowAttributes attrib_create
;
419 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
|
422 attrib_create
.background_pixmap
= None
;
423 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
424 ButtonMotionMask
| ExposureMask
;
427 create_mask
|= CWCursor
;
428 attrib_create
.cursor
= cursor
;
431 return XCreateWindow(blackbox
->getXDisplay(), parent
, 0, 0, 1, 1, 0,
432 screen
->getDepth(), InputOutput
, screen
->getVisual(),
433 create_mask
, &attrib_create
);
437 void BlackboxWindow::associateClientWindow(void) {
438 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, 0);
442 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeInsert
);
444 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, SubstructureRedirectMask
);
446 XGrabServer(blackbox
->getXDisplay());
448 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
450 XSelectInput(blackbox
->getXDisplay(), client
.window
,
451 event_mask
& ~StructureNotifyMask
);
452 XReparentWindow(blackbox
->getXDisplay(), client
.window
, frame
.plate
, 0, 0);
453 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
455 XUngrabServer(blackbox
->getXDisplay());
457 XRaiseWindow(blackbox
->getXDisplay(), frame
.plate
);
458 XMapSubwindows(blackbox
->getXDisplay(), frame
.plate
);
462 if (blackbox
->hasShapeExtensions()) {
463 XShapeSelectInput(blackbox
->getXDisplay(), client
.window
,
470 XShapeQueryExtents(blackbox
->getXDisplay(), client
.window
, &shaped
,
471 &foo
, &foo
, &ufoo
, &ufoo
, &foo
, &foo
, &foo
,
473 flags
.shaped
= shaped
;
479 void BlackboxWindow::decorate(void) {
482 texture
= &(screen
->getWindowStyle()->b_focus
);
483 frame
.fbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
486 frame
.fbutton_pixel
= texture
->color().pixel();
488 texture
= &(screen
->getWindowStyle()->b_unfocus
);
489 frame
.ubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
492 frame
.ubutton_pixel
= texture
->color().pixel();
494 texture
= &(screen
->getWindowStyle()->b_pressed
);
495 frame
.pbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
498 frame
.pbutton_pixel
= texture
->color().pixel();
500 if (decorations
& Decor_Titlebar
) {
501 texture
= &(screen
->getWindowStyle()->t_focus
);
502 frame
.ftitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
505 frame
.ftitle_pixel
= texture
->color().pixel();
507 texture
= &(screen
->getWindowStyle()->t_unfocus
);
508 frame
.utitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
511 frame
.utitle_pixel
= texture
->color().pixel();
513 XSetWindowBorder(blackbox
->getXDisplay(), frame
.title
,
514 screen
->getBorderColor()->pixel());
519 if (decorations
& Decor_Border
) {
520 frame
.fborder_pixel
= screen
->getWindowStyle()->f_focus
.pixel();
521 frame
.uborder_pixel
= screen
->getWindowStyle()->f_unfocus
.pixel();
522 blackbox_attrib
.flags
|= AttribDecoration
;
523 blackbox_attrib
.decoration
= DecorNormal
;
525 blackbox_attrib
.flags
|= AttribDecoration
;
526 blackbox_attrib
.decoration
= DecorNone
;
529 if (decorations
& Decor_Handle
) {
530 texture
= &(screen
->getWindowStyle()->h_focus
);
531 frame
.fhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
534 frame
.fhandle_pixel
= texture
->color().pixel();
536 texture
= &(screen
->getWindowStyle()->h_unfocus
);
537 frame
.uhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
540 frame
.uhandle_pixel
= texture
->color().pixel();
542 texture
= &(screen
->getWindowStyle()->g_focus
);
543 frame
.fgrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.fgrip
);
545 frame
.fgrip_pixel
= texture
->color().pixel();
547 texture
= &(screen
->getWindowStyle()->g_unfocus
);
548 frame
.ugrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.ugrip
);
550 frame
.ugrip_pixel
= texture
->color().pixel();
552 XSetWindowBorder(blackbox
->getXDisplay(), frame
.handle
,
553 screen
->getBorderColor()->pixel());
554 XSetWindowBorder(blackbox
->getXDisplay(), frame
.left_grip
,
555 screen
->getBorderColor()->pixel());
556 XSetWindowBorder(blackbox
->getXDisplay(), frame
.right_grip
,
557 screen
->getBorderColor()->pixel());
560 XSetWindowBorder(blackbox
->getXDisplay(), frame
.window
,
561 screen
->getBorderColor()->pixel());
565 void BlackboxWindow::decorateLabel(void) {
568 texture
= &(screen
->getWindowStyle()->l_focus
);
569 frame
.flabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.flabel
);
571 frame
.flabel_pixel
= texture
->color().pixel();
573 texture
= &(screen
->getWindowStyle()->l_unfocus
);
574 frame
.ulabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.ulabel
);
576 frame
.ulabel_pixel
= texture
->color().pixel();
580 void BlackboxWindow::createHandle(void) {
581 frame
.handle
= createChildWindow(frame
.window
);
582 blackbox
->saveWindowSearch(frame
.handle
, this);
585 createChildWindow(frame
.handle
, blackbox
->getLowerLeftAngleCursor());
586 blackbox
->saveWindowSearch(frame
.left_grip
, this);
589 createChildWindow(frame
.handle
, blackbox
->getLowerRightAngleCursor());
590 blackbox
->saveWindowSearch(frame
.right_grip
, this);
594 void BlackboxWindow::destroyHandle(void) {
596 screen
->getImageControl()->removeImage(frame
.fhandle
);
599 screen
->getImageControl()->removeImage(frame
.uhandle
);
602 screen
->getImageControl()->removeImage(frame
.fgrip
);
605 screen
->getImageControl()->removeImage(frame
.ugrip
);
607 blackbox
->removeWindowSearch(frame
.left_grip
);
608 blackbox
->removeWindowSearch(frame
.right_grip
);
610 XDestroyWindow(blackbox
->getXDisplay(), frame
.left_grip
);
611 XDestroyWindow(blackbox
->getXDisplay(), frame
.right_grip
);
612 frame
.left_grip
= frame
.right_grip
= None
;
614 blackbox
->removeWindowSearch(frame
.handle
);
615 XDestroyWindow(blackbox
->getXDisplay(), frame
.handle
);
620 void BlackboxWindow::createTitlebar(void) {
621 frame
.title
= createChildWindow(frame
.window
);
622 frame
.label
= createChildWindow(frame
.title
);
623 blackbox
->saveWindowSearch(frame
.title
, this);
624 blackbox
->saveWindowSearch(frame
.label
, this);
626 if (decorations
& Decor_Iconify
) createIconifyButton();
627 if (decorations
& Decor_Maximize
) createMaximizeButton();
628 if (decorations
& Decor_Close
) createCloseButton();
632 void BlackboxWindow::destroyTitlebar(void) {
633 if (frame
.close_button
)
634 destroyCloseButton();
636 if (frame
.iconify_button
)
637 destroyIconifyButton();
639 if (frame
.maximize_button
)
640 destroyMaximizeButton();
643 screen
->getImageControl()->removeImage(frame
.ftitle
);
646 screen
->getImageControl()->removeImage(frame
.utitle
);
649 screen
->getImageControl()->removeImage(frame
.flabel
);
652 screen
->getImageControl()->removeImage(frame
.ulabel
);
655 screen
->getImageControl()->removeImage(frame
.fbutton
);
658 screen
->getImageControl()->removeImage(frame
.ubutton
);
661 screen
->getImageControl()->removeImage(frame
.pbutton
);
663 blackbox
->removeWindowSearch(frame
.title
);
664 blackbox
->removeWindowSearch(frame
.label
);
666 XDestroyWindow(blackbox
->getXDisplay(), frame
.label
);
667 XDestroyWindow(blackbox
->getXDisplay(), frame
.title
);
668 frame
.title
= frame
.label
= None
;
672 void BlackboxWindow::createCloseButton(void) {
673 if (frame
.title
!= None
) {
674 frame
.close_button
= createChildWindow(frame
.title
);
675 blackbox
->saveWindowSearch(frame
.close_button
, this);
680 void BlackboxWindow::destroyCloseButton(void) {
681 blackbox
->removeWindowSearch(frame
.close_button
);
682 XDestroyWindow(blackbox
->getXDisplay(), frame
.close_button
);
683 frame
.close_button
= None
;
687 void BlackboxWindow::createIconifyButton(void) {
688 if (frame
.title
!= None
) {
689 frame
.iconify_button
= createChildWindow(frame
.title
);
690 blackbox
->saveWindowSearch(frame
.iconify_button
, this);
695 void BlackboxWindow::destroyIconifyButton(void) {
696 blackbox
->removeWindowSearch(frame
.iconify_button
);
697 XDestroyWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
698 frame
.iconify_button
= None
;
702 void BlackboxWindow::createMaximizeButton(void) {
703 if (frame
.title
!= None
) {
704 frame
.maximize_button
= createChildWindow(frame
.title
);
705 blackbox
->saveWindowSearch(frame
.maximize_button
, this);
710 void BlackboxWindow::destroyMaximizeButton(void) {
711 blackbox
->removeWindowSearch(frame
.maximize_button
);
712 XDestroyWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
713 frame
.maximize_button
= None
;
717 void BlackboxWindow::positionButtons(bool redecorate_label
) {
718 string layout
= blackbox
->getTitlebarLayout();
721 bool hasclose
, hasiconify
, hasmaximize
, haslabel
;
722 hasclose
= hasiconify
= hasmaximize
= haslabel
= false;
724 string::const_iterator it
, end
;
725 for (it
= layout
.begin(), end
= layout
.end(); it
!= end
; ++it
) {
728 if (! hasclose
&& (decorations
& Decor_Close
)) {
734 if (! hasiconify
&& (decorations
& Decor_Iconify
)) {
740 if (! hasmaximize
&& (decorations
& Decor_Maximize
)) {
752 if (! hasclose
&& frame
.close_button
)
753 destroyCloseButton();
754 if (! hasiconify
&& frame
.iconify_button
)
755 destroyIconifyButton();
756 if (! hasmaximize
&& frame
.maximize_button
)
757 destroyMaximizeButton();
759 parsed
+= 'L'; // require that the label be in the layout
761 const unsigned int bsep
= frame
.bevel_w
+ 1; // separation between elements
762 const unsigned int by
= frame
.bevel_w
+ 1;
763 const unsigned int ty
= frame
.bevel_w
;
765 frame
.label_w
= frame
.inside_w
- bsep
* 2 -
766 (frame
.button_w
+ bsep
) * (parsed
.size() - 1);
768 unsigned int x
= bsep
;
769 for (it
= parsed
.begin(), end
= parsed
.end(); it
!= end
; ++it
) {
772 if (! frame
.close_button
) createCloseButton();
773 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.close_button
, x
, by
,
774 frame
.button_w
, frame
.button_w
);
775 x
+= frame
.button_w
+ bsep
;
778 if (! frame
.iconify_button
) createIconifyButton();
779 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.iconify_button
, x
, by
,
780 frame
.button_w
, frame
.button_w
);
781 x
+= frame
.button_w
+ bsep
;
784 if (! frame
.maximize_button
) createMaximizeButton();
785 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.maximize_button
, x
, by
,
786 frame
.button_w
, frame
.button_w
);
787 x
+= frame
.button_w
+ bsep
;
790 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.label
, x
, ty
,
791 frame
.label_w
, frame
.label_h
);
792 x
+= frame
.label_w
+ bsep
;
797 if (redecorate_label
) decorateLabel();
803 void BlackboxWindow::reconfigure(void) {
804 restoreGravity(client
.rect
);
806 applyGravity(frame
.rect
);
815 windowmenu
->move(windowmenu
->getX(), frame
.rect
.y() + frame
.title_h
);
816 windowmenu
->reconfigure();
821 void BlackboxWindow::grabButtons(void) {
822 if ((! screen
->isSloppyFocus()) || screen
->doClickRaise())
823 // grab button 1 for changing focus/raising
824 blackbox
->grabButton(Button1
, 0, frame
.plate
, True
, ButtonPressMask
,
825 GrabModeSync
, GrabModeSync
, frame
.plate
, None
);
827 if (functions
& Func_Move
)
828 blackbox
->grabButton(Button1
, Mod1Mask
, frame
.window
, True
,
829 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
830 GrabModeAsync
, frame
.window
,
831 blackbox
->getMoveCursor());
832 if (functions
& Func_Resize
)
833 blackbox
->grabButton(Button3
, Mod1Mask
, frame
.window
, True
,
834 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
835 GrabModeAsync
, frame
.window
, None
);
836 // alt+middle lowers the window
837 blackbox
->grabButton(Button2
, Mod1Mask
, frame
.window
, True
,
838 ButtonReleaseMask
, GrabModeAsync
, GrabModeAsync
,
843 void BlackboxWindow::ungrabButtons(void) {
844 if ((! screen
->isSloppyFocus()) || screen
->doClickRaise())
845 blackbox
->ungrabButton(Button1
, 0, frame
.plate
);
847 blackbox
->ungrabButton(Button1
, Mod1Mask
, frame
.window
);
848 blackbox
->ungrabButton(Button2
, Mod1Mask
, frame
.window
);
849 blackbox
->ungrabButton(Button3
, Mod1Mask
, frame
.window
);
853 void BlackboxWindow::positionWindows(void) {
854 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.window
,
855 frame
.rect
.x(), frame
.rect
.y(), frame
.inside_w
,
856 (flags
.shaded
) ? frame
.title_h
: frame
.inside_h
);
857 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.window
,
859 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.plate
,
861 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.plate
,
862 frame
.margin
.left
- frame
.mwm_border_w
- frame
.border_w
,
863 frame
.margin
.top
- frame
.mwm_border_w
- frame
.border_w
,
864 client
.rect
.width(), client
.rect
.height());
865 XMoveResizeWindow(blackbox
->getXDisplay(), client
.window
,
866 0, 0, client
.rect
.width(), client
.rect
.height());
867 // ensure client.rect contains the real location
868 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
869 frame
.rect
.top() + frame
.margin
.top
);
871 if (decorations
& Decor_Titlebar
) {
872 if (frame
.title
== None
) createTitlebar();
874 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.title
,
876 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.title
, -frame
.border_w
,
877 -frame
.border_w
, frame
.inside_w
, frame
.title_h
);
880 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
881 XMapWindow(blackbox
->getXDisplay(), frame
.title
);
882 } else if (frame
.title
) {
885 if (decorations
& Decor_Handle
) {
886 if (frame
.handle
== None
) createHandle();
887 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.handle
,
889 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.left_grip
,
891 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.right_grip
,
894 // use client.rect here so the value is correct even if shaded
895 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.handle
,
897 client
.rect
.height() + frame
.margin
.top
+
898 frame
.mwm_border_w
- frame
.border_w
,
899 frame
.inside_w
, frame
.handle_h
);
900 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.left_grip
,
901 -frame
.border_w
, -frame
.border_w
,
902 frame
.grip_w
, frame
.handle_h
);
903 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.right_grip
,
904 frame
.inside_w
- frame
.grip_w
- frame
.border_w
,
905 -frame
.border_w
, frame
.grip_w
, frame
.handle_h
);
907 XMapSubwindows(blackbox
->getXDisplay(), frame
.handle
);
908 XMapWindow(blackbox
->getXDisplay(), frame
.handle
);
909 } else if (frame
.handle
) {
912 XSync(blackbox
->getXDisplay(), False
);
916 void BlackboxWindow::updateStrut(void) {
917 unsigned long num
= 4;
919 if (! xatom
->getValue(client
.window
, XAtom::net_wm_strut
, XAtom::cardinal
,
924 client
.strut
.left
= data
[0];
925 client
.strut
.right
= data
[1];
926 client
.strut
.top
= data
[2];
927 client
.strut
.bottom
= data
[3];
929 screen
->updateAvailableArea();
936 void BlackboxWindow::getWindowType(void) {
938 if (xatom
->getValue(client
.window
, XAtom::net_wm_window_type
, XAtom::atom
,
940 if (val
== xatom
->getAtom(XAtom::net_wm_window_type_desktop
))
941 window_type
= Type_Desktop
;
942 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_dock
))
943 window_type
= Type_Dock
;
944 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_toolbar
))
945 window_type
= Type_Toolbar
;
946 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_menu
))
947 window_type
= Type_Menu
;
948 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_utility
))
949 window_type
= Type_Utility
;
950 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_splash
))
951 window_type
= Type_Splash
;
952 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_dialog
))
953 window_type
= Type_Dialog
;
954 else //if (val[0] == xatom->getAtom(XAtom::net_wm_window_type_normal))
955 window_type
= Type_Normal
;
960 * the window type hint was not set, which means we either classify ourself
961 * as a normal window or a dialog, depending on if we are a transient.
964 window_type
= Type_Dialog
;
966 window_type
= Type_Normal
;
970 void BlackboxWindow::getWMName(void) {
971 if (xatom
->getValue(client
.window
, XAtom::net_wm_name
,
972 XAtom::utf8
, client
.title
) &&
973 !client
.title
.empty()) {
974 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
977 //fall through to using WM_NAME
978 if (xatom
->getValue(client
.window
, XAtom::wm_name
, XAtom::ansi
, client
.title
)
979 && !client
.title
.empty()) {
980 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
983 // fall back to an internal default
984 client
.title
= i18n(WindowSet
, WindowUnnamed
, "Unnamed");
985 xatom
->setValue(client
.window
, XAtom::net_wm_visible_name
, XAtom::utf8
,
990 void BlackboxWindow::getWMIconName(void) {
991 if (xatom
->getValue(client
.window
, XAtom::net_wm_icon_name
,
992 XAtom::utf8
, client
.icon_title
) &&
993 !client
.icon_title
.empty()) {
994 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
997 //fall through to using WM_ICON_NAME
998 if (xatom
->getValue(client
.window
, XAtom::wm_icon_name
, XAtom::ansi
,
999 client
.icon_title
) &&
1000 !client
.icon_title
.empty()) {
1001 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1004 // fall back to using the main name
1005 client
.icon_title
= client
.title
;
1006 xatom
->setValue(client
.window
, XAtom::net_wm_visible_icon_name
, XAtom::utf8
,
1012 * Retrieve which WM Protocols are supported by the client window.
1013 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
1014 * window's decorations and allow the close behavior.
1015 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
1018 void BlackboxWindow::getWMProtocols(void) {
1022 if (XGetWMProtocols(blackbox
->getXDisplay(), client
.window
,
1023 &proto
, &num_return
)) {
1024 for (int i
= 0; i
< num_return
; ++i
) {
1025 if (proto
[i
] == xatom
->getAtom(XAtom::wm_delete_window
)) {
1026 decorations
|= Decor_Close
;
1027 functions
|= Func_Close
;
1028 } else if (proto
[i
] == xatom
->getAtom(XAtom::wm_take_focus
))
1029 flags
.send_focus_message
= True
;
1030 else if (proto
[i
] == xatom
->getAtom(XAtom::blackbox_structure_messages
))
1031 screen
->addNetizen(new Netizen(screen
, client
.window
));
1040 * Gets the value of the WM_HINTS property.
1041 * If the property is not set, then use a set of default values.
1043 void BlackboxWindow::getWMHints(void) {
1044 focus_mode
= F_Passive
;
1045 client
.initial_state
= NormalState
;
1047 // remove from current window group
1048 if (client
.window_group
) {
1049 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1050 if (group
) group
->removeWindow(this);
1052 client
.window_group
= None
;
1054 XWMHints
*wmhint
= XGetWMHints(blackbox
->getXDisplay(), client
.window
);
1059 if (wmhint
->flags
& InputHint
) {
1060 if (wmhint
->input
== True
) {
1061 if (flags
.send_focus_message
)
1062 focus_mode
= F_LocallyActive
;
1064 if (flags
.send_focus_message
)
1065 focus_mode
= F_GloballyActive
;
1067 focus_mode
= F_NoInput
;
1071 if (wmhint
->flags
& StateHint
)
1072 client
.initial_state
= wmhint
->initial_state
;
1074 if (wmhint
->flags
& WindowGroupHint
) {
1075 client
.window_group
= wmhint
->window_group
;
1077 // add window to the appropriate group
1078 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1079 if (! group
) { // no group found, create it!
1080 new BWindowGroup(blackbox
, client
.window_group
);
1081 group
= blackbox
->searchGroup(client
.window_group
);
1084 group
->addWindow(this);
1087 client
.wm_hint_flags
= wmhint
->flags
;
1093 * Gets the value of the WM_NORMAL_HINTS property.
1094 * If the property is not set, then use a set of default values.
1096 void BlackboxWindow::getWMNormalHints(void) {
1098 XSizeHints sizehint
;
1100 client
.min_width
= client
.min_height
=
1101 client
.width_inc
= client
.height_inc
= 1;
1102 client
.base_width
= client
.base_height
= 0;
1103 client
.win_gravity
= NorthWestGravity
;
1105 client
.min_aspect_x
= client
.min_aspect_y
=
1106 client
.max_aspect_x
= client
.max_aspect_y
= 1;
1110 use the full screen, not the strut modified size. otherwise when the
1111 availableArea changes max_width/height will be incorrect and lead to odd
1114 const Rect
& screen_area
= screen
->getRect();
1115 client
.max_width
= screen_area
.width();
1116 client
.max_height
= screen_area
.height();
1118 if (! XGetWMNormalHints(blackbox
->getXDisplay(), client
.window
,
1119 &sizehint
, &icccm_mask
))
1122 client
.normal_hint_flags
= sizehint
.flags
;
1124 if (sizehint
.flags
& PMinSize
) {
1125 if (sizehint
.min_width
>= 0)
1126 client
.min_width
= sizehint
.min_width
;
1127 if (sizehint
.min_height
>= 0)
1128 client
.min_height
= sizehint
.min_height
;
1131 if (sizehint
.flags
& PMaxSize
) {
1132 if (sizehint
.max_width
> static_cast<signed>(client
.min_width
))
1133 client
.max_width
= sizehint
.max_width
;
1135 client
.max_width
= client
.min_width
;
1137 if (sizehint
.max_height
> static_cast<signed>(client
.min_height
))
1138 client
.max_height
= sizehint
.max_height
;
1140 client
.max_height
= client
.min_height
;
1143 if (sizehint
.flags
& PResizeInc
) {
1144 client
.width_inc
= sizehint
.width_inc
;
1145 client
.height_inc
= sizehint
.height_inc
;
1148 #if 0 // we do not support this at the moment
1149 if (sizehint
.flags
& PAspect
) {
1150 client
.min_aspect_x
= sizehint
.min_aspect
.x
;
1151 client
.min_aspect_y
= sizehint
.min_aspect
.y
;
1152 client
.max_aspect_x
= sizehint
.max_aspect
.x
;
1153 client
.max_aspect_y
= sizehint
.max_aspect
.y
;
1157 if (sizehint
.flags
& PBaseSize
) {
1158 client
.base_width
= sizehint
.base_width
;
1159 client
.base_height
= sizehint
.base_height
;
1162 if (sizehint
.flags
& PWinGravity
)
1163 client
.win_gravity
= sizehint
.win_gravity
;
1168 * Gets the NETWM hints for the class' contained window.
1170 void BlackboxWindow::getNetWMHints(void) {
1171 unsigned long workspace
;
1173 if (xatom
->getValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1175 if (workspace
== 0xffffffff)
1178 blackbox_attrib
.workspace
= workspace
;
1181 unsigned long *state
;
1182 unsigned long num
= (unsigned) -1;
1183 if (xatom
->getValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
1187 for (unsigned long i
= 0; i
< num
; ++i
) {
1188 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
))
1190 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_shaded
))
1191 flags
.shaded
= True
;
1192 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
))
1193 flags
.skip_taskbar
= True
;
1194 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_pager
))
1195 flags
.skip_pager
= True
;
1196 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_fullscreen
))
1197 flags
.fullscreen
= True
;
1198 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_hidden
))
1199 setState(IconicState
);
1200 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_vert
))
1202 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_horz
))
1206 flags
.maximized
= 1;
1208 flags
.maximized
= 2;
1210 flags
.maximized
= 3;
1218 * Gets the MWM hints for the class' contained window.
1219 * This is used while initializing the window to its first state, and not
1221 * Returns: true if the MWM hints are successfully retreived and applied;
1222 * false if they are not.
1224 void BlackboxWindow::getMWMHints(void) {
1228 num
= PropMwmHintsElements
;
1229 if (! xatom
->getValue(client
.window
, XAtom::motif_wm_hints
,
1230 XAtom::motif_wm_hints
, num
,
1231 (unsigned long **)&mwm_hint
))
1233 if (num
< PropMwmHintsElements
) {
1238 if (mwm_hint
->flags
& MwmHintsDecorations
) {
1239 if (mwm_hint
->decorations
& MwmDecorAll
) {
1240 decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
1241 Decor_Iconify
| Decor_Maximize
| Decor_Close
;
1245 if (mwm_hint
->decorations
& MwmDecorBorder
)
1246 decorations
|= Decor_Border
;
1247 if (mwm_hint
->decorations
& MwmDecorHandle
)
1248 decorations
|= Decor_Handle
;
1249 if (mwm_hint
->decorations
& MwmDecorTitle
)
1250 decorations
|= Decor_Titlebar
;
1251 if (mwm_hint
->decorations
& MwmDecorIconify
)
1252 decorations
|= Decor_Iconify
;
1253 if (mwm_hint
->decorations
& MwmDecorMaximize
)
1254 decorations
|= Decor_Maximize
;
1258 if (mwm_hint
->flags
& MwmHintsFunctions
) {
1259 if (mwm_hint
->functions
& MwmFuncAll
) {
1260 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
|
1265 if (mwm_hint
->functions
& MwmFuncResize
)
1266 functions
|= Func_Resize
;
1267 if (mwm_hint
->functions
& MwmFuncMove
)
1268 functions
|= Func_Move
;
1269 if (mwm_hint
->functions
& MwmFuncIconify
)
1270 functions
|= Func_Iconify
;
1271 if (mwm_hint
->functions
& MwmFuncMaximize
)
1272 functions
|= Func_Maximize
;
1273 if (mwm_hint
->functions
& MwmFuncClose
)
1274 functions
|= Func_Close
;
1282 * Gets the blackbox hints from the class' contained window.
1283 * This is used while initializing the window to its first state, and not
1285 * Returns: true if the hints are successfully retreived and applied; false if
1288 bool BlackboxWindow::getBlackboxHints(void) {
1290 BlackboxHints
*blackbox_hint
;
1292 num
= PropBlackboxHintsElements
;
1293 if (! xatom
->getValue(client
.window
, XAtom::blackbox_hints
,
1294 XAtom::blackbox_hints
, num
,
1295 (unsigned long **)&blackbox_hint
))
1297 if (num
< PropBlackboxHintsElements
) {
1298 delete [] blackbox_hint
;
1302 if (blackbox_hint
->flags
& AttribShaded
)
1303 flags
.shaded
= (blackbox_hint
->attrib
& AttribShaded
);
1305 if ((blackbox_hint
->flags
& AttribMaxHoriz
) &&
1306 (blackbox_hint
->flags
& AttribMaxVert
))
1307 flags
.maximized
= (blackbox_hint
->attrib
&
1308 (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1309 else if (blackbox_hint
->flags
& AttribMaxVert
)
1310 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxVert
) ? 2 : 0;
1311 else if (blackbox_hint
->flags
& AttribMaxHoriz
)
1312 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1314 if (blackbox_hint
->flags
& AttribOmnipresent
)
1315 flags
.stuck
= (blackbox_hint
->attrib
& AttribOmnipresent
);
1317 if (blackbox_hint
->flags
& AttribWorkspace
)
1318 blackbox_attrib
.workspace
= blackbox_hint
->workspace
;
1320 // if (blackbox_hint->flags & AttribStack)
1321 // don't yet have always on top/bottom for blackbox yet... working
1324 if (blackbox_hint
->flags
& AttribDecoration
) {
1325 switch (blackbox_hint
->decoration
) {
1327 // clear all decorations except close
1328 decorations
&= Decor_Close
;
1329 // clear all functions except close
1330 functions
&= Func_Close
;
1335 decorations
|= Decor_Titlebar
| Decor_Iconify
;
1336 decorations
&= ~(Decor_Border
| Decor_Handle
| Decor_Maximize
);
1337 functions
|= Func_Move
| Func_Iconify
;
1338 functions
&= ~(Func_Resize
| Func_Maximize
);
1343 decorations
|= Decor_Titlebar
;
1344 decorations
&= ~(Decor_Iconify
| Decor_Border
| Decor_Handle
);
1345 functions
|= Func_Move
;
1346 functions
&= ~(Func_Resize
| Func_Maximize
| Func_Iconify
);
1352 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Handle
|
1353 Decor_Iconify
| Decor_Maximize
;
1354 functions
|= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
1362 delete [] blackbox_hint
;
1368 void BlackboxWindow::getTransientInfo(void) {
1369 if (client
.transient_for
&&
1370 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1371 // the transient for hint was removed, so we need to tell our
1372 // previous transient_for that we are going away
1373 client
.transient_for
->client
.transientList
.remove(this);
1376 // we have no transient_for until we find a new one
1377 client
.transient_for
= 0;
1380 if (! XGetTransientForHint(blackbox
->getXDisplay(), client
.window
,
1382 // transient_for hint not set
1386 if (trans_for
== client
.window
) {
1387 // wierd client... treat this window as a normal window
1391 if (trans_for
== None
|| trans_for
== screen
->getRootWindow()) {
1392 // this is an undocumented interpretation of the ICCCM. a transient
1393 // associated with None/Root/itself is assumed to be a modal root
1394 // transient. we don't support the concept of a global transient,
1395 // so we just associate this transient with nothing, and perhaps
1396 // we will add support later for global modality.
1397 client
.transient_for
= (BlackboxWindow
*) ~0ul;
1402 client
.transient_for
= blackbox
->searchWindow(trans_for
);
1403 if (! client
.transient_for
&&
1404 client
.window_group
&& trans_for
== client
.window_group
) {
1405 // no direct transient_for, perhaps this is a group transient?
1406 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1407 if (group
) client
.transient_for
= group
->find(screen
);
1410 if (! client
.transient_for
|| client
.transient_for
== this) {
1411 // no transient_for found, or we have a wierd client that wants to be
1412 // a transient for itself, so we treat this window as a normal window
1413 client
.transient_for
= (BlackboxWindow
*) 0;
1417 // register ourselves with our new transient_for
1418 client
.transient_for
->client
.transientList
.push_back(this);
1419 flags
.stuck
= client
.transient_for
->flags
.stuck
;
1423 BlackboxWindow
*BlackboxWindow::getTransientFor(void) const {
1424 if (client
.transient_for
&&
1425 client
.transient_for
!= (BlackboxWindow
*) ~0ul)
1426 return client
.transient_for
;
1432 * This function is responsible for updating both the client and the frame
1434 * According to the ICCCM a client message is not sent for a resize, only a
1437 void BlackboxWindow::configure(int dx
, int dy
,
1438 unsigned int dw
, unsigned int dh
) {
1439 bool send_event
= ((frame
.rect
.x() != dx
|| frame
.rect
.y() != dy
) &&
1442 if (dw
!= frame
.rect
.width() || dh
!= frame
.rect
.height()) {
1443 frame
.rect
.setRect(dx
, dy
, dw
, dh
);
1444 frame
.inside_w
= frame
.rect
.width() - (frame
.border_w
* 2);
1445 frame
.inside_h
= frame
.rect
.height() - (frame
.border_w
* 2);
1447 if (frame
.rect
.right() <= 0 || frame
.rect
.bottom() <= 0)
1448 frame
.rect
.setPos(0, 0);
1450 client
.rect
.setCoords(frame
.rect
.left() + frame
.margin
.left
,
1451 frame
.rect
.top() + frame
.margin
.top
,
1452 frame
.rect
.right() - frame
.margin
.right
,
1453 frame
.rect
.bottom() - frame
.margin
.bottom
);
1456 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
1463 redrawWindowFrame();
1465 frame
.rect
.setPos(dx
, dy
);
1467 XMoveWindow(blackbox
->getXDisplay(), frame
.window
,
1468 frame
.rect
.x(), frame
.rect
.y());
1470 we may have been called just after an opaque window move, so even though
1471 the old coords match the new ones no ConfigureNotify has been sent yet.
1472 There are likely other times when this will be relevant as well.
1474 if (! flags
.moving
) send_event
= True
;
1478 // if moving, the update and event will occur when the move finishes
1479 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1480 frame
.rect
.top() + frame
.margin
.top
);
1483 event
.type
= ConfigureNotify
;
1485 event
.xconfigure
.display
= blackbox
->getXDisplay();
1486 event
.xconfigure
.event
= client
.window
;
1487 event
.xconfigure
.window
= client
.window
;
1488 event
.xconfigure
.x
= client
.rect
.x();
1489 event
.xconfigure
.y
= client
.rect
.y();
1490 event
.xconfigure
.width
= client
.rect
.width();
1491 event
.xconfigure
.height
= client
.rect
.height();
1492 event
.xconfigure
.border_width
= client
.old_bw
;
1493 event
.xconfigure
.above
= frame
.window
;
1494 event
.xconfigure
.override_redirect
= False
;
1496 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1497 StructureNotifyMask
, &event
);
1498 screen
->updateNetizenConfigNotify(&event
);
1499 XFlush(blackbox
->getXDisplay());
1505 void BlackboxWindow::configureShape(void) {
1506 XShapeCombineShape(blackbox
->getXDisplay(), frame
.window
, ShapeBounding
,
1507 frame
.margin
.left
- frame
.border_w
,
1508 frame
.margin
.top
- frame
.border_w
,
1509 client
.window
, ShapeBounding
, ShapeSet
);
1512 XRectangle xrect
[2];
1514 if (decorations
& Decor_Titlebar
) {
1515 xrect
[0].x
= xrect
[0].y
= -frame
.border_w
;
1516 xrect
[0].width
= frame
.rect
.width();
1517 xrect
[0].height
= frame
.title_h
+ (frame
.border_w
* 2);
1521 if (decorations
& Decor_Handle
) {
1522 xrect
[1].x
= -frame
.border_w
;
1523 xrect
[1].y
= frame
.rect
.height() - frame
.margin
.bottom
+
1524 frame
.mwm_border_w
- frame
.border_w
;
1525 xrect
[1].width
= frame
.rect
.width();
1526 xrect
[1].height
= frame
.handle_h
+ (frame
.border_w
* 2);
1530 XShapeCombineRectangles(blackbox
->getXDisplay(), frame
.window
,
1531 ShapeBounding
, 0, 0, xrect
, num
,
1532 ShapeUnion
, Unsorted
);
1537 bool BlackboxWindow::setInputFocus(void) {
1538 if (flags
.focused
) return True
;
1540 assert(! flags
.iconic
&&
1541 (flags
.stuck
|| // window must be on the current workspace or sticky
1542 blackbox_attrib
.workspace
== screen
->getCurrentWorkspaceID()));
1544 // if the window is not visible, mark the window as wanting focus rather
1545 // than give it focus.
1546 if (! flags
.visible
) {
1547 Workspace
*wkspc
= screen
->getWorkspace(blackbox_attrib
.workspace
);
1548 wkspc
->setLastFocusedWindow(this);
1553 We only do this check for normal windows and dialogs because other windows
1554 do this on purpose, such as kde's kicker, and we don't want to go moving
1557 if (window_type
== Type_Normal
|| window_type
== Type_Dialog
)
1558 if (! frame
.rect
.intersects(screen
->getRect())) {
1559 // client is outside the screen, move it to the center
1560 configure((screen
->getWidth() - frame
.rect
.width()) / 2,
1561 (screen
->getHeight() - frame
.rect
.height()) / 2,
1562 frame
.rect
.width(), frame
.rect
.height());
1565 if (client
.transientList
.size() > 0) {
1566 // transfer focus to any modal transients
1567 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1568 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1569 if ((*it
)->flags
.modal
) return (*it
)->setInputFocus();
1574 if (focus_mode
== F_LocallyActive
|| focus_mode
== F_Passive
) {
1575 XSetInputFocus(blackbox
->getXDisplay(), client
.window
,
1576 RevertToPointerRoot
, CurrentTime
);
1578 blackbox
->setFocusedWindow(this);
1580 /* we could set the focus to none, since the window doesn't accept focus,
1581 * but we shouldn't set focus to nothing since this would surely make
1587 if (flags
.send_focus_message
) {
1589 ce
.xclient
.type
= ClientMessage
;
1590 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1591 ce
.xclient
.display
= blackbox
->getXDisplay();
1592 ce
.xclient
.window
= client
.window
;
1593 ce
.xclient
.format
= 32;
1594 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_take_focus
);
1595 ce
.xclient
.data
.l
[1] = blackbox
->getLastTime();
1596 ce
.xclient
.data
.l
[2] = 0l;
1597 ce
.xclient
.data
.l
[3] = 0l;
1598 ce
.xclient
.data
.l
[4] = 0l;
1599 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1601 XFlush(blackbox
->getXDisplay());
1608 void BlackboxWindow::iconify(void) {
1609 if (flags
.iconic
) return;
1611 // We don't need to worry about resizing because resizing always grabs the X
1612 // server. This should only ever happen if using opaque moving.
1616 if (windowmenu
) windowmenu
->hide();
1619 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1620 * we need to clear the event mask on client.window for a split second.
1621 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1622 * split second, leaving us with a ghost window... so, we need to do this
1623 * while the X server is grabbed
1625 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1626 StructureNotifyMask
;
1627 XGrabServer(blackbox
->getXDisplay());
1628 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1629 event_mask
& ~StructureNotifyMask
);
1630 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1631 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1632 XUngrabServer(blackbox
->getXDisplay());
1634 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1635 flags
.visible
= False
;
1636 flags
.iconic
= True
;
1638 setState(IconicState
);
1640 screen
->getWorkspace(blackbox_attrib
.workspace
)->removeWindow(this);
1642 if (isTransient()) {
1643 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1644 ! client
.transient_for
->flags
.iconic
) {
1645 // iconify our transient_for
1646 client
.transient_for
->iconify();
1650 screen
->addIcon(this);
1652 if (client
.transientList
.size() > 0) {
1653 // iconify all transients
1654 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1655 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1656 if (! (*it
)->flags
.iconic
) (*it
)->iconify();
1659 screen
->updateStackingList();
1663 void BlackboxWindow::show(void) {
1664 flags
.visible
= True
;
1665 flags
.iconic
= False
;
1667 current_state
= (flags
.shaded
) ? IconicState
: NormalState
;
1668 setState(current_state
);
1670 XMapWindow(blackbox
->getXDisplay(), client
.window
);
1671 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
1672 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
1677 XTranslateCoordinates(blackbox
->getXDisplay(), client
.window
,
1678 screen
->getRootWindow(),
1679 0, 0, &real_x
, &real_y
, &child
);
1680 fprintf(stderr
, "%s -- assumed: (%d, %d), real: (%d, %d)\n", getTitle(),
1681 client
.rect
.left(), client
.rect
.top(), real_x
, real_y
);
1682 assert(client
.rect
.left() == real_x
&& client
.rect
.top() == real_y
);
1687 void BlackboxWindow::deiconify(bool reassoc
, bool raise
) {
1688 if (flags
.iconic
|| reassoc
)
1689 screen
->reassociateWindow(this, BSENTINEL
, False
);
1690 else if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID())
1695 // reassociate and deiconify all transients
1696 if (reassoc
&& client
.transientList
.size() > 0) {
1697 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1698 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1699 (*it
)->deiconify(True
, False
);
1704 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1708 void BlackboxWindow::close(void) {
1710 ce
.xclient
.type
= ClientMessage
;
1711 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1712 ce
.xclient
.display
= blackbox
->getXDisplay();
1713 ce
.xclient
.window
= client
.window
;
1714 ce
.xclient
.format
= 32;
1715 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_delete_window
);
1716 ce
.xclient
.data
.l
[1] = CurrentTime
;
1717 ce
.xclient
.data
.l
[2] = 0l;
1718 ce
.xclient
.data
.l
[3] = 0l;
1719 ce
.xclient
.data
.l
[4] = 0l;
1720 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
, NoEventMask
, &ce
);
1721 XFlush(blackbox
->getXDisplay());
1725 void BlackboxWindow::withdraw(void) {
1726 // We don't need to worry about resizing because resizing always grabs the X
1727 // server. This should only ever happen if using opaque moving.
1731 flags
.visible
= False
;
1732 flags
.iconic
= False
;
1734 setState(current_state
);
1736 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1738 XGrabServer(blackbox
->getXDisplay());
1740 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1741 StructureNotifyMask
;
1742 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1743 event_mask
& ~StructureNotifyMask
);
1744 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1745 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1747 XUngrabServer(blackbox
->getXDisplay());
1749 if (windowmenu
) windowmenu
->hide();
1753 void BlackboxWindow::maximize(unsigned int button
) {
1754 // We don't need to worry about resizing because resizing always grabs the X
1755 // server. This should only ever happen if using opaque moving.
1759 // handle case where menu is open then the max button is used instead
1760 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
1762 if (flags
.maximized
) {
1763 flags
.maximized
= 0;
1765 blackbox_attrib
.flags
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1766 blackbox_attrib
.attrib
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1769 when a resize finishes, maximize(0) is called to clear any maximization
1770 flags currently set. Otherwise it still thinks it is maximized.
1771 so we do not need to call configure() because resizing will handle it
1773 if (! flags
.resizing
)
1774 configure(blackbox_attrib
.premax_x
, blackbox_attrib
.premax_y
,
1775 blackbox_attrib
.premax_w
, blackbox_attrib
.premax_h
);
1777 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
1778 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
1780 redrawAllButtons(); // in case it is not called in configure()
1781 setState(current_state
);
1785 blackbox_attrib
.premax_x
= frame
.rect
.x();
1786 blackbox_attrib
.premax_y
= frame
.rect
.y();
1787 blackbox_attrib
.premax_w
= frame
.rect
.width();
1788 // use client.rect so that clients can be restored even if shaded
1789 blackbox_attrib
.premax_h
=
1790 client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
;
1792 const Rect
&screen_area
= screen
->availableArea();
1793 frame
.changing
= screen_area
;
1797 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1798 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1802 blackbox_attrib
.flags
|= AttribMaxVert
;
1803 blackbox_attrib
.attrib
|= AttribMaxVert
;
1805 frame
.changing
.setX(frame
.rect
.x());
1806 frame
.changing
.setWidth(frame
.rect
.width());
1810 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1811 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1813 frame
.changing
.setY(frame
.rect
.y());
1814 frame
.changing
.setHeight(frame
.rect
.height());
1821 blackbox_attrib
.flags
^= AttribShaded
;
1822 blackbox_attrib
.attrib
^= AttribShaded
;
1823 flags
.shaded
= False
;
1826 flags
.maximized
= button
;
1828 configure(frame
.changing
.x(), frame
.changing
.y(),
1829 frame
.changing
.width(), frame
.changing
.height());
1831 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1832 redrawAllButtons(); // in case it is not called in configure()
1833 setState(current_state
);
1837 // re-maximizes the window to take into account availableArea changes
1838 void BlackboxWindow::remaximize(void) {
1839 // save the original dimensions because maximize will wipe them out
1840 int premax_x
= blackbox_attrib
.premax_x
,
1841 premax_y
= blackbox_attrib
.premax_y
,
1842 premax_w
= blackbox_attrib
.premax_w
,
1843 premax_h
= blackbox_attrib
.premax_h
;
1845 unsigned int button
= flags
.maximized
;
1846 flags
.maximized
= 0; // trick maximize() into working
1849 // restore saved values
1850 blackbox_attrib
.premax_x
= premax_x
;
1851 blackbox_attrib
.premax_y
= premax_y
;
1852 blackbox_attrib
.premax_w
= premax_w
;
1853 blackbox_attrib
.premax_h
= premax_h
;
1857 void BlackboxWindow::setWorkspace(unsigned int n
) {
1858 blackbox_attrib
.flags
|= AttribWorkspace
;
1859 blackbox_attrib
.workspace
= n
;
1860 if (n
== BSENTINEL
) { // iconified window
1862 we set the workspace to 'all workspaces' so that taskbars will show the
1863 window. otherwise, it made uniconifying a window imposible without the
1864 blackbox workspace menu
1868 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
, n
);
1872 void BlackboxWindow::shade(void) {
1874 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1875 frame
.inside_w
, frame
.inside_h
);
1876 flags
.shaded
= False
;
1877 blackbox_attrib
.flags
^= AttribShaded
;
1878 blackbox_attrib
.attrib
^= AttribShaded
;
1880 setState(NormalState
);
1882 // set the frame rect to the normal size
1883 frame
.rect
.setHeight(client
.rect
.height() + frame
.margin
.top
+
1884 frame
.margin
.bottom
);
1886 if (! (decorations
& Decor_Titlebar
))
1887 return; // can't shade it without a titlebar!
1889 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1890 frame
.inside_w
, frame
.title_h
);
1891 flags
.shaded
= True
;
1892 blackbox_attrib
.flags
|= AttribShaded
;
1893 blackbox_attrib
.attrib
|= AttribShaded
;
1895 setState(IconicState
);
1897 // set the frame rect to the shaded size
1898 frame
.rect
.setHeight(frame
.title_h
+ (frame
.border_w
* 2));
1904 * (Un)Sticks a window and its relatives.
1906 void BlackboxWindow::stick(void) {
1908 blackbox_attrib
.flags
^= AttribOmnipresent
;
1909 blackbox_attrib
.attrib
^= AttribOmnipresent
;
1911 flags
.stuck
= False
;
1914 screen
->reassociateWindow(this, BSENTINEL
, True
);
1915 // temporary fix since sticky windows suck. set the hint to what we
1916 // actually hold in our data.
1917 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1918 blackbox_attrib
.workspace
);
1920 setState(current_state
);
1924 blackbox_attrib
.flags
|= AttribOmnipresent
;
1925 blackbox_attrib
.attrib
|= AttribOmnipresent
;
1927 // temporary fix since sticky windows suck. set the hint to a different
1928 // value than that contained in the class' data.
1929 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1932 setState(current_state
);
1935 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1936 client
.transient_for
->isStuck() != flags
.stuck
)
1937 client
.transient_for
->stick();
1938 // go down the chain
1939 BlackboxWindowList::iterator it
;
1940 const BlackboxWindowList::iterator end
= client
.transientList
.end();
1941 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1942 if ((*it
)->isStuck() != flags
.stuck
)
1947 void BlackboxWindow::redrawWindowFrame(void) const {
1948 if (decorations
& Decor_Titlebar
) {
1949 if (flags
.focused
) {
1951 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1952 frame
.title
, frame
.ftitle
);
1954 XSetWindowBackground(blackbox
->getXDisplay(),
1955 frame
.title
, frame
.ftitle_pixel
);
1958 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1959 frame
.title
, frame
.utitle
);
1961 XSetWindowBackground(blackbox
->getXDisplay(),
1962 frame
.title
, frame
.utitle_pixel
);
1964 XClearWindow(blackbox
->getXDisplay(), frame
.title
);
1970 if (decorations
& Decor_Handle
) {
1971 if (flags
.focused
) {
1973 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1974 frame
.handle
, frame
.fhandle
);
1976 XSetWindowBackground(blackbox
->getXDisplay(),
1977 frame
.handle
, frame
.fhandle_pixel
);
1980 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1981 frame
.left_grip
, frame
.fgrip
);
1982 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1983 frame
.right_grip
, frame
.fgrip
);
1985 XSetWindowBackground(blackbox
->getXDisplay(),
1986 frame
.left_grip
, frame
.fgrip_pixel
);
1987 XSetWindowBackground(blackbox
->getXDisplay(),
1988 frame
.right_grip
, frame
.fgrip_pixel
);
1992 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1993 frame
.handle
, frame
.uhandle
);
1995 XSetWindowBackground(blackbox
->getXDisplay(),
1996 frame
.handle
, frame
.uhandle_pixel
);
1999 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2000 frame
.left_grip
, frame
.ugrip
);
2001 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2002 frame
.right_grip
, frame
.ugrip
);
2004 XSetWindowBackground(blackbox
->getXDisplay(),
2005 frame
.left_grip
, frame
.ugrip_pixel
);
2006 XSetWindowBackground(blackbox
->getXDisplay(),
2007 frame
.right_grip
, frame
.ugrip_pixel
);
2010 XClearWindow(blackbox
->getXDisplay(), frame
.handle
);
2011 XClearWindow(blackbox
->getXDisplay(), frame
.left_grip
);
2012 XClearWindow(blackbox
->getXDisplay(), frame
.right_grip
);
2015 if (decorations
& Decor_Border
) {
2017 XSetWindowBorder(blackbox
->getXDisplay(),
2018 frame
.plate
, frame
.fborder_pixel
);
2020 XSetWindowBorder(blackbox
->getXDisplay(),
2021 frame
.plate
, frame
.uborder_pixel
);
2026 void BlackboxWindow::setFocusFlag(bool focus
) {
2027 // only focus a window if it is visible
2028 if (focus
&& !flags
.visible
)
2031 flags
.focused
= focus
;
2033 redrawWindowFrame();
2035 if (screen
->isSloppyFocus() && screen
->doAutoRaise()) {
2036 if (isFocused()) timer
->start();
2041 blackbox
->setFocusedWindow(this);
2043 Clientmenu
*menu
= screen
->getWorkspace(blackbox_attrib
.workspace
)->getMenu();
2044 menu
->setItemSelected(window_number
, isFocused());
2048 void BlackboxWindow::installColormap(bool install
) {
2049 int i
= 0, ncmap
= 0;
2050 Colormap
*cmaps
= XListInstalledColormaps(blackbox
->getXDisplay(),
2051 client
.window
, &ncmap
);
2053 XWindowAttributes wattrib
;
2054 if (XGetWindowAttributes(blackbox
->getXDisplay(),
2055 client
.window
, &wattrib
)) {
2057 // install the window's colormap
2058 for (i
= 0; i
< ncmap
; i
++) {
2059 if (*(cmaps
+ i
) == wattrib
.colormap
)
2060 // this window is using an installed color map... do not install
2063 // otherwise, install the window's colormap
2065 XInstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2067 // uninstall the window's colormap
2068 for (i
= 0; i
< ncmap
; i
++) {
2069 if (*(cmaps
+ i
) == wattrib
.colormap
)
2070 // we found the colormap to uninstall
2071 XUninstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2081 void BlackboxWindow::setAllowedActions(void) {
2085 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_shade
);
2086 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_change_desktop
);
2087 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_close
);
2089 if (functions
& Func_Move
)
2090 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_move
);
2091 if (functions
& Func_Resize
)
2092 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_resize
);
2093 if (functions
& Func_Maximize
) {
2094 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_horz
);
2095 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_vert
);
2098 xatom
->setValue(client
.window
, XAtom::net_wm_allowed_actions
, XAtom::atom
,
2103 void BlackboxWindow::setState(unsigned long new_state
) {
2104 current_state
= new_state
;
2106 unsigned long state
[2];
2107 state
[0] = current_state
;
2109 xatom
->setValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
, state
, 2);
2111 xatom
->setValue(client
.window
, XAtom::blackbox_attributes
,
2112 XAtom::blackbox_attributes
, (unsigned long *)&blackbox_attrib
,
2113 PropBlackboxAttributesElements
);
2118 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_modal
);
2120 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_shaded
);
2122 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_hidden
);
2123 if (flags
.skip_taskbar
)
2124 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
);
2125 if (flags
.skip_pager
)
2126 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_pager
);
2127 if (flags
.fullscreen
)
2128 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_fullscreen
);
2129 if (flags
.maximized
== 1 || flags
.maximized
== 2)
2130 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_vert
);
2131 if (flags
.maximized
== 1 || flags
.maximized
== 3)
2132 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_horz
);
2133 xatom
->setValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
2138 bool BlackboxWindow::getState(void) {
2139 bool ret
= xatom
->getValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
,
2141 if (! ret
) current_state
= 0;
2146 void BlackboxWindow::restoreAttributes(void) {
2147 unsigned long num
= PropBlackboxAttributesElements
;
2148 BlackboxAttributes
*net
;
2149 if (! xatom
->getValue(client
.window
, XAtom::blackbox_attributes
,
2150 XAtom::blackbox_attributes
, num
,
2151 (unsigned long **)&net
))
2153 if (num
< PropBlackboxAttributesElements
) {
2158 if (net
->flags
& AttribShaded
&& net
->attrib
& AttribShaded
) {
2159 flags
.shaded
= False
;
2160 unsigned long orig_state
= current_state
;
2164 At this point in the life of a window, current_state should only be set
2165 to IconicState if the window was an *icon*, not if it was shaded.
2167 if (orig_state
!= IconicState
)
2168 current_state
= WithdrawnState
;
2171 if (net
->workspace
!= screen
->getCurrentWorkspaceID() &&
2172 net
->workspace
< screen
->getWorkspaceCount())
2173 screen
->reassociateWindow(this, net
->workspace
, True
);
2175 if ((blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID()) &&
2176 (blackbox_attrib
.workspace
< screen
->getWorkspaceCount())) {
2177 // set to WithdrawnState so it will be mapped on the new workspace
2178 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2179 } else if (current_state
== WithdrawnState
) {
2180 // the window is on this workspace and is Withdrawn, so it is waiting to
2182 current_state
= NormalState
;
2185 if (net
->flags
& AttribOmnipresent
&& net
->attrib
& AttribOmnipresent
) {
2186 flags
.stuck
= False
;
2189 // if the window was on another workspace, it was going to be hidden. this
2190 // specifies that the window should be mapped since it is sticky.
2191 if (current_state
== WithdrawnState
) current_state
= NormalState
;
2194 if (net
->flags
& AttribMaxHoriz
|| net
->flags
& AttribMaxVert
) {
2195 int x
= net
->premax_x
, y
= net
->premax_y
;
2196 unsigned int w
= net
->premax_w
, h
= net
->premax_h
;
2197 flags
.maximized
= 0;
2200 if ((net
->flags
& AttribMaxHoriz
) &&
2201 (net
->flags
& AttribMaxVert
))
2202 m
= (net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
2203 else if (net
->flags
& AttribMaxVert
)
2204 m
= (net
->attrib
& AttribMaxVert
) ? 2 : 0;
2205 else if (net
->flags
& AttribMaxHoriz
)
2206 m
= (net
->attrib
& AttribMaxHoriz
) ? 3 : 0;
2210 blackbox_attrib
.premax_x
= x
;
2211 blackbox_attrib
.premax_y
= y
;
2212 blackbox_attrib
.premax_w
= w
;
2213 blackbox_attrib
.premax_h
= h
;
2216 // with the state set it will then be the map event's job to read the
2217 // window's state and behave accordingly
2224 * Positions the Rect r according the the client window position and
2227 void BlackboxWindow::applyGravity(Rect
&r
) {
2228 // apply horizontal window gravity
2229 switch (client
.win_gravity
) {
2231 case NorthWestGravity
:
2232 case SouthWestGravity
:
2234 r
.setX(client
.rect
.x());
2240 r
.setX(client
.rect
.x() - (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2243 case NorthEastGravity
:
2244 case SouthEastGravity
:
2246 r
.setX(client
.rect
.x() - frame
.margin
.left
- frame
.margin
.right
+ 2);
2251 r
.setX(client
.rect
.x() - frame
.margin
.left
);
2255 // apply vertical window gravity
2256 switch (client
.win_gravity
) {
2258 case NorthWestGravity
:
2259 case NorthEastGravity
:
2261 r
.setY(client
.rect
.y());
2267 r
.setY(client
.rect
.y() - (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2270 case SouthWestGravity
:
2271 case SouthEastGravity
:
2273 r
.setY(client
.rect
.y() - frame
.margin
.top
- frame
.margin
.bottom
+ 2);
2278 r
.setY(client
.rect
.y() - frame
.margin
.top
);
2285 * The reverse of the applyGravity function.
2287 * Positions the Rect r according to the frame window position and
2290 void BlackboxWindow::restoreGravity(Rect
&r
) {
2291 // restore horizontal window gravity
2292 switch (client
.win_gravity
) {
2294 case NorthWestGravity
:
2295 case SouthWestGravity
:
2297 r
.setX(frame
.rect
.x());
2303 r
.setX(frame
.rect
.x() + (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2306 case NorthEastGravity
:
2307 case SouthEastGravity
:
2309 r
.setX(frame
.rect
.x() + frame
.margin
.left
+ frame
.margin
.right
- 2);
2314 r
.setX(frame
.rect
.x() + frame
.margin
.left
);
2318 // restore vertical window gravity
2319 switch (client
.win_gravity
) {
2321 case NorthWestGravity
:
2322 case NorthEastGravity
:
2324 r
.setY(frame
.rect
.y());
2330 r
.setY(frame
.rect
.y() + (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2333 case SouthWestGravity
:
2334 case SouthEastGravity
:
2336 r
.setY(frame
.rect
.y() + frame
.margin
.top
+ frame
.margin
.bottom
- 2);
2341 r
.setY(frame
.rect
.y() + frame
.margin
.top
);
2347 void BlackboxWindow::redrawLabel(void) const {
2348 if (flags
.focused
) {
2350 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2351 frame
.label
, frame
.flabel
);
2353 XSetWindowBackground(blackbox
->getXDisplay(),
2354 frame
.label
, frame
.flabel_pixel
);
2357 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2358 frame
.label
, frame
.ulabel
);
2360 XSetWindowBackground(blackbox
->getXDisplay(),
2361 frame
.label
, frame
.ulabel_pixel
);
2363 XClearWindow(blackbox
->getXDisplay(), frame
.label
);
2365 WindowStyle
*style
= screen
->getWindowStyle();
2367 int pos
= frame
.bevel_w
* 2;
2368 style
->doJustify(client
.title
.c_str(), pos
, frame
.label_w
, frame
.bevel_w
* 4);
2369 style
->font
->drawString(frame
.label
, pos
, 1,
2370 (flags
.focused
? style
->l_text_focus
:
2371 style
->l_text_unfocus
),
2376 void BlackboxWindow::redrawAllButtons(void) const {
2377 if (frame
.iconify_button
) redrawIconifyButton(False
);
2378 if (frame
.maximize_button
) redrawMaximizeButton(flags
.maximized
);
2379 if (frame
.close_button
) redrawCloseButton(False
);
2383 void BlackboxWindow::redrawIconifyButton(bool pressed
) const {
2385 if (flags
.focused
) {
2387 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2388 frame
.iconify_button
, frame
.fbutton
);
2390 XSetWindowBackground(blackbox
->getXDisplay(),
2391 frame
.iconify_button
, frame
.fbutton_pixel
);
2394 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2395 frame
.iconify_button
, frame
.ubutton
);
2397 XSetWindowBackground(blackbox
->getXDisplay(), frame
.iconify_button
,
2398 frame
.ubutton_pixel
);
2402 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2403 frame
.iconify_button
, frame
.pbutton
);
2405 XSetWindowBackground(blackbox
->getXDisplay(),
2406 frame
.iconify_button
, frame
.pbutton_pixel
);
2408 XClearWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
2410 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2411 screen
->getWindowStyle()->b_pic_unfocus
);
2412 XDrawRectangle(blackbox
->getXDisplay(), frame
.iconify_button
, pen
.gc(),
2413 2, (frame
.button_w
- 5), (frame
.button_w
- 5), 2);
2417 void BlackboxWindow::redrawMaximizeButton(bool pressed
) const {
2419 if (flags
.focused
) {
2421 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2422 frame
.maximize_button
, frame
.fbutton
);
2424 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2425 frame
.fbutton_pixel
);
2428 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2429 frame
.maximize_button
, frame
.ubutton
);
2431 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2432 frame
.ubutton_pixel
);
2436 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2437 frame
.maximize_button
, frame
.pbutton
);
2439 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2440 frame
.pbutton_pixel
);
2442 XClearWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
2444 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2445 screen
->getWindowStyle()->b_pic_unfocus
);
2446 XDrawRectangle(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2447 2, 2, (frame
.button_w
- 5), (frame
.button_w
- 5));
2448 XDrawLine(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2449 2, 3, (frame
.button_w
- 3), 3);
2453 void BlackboxWindow::redrawCloseButton(bool pressed
) const {
2455 if (flags
.focused
) {
2457 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2460 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2461 frame
.fbutton_pixel
);
2464 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2467 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2468 frame
.ubutton_pixel
);
2472 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2473 frame
.close_button
, frame
.pbutton
);
2475 XSetWindowBackground(blackbox
->getXDisplay(),
2476 frame
.close_button
, frame
.pbutton_pixel
);
2478 XClearWindow(blackbox
->getXDisplay(), frame
.close_button
);
2480 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2481 screen
->getWindowStyle()->b_pic_unfocus
);
2482 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2483 2, 2, (frame
.button_w
- 3), (frame
.button_w
- 3));
2484 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2485 2, (frame
.button_w
- 3), (frame
.button_w
- 3), 2);
2489 void BlackboxWindow::mapRequestEvent(const XMapRequestEvent
*re
) {
2490 if (re
->window
!= client
.window
)
2494 fprintf(stderr
, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2498 switch (current_state
) {
2503 case WithdrawnState
:
2512 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2514 if (! blackbox
->isStartup()) {
2515 XSync(blackbox
->getXDisplay(), False
); // make sure the frame is mapped
2516 if (screen
->doFocusNew()|| (isTransient() && getTransientFor() &&
2517 getTransientFor()->isFocused())) {
2520 if (screen
->getPlacementPolicy() == BScreen::ClickMousePlacement
) {
2524 XQueryPointer(blackbox
->getXDisplay(), screen
->getRootWindow(),
2525 &r
, &c
, &rx
, &ry
, &x
, &y
, &m
);
2535 void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent
*ue
) {
2536 if (ue
->window
!= client
.window
)
2540 fprintf(stderr
, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2544 screen
->unmanageWindow(this, False
);
2548 void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent
*de
) {
2549 if (de
->window
!= client
.window
)
2553 fprintf(stderr
, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2557 screen
->unmanageWindow(this, False
);
2561 void BlackboxWindow::reparentNotifyEvent(const XReparentEvent
*re
) {
2562 if (re
->window
!= client
.window
|| re
->parent
== frame
.plate
)
2566 fprintf(stderr
, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2567 "0x%lx.\n", client
.window
, re
->parent
);
2572 XPutBackEvent(blackbox
->getXDisplay(), &ev
);
2573 screen
->unmanageWindow(this, True
);
2577 void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent
*pe
) {
2578 if (pe
->state
== PropertyDelete
)
2582 fprintf(stderr
, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n",
2588 case XA_WM_CLIENT_MACHINE
:
2592 case XA_WM_TRANSIENT_FOR
: {
2593 // determine if this is a transient window
2596 // adjust the window decorations based on transience
2597 if (isTransient()) {
2598 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2599 functions
&= ~Func_Maximize
;
2600 setAllowedActions();
2611 case XA_WM_ICON_NAME
:
2613 if (flags
.iconic
) screen
->propagateWindowName(this);
2616 case XAtom::net_wm_name
:
2620 if (decorations
& Decor_Titlebar
)
2623 screen
->propagateWindowName(this);
2626 case XA_WM_NORMAL_HINTS
: {
2629 if ((client
.normal_hint_flags
& PMinSize
) &&
2630 (client
.normal_hint_flags
& PMaxSize
)) {
2631 // the window now can/can't resize itself, so the buttons need to be
2634 if (client
.max_width
<= client
.min_width
&&
2635 client
.max_height
<= client
.min_height
) {
2636 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2637 functions
&= ~(Func_Resize
| Func_Maximize
);
2639 if (! isTransient()) {
2640 decorations
|= Decor_Maximize
| Decor_Handle
;
2641 functions
|= Func_Maximize
;
2643 functions
|= Func_Resize
;
2646 setAllowedActions();
2649 Rect old_rect
= frame
.rect
;
2653 if (old_rect
!= frame
.rect
)
2660 if (pe
->atom
== xatom
->getAtom(XAtom::wm_protocols
)) {
2663 if ((decorations
& Decor_Close
) && (! frame
.close_button
)) {
2664 createCloseButton();
2665 if (decorations
& Decor_Titlebar
) {
2666 positionButtons(True
);
2667 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
2669 if (windowmenu
) windowmenu
->reconfigure();
2671 } else if (pe
->atom
== xatom
->getAtom(XAtom::net_wm_strut
)) {
2680 void BlackboxWindow::exposeEvent(const XExposeEvent
*ee
) {
2682 fprintf(stderr
, "BlackboxWindow::exposeEvent() for 0x%lx\n", client
.window
);
2685 if (frame
.label
== ee
->window
&& (decorations
& Decor_Titlebar
))
2687 else if (frame
.close_button
== ee
->window
)
2688 redrawCloseButton(False
);
2689 else if (frame
.maximize_button
== ee
->window
)
2690 redrawMaximizeButton(flags
.maximized
);
2691 else if (frame
.iconify_button
== ee
->window
)
2692 redrawIconifyButton(False
);
2696 void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent
*cr
) {
2697 if (cr
->window
!= client
.window
|| flags
.iconic
)
2700 if (cr
->value_mask
& CWBorderWidth
)
2701 client
.old_bw
= cr
->border_width
;
2703 if (cr
->value_mask
& (CWX
| CWY
| CWWidth
| CWHeight
)) {
2704 Rect req
= frame
.rect
;
2706 if (cr
->value_mask
& (CWX
| CWY
)) {
2707 if (cr
->value_mask
& CWX
)
2708 client
.rect
.setX(cr
->x
);
2709 if (cr
->value_mask
& CWY
)
2710 client
.rect
.setY(cr
->y
);
2715 if (cr
->value_mask
& CWWidth
)
2716 req
.setWidth(cr
->width
+ frame
.margin
.left
+ frame
.margin
.right
);
2718 if (cr
->value_mask
& CWHeight
)
2719 req
.setHeight(cr
->height
+ frame
.margin
.top
+ frame
.margin
.bottom
);
2721 configure(req
.x(), req
.y(), req
.width(), req
.height());
2724 if (cr
->value_mask
& CWStackMode
&& !isDesktop()) {
2725 switch (cr
->detail
) {
2728 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2734 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2741 void BlackboxWindow::buttonPressEvent(const XButtonEvent
*be
) {
2743 fprintf(stderr
, "BlackboxWindow::buttonPressEvent() for 0x%lx\n",
2747 if (frame
.maximize_button
== be
->window
&& be
->button
<= 3) {
2748 redrawMaximizeButton(True
);
2749 } else if (be
->button
== 1 || (be
->button
== 3 && be
->state
== Mod1Mask
)) {
2750 if (! flags
.focused
)
2753 if (frame
.iconify_button
== be
->window
) {
2754 redrawIconifyButton(True
);
2755 } else if (frame
.close_button
== be
->window
) {
2756 redrawCloseButton(True
);
2757 } else if (frame
.plate
== be
->window
) {
2758 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2760 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2762 XAllowEvents(blackbox
->getXDisplay(), ReplayPointer
, be
->time
);
2764 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
2765 if (((be
->time
- lastButtonPressTime
) <=
2766 blackbox
->getDoubleClickInterval()) ||
2767 (be
->state
== ControlMask
)) {
2768 lastButtonPressTime
= 0;
2771 lastButtonPressTime
= be
->time
;
2775 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2777 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2779 } else if (be
->button
== 2 && (be
->window
!= frame
.iconify_button
) &&
2780 (be
->window
!= frame
.close_button
)) {
2781 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2782 } else if (windowmenu
&& be
->button
== 3 &&
2783 (frame
.title
== be
->window
|| frame
.label
== be
->window
||
2784 frame
.handle
== be
->window
|| frame
.window
== be
->window
)) {
2785 if (windowmenu
->isVisible()) {
2788 int mx
= be
->x_root
- windowmenu
->getWidth() / 2,
2789 my
= be
->y_root
- windowmenu
->getHeight() / 2;
2791 // snap the window menu into a corner/side if necessary
2792 int left_edge
, right_edge
, top_edge
, bottom_edge
;
2795 the " + (frame.border_w * 2) - 1" bits are to get the proper width
2796 and height of the menu, as the sizes returned by it do not include
2799 left_edge
= frame
.rect
.x();
2800 right_edge
= frame
.rect
.right() -
2801 (windowmenu
->getWidth() + (frame
.border_w
* 2) - 1);
2802 top_edge
= client
.rect
.top() - (frame
.border_w
+ frame
.mwm_border_w
);
2803 bottom_edge
= client
.rect
.bottom() -
2804 (windowmenu
->getHeight() + (frame
.border_w
* 2) - 1) +
2805 (frame
.border_w
+ frame
.mwm_border_w
);
2809 if (mx
> right_edge
)
2813 if (my
> bottom_edge
)
2816 windowmenu
->move(mx
, my
);
2818 XRaiseWindow(blackbox
->getXDisplay(), windowmenu
->getWindowID());
2819 XRaiseWindow(blackbox
->getXDisplay(),
2820 windowmenu
->getSendToMenu()->getWindowID());
2823 } else if (be
->button
== 4) {
2824 if ((be
->window
== frame
.label
||
2825 be
->window
== frame
.title
||
2826 be
->window
== frame
.maximize_button
||
2827 be
->window
== frame
.iconify_button
||
2828 be
->window
== frame
.close_button
) &&
2832 } else if (be
->button
== 5) {
2833 if ((be
->window
== frame
.label
||
2834 be
->window
== frame
.title
||
2835 be
->window
== frame
.maximize_button
||
2836 be
->window
== frame
.iconify_button
||
2837 be
->window
== frame
.close_button
) &&
2844 void BlackboxWindow::buttonReleaseEvent(const XButtonEvent
*re
) {
2846 fprintf(stderr
, "BlackboxWindow::buttonReleaseEvent() for 0x%lx\n",
2850 if (re
->window
== frame
.maximize_button
&&
2851 re
->button
>= 1 && re
->button
<= 3) {
2852 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2853 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2854 maximize(re
->button
);
2856 redrawMaximizeButton(flags
.maximized
);
2858 } else if (re
->window
== frame
.iconify_button
&& re
->button
== 1) {
2859 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2860 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2863 redrawIconifyButton(False
);
2865 } else if (re
->window
== frame
.close_button
& re
->button
== 1) {
2866 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2867 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
)))
2869 redrawCloseButton(False
);
2870 } else if (flags
.moving
) {
2872 } else if (flags
.resizing
) {
2874 } else if (re
->window
== frame
.window
) {
2875 if (re
->button
== 2 && re
->state
== Mod1Mask
)
2876 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
2882 void BlackboxWindow::beginMove(int x_root
, int y_root
) {
2883 assert(! (flags
.resizing
|| flags
.moving
));
2886 Only one window can be moved/resized at a time. If another window is already
2887 being moved or resized, then stop it before whating to work with this one.
2889 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
2890 if (changing
&& changing
!= this) {
2891 if (changing
->flags
.moving
)
2892 changing
->endMove();
2893 else // if (changing->flags.resizing)
2894 changing
->endResize();
2897 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
2898 PointerMotionMask
| ButtonReleaseMask
,
2899 GrabModeAsync
, GrabModeAsync
,
2900 None
, blackbox
->getMoveCursor(), CurrentTime
);
2902 if (windowmenu
&& windowmenu
->isVisible())
2905 flags
.moving
= True
;
2906 blackbox
->setChangingWindow(this);
2908 if (! screen
->doOpaqueMove()) {
2909 XGrabServer(blackbox
->getXDisplay());
2911 frame
.changing
= frame
.rect
;
2912 screen
->showPosition(frame
.changing
.x(), frame
.changing
.y());
2914 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2918 frame
.changing
.width() - 1,
2919 frame
.changing
.height() - 1);
2922 frame
.grab_x
= x_root
- frame
.rect
.x() - frame
.border_w
;
2923 frame
.grab_y
= y_root
- frame
.rect
.y() - frame
.border_w
;
2927 void BlackboxWindow::doMove(int x_root
, int y_root
) {
2928 assert(flags
.moving
);
2929 assert(blackbox
->getChangingWindow() == this);
2931 int dx
= x_root
- frame
.grab_x
, dy
= y_root
- frame
.grab_y
;
2932 dx
-= frame
.border_w
;
2933 dy
-= frame
.border_w
;
2935 const int snap_distance
= screen
->getEdgeSnapThreshold();
2937 if (snap_distance
) {
2939 const int wleft
= dx
,
2940 wright
= dx
+ frame
.rect
.width() - 1,
2942 wbottom
= dy
+ frame
.rect
.height() - 1;
2944 if (screen
->getWindowToWindowSnap()) {
2945 Workspace
*w
= screen
->getWorkspace(getWorkspaceNumber());
2948 // try snap to another window
2949 for (unsigned int i
= 0, c
= w
->getCount(); i
< c
; ++i
) {
2950 BlackboxWindow
*snapwin
= w
->getWindow(i
);
2951 if (snapwin
== this)
2952 continue; // don't snap to self
2954 bool snapped
= False
;
2956 const Rect
&winrect
= snapwin
->frameRect();
2957 int dleft
= std::abs(wright
- winrect
.left()),
2958 dright
= std::abs(wleft
- winrect
.right()),
2959 dtop
= std::abs(wbottom
- winrect
.top()),
2960 dbottom
= std::abs(wtop
- winrect
.bottom());
2962 if (wtop
>= (signed)(winrect
.y() - frame
.rect
.height() + 1) &&
2963 wtop
< (signed)(winrect
.y() + winrect
.height() - 1)) {
2965 // snap left of other window?
2966 if (dleft
< snap_distance
&& dleft
<= dright
) {
2967 dx
= winrect
.left() - frame
.rect
.width();
2970 // snap right of other window?
2971 else if (dright
< snap_distance
) {
2972 dx
= winrect
.right() + 1;
2977 if (screen
->getWindowCornerSnap()) {
2978 // try corner-snap to its other sides
2979 dtop
= std::abs(wtop
- winrect
.top());
2980 dbottom
= std::abs(wbottom
- winrect
.bottom());
2981 if (dtop
< snap_distance
&& dtop
<= dbottom
)
2983 else if (dbottom
< snap_distance
)
2984 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
2991 if (wleft
>= (signed)(winrect
.x() - frame
.rect
.width() + 1) &&
2992 wleft
< (signed)(winrect
.x() + winrect
.width() - 1)) {
2994 // snap top of other window?
2995 if (dtop
< snap_distance
&& dtop
<= dbottom
) {
2996 dy
= winrect
.top() - frame
.rect
.height();
2999 // snap bottom of other window?
3000 else if (dbottom
< snap_distance
) {
3001 dy
= winrect
.bottom() + 1;
3006 if (screen
->getWindowCornerSnap()) {
3007 // try corner-snap to its other sides
3008 dleft
= std::abs(wleft
- winrect
.left());
3009 dright
= std::abs(wright
- winrect
.right());
3010 if (dleft
< snap_distance
&& dleft
<= dright
)
3011 dx
= winrect
.left();
3012 else if (dright
< snap_distance
)
3013 dx
= winrect
.right() - frame
.rect
.width() + 1;
3022 // try snap to the screen's available area
3023 Rect srect
= screen
->availableArea();
3025 int dleft
= std::abs(wleft
- srect
.left()),
3026 dright
= std::abs(wright
- srect
.right()),
3027 dtop
= std::abs(wtop
- srect
.top()),
3028 dbottom
= std::abs(wbottom
- srect
.bottom());
3031 if (dleft
< snap_distance
&& dleft
<= dright
)
3034 else if (dright
< snap_distance
)
3035 dx
= srect
.right() - frame
.rect
.width() + 1;
3038 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3041 else if (dbottom
< snap_distance
)
3042 dy
= srect
.bottom() - frame
.rect
.height() + 1;
3044 srect
= screen
->getRect(); // now get the full screen
3046 dleft
= std::abs(wleft
- srect
.left()),
3047 dright
= std::abs(wright
- srect
.right()),
3048 dtop
= std::abs(wtop
- srect
.top()),
3049 dbottom
= std::abs(wbottom
- srect
.bottom());
3052 if (dleft
< snap_distance
&& dleft
<= dright
)
3055 else if (dright
< snap_distance
)
3056 dx
= srect
.right() - frame
.rect
.width() + 1;
3059 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3062 else if (dbottom
< snap_distance
)
3063 dy
= srect
.bottom() - frame
.rect
.height() + 1;
3066 if (screen
->doOpaqueMove()) {
3067 configure(dx
, dy
, frame
.rect
.width(), frame
.rect
.height());
3069 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3073 frame
.changing
.width() - 1,
3074 frame
.changing
.height() - 1);
3076 frame
.changing
.setPos(dx
, dy
);
3078 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3082 frame
.changing
.width() - 1,
3083 frame
.changing
.height() - 1);
3086 screen
->showPosition(dx
, dy
);
3090 void BlackboxWindow::endMove(void) {
3091 assert(flags
.moving
);
3092 assert(blackbox
->getChangingWindow() == this);
3094 flags
.moving
= False
;
3095 blackbox
->setChangingWindow(0);
3097 if (! screen
->doOpaqueMove()) {
3098 /* when drawing the rubber band, we need to make sure we only draw inside
3099 * the frame... frame.changing_* contain the new coords for the window,
3100 * so we need to subtract 1 from changing_w/changing_h every where we
3101 * draw the rubber band (for both moving and resizing)
3103 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3104 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3105 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3106 XUngrabServer(blackbox
->getXDisplay());
3108 configure(frame
.changing
.x(), frame
.changing
.y(),
3109 frame
.changing
.width(), frame
.changing
.height());
3111 configure(frame
.rect
.x(), frame
.rect
.y(),
3112 frame
.rect
.width(), frame
.rect
.height());
3114 screen
->hideGeometry();
3116 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3118 // if there are any left over motions from the move, drop them now
3119 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3121 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3126 void BlackboxWindow::beginResize(int x_root
, int y_root
, Corner dir
) {
3127 assert(! (flags
.resizing
|| flags
.moving
));
3130 Only one window can be moved/resized at a time. If another window is already
3131 being moved or resized, then stop it before whating to work with this one.
3133 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3134 if (changing
&& changing
!= this) {
3135 if (changing
->flags
.moving
)
3136 changing
->endMove();
3137 else // if (changing->flags.resizing)
3138 changing
->endResize();
3146 switch (resize_dir
) {
3149 cursor
= blackbox
->getLowerLeftAngleCursor();
3154 cursor
= blackbox
->getLowerRightAngleCursor();
3158 anchor
= BottomRight
;
3159 cursor
= blackbox
->getUpperLeftAngleCursor();
3163 anchor
= BottomLeft
;
3164 cursor
= blackbox
->getUpperRightAngleCursor();
3168 assert(false); // unhandled Corner
3169 return; // unreachable, for the compiler
3172 XGrabServer(blackbox
->getXDisplay());
3173 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3174 PointerMotionMask
| ButtonReleaseMask
,
3175 GrabModeAsync
, GrabModeAsync
, None
, cursor
, CurrentTime
);
3177 flags
.resizing
= True
;
3178 blackbox
->setChangingWindow(this);
3181 frame
.changing
= frame
.rect
;
3183 constrain(anchor
, &gw
, &gh
);
3185 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3186 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3187 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3189 screen
->showGeometry(gw
, gh
);
3191 frame
.grab_x
= x_root
;
3192 frame
.grab_y
= y_root
;
3196 void BlackboxWindow::doResize(int x_root
, int y_root
) {
3197 assert(flags
.resizing
);
3198 assert(blackbox
->getChangingWindow() == this);
3200 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3201 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3202 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3207 switch (resize_dir
) {
3210 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3211 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3215 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3216 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3219 anchor
= BottomRight
;
3220 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3221 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3224 anchor
= BottomLeft
;
3225 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3226 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3230 assert(false); // unhandled Corner
3231 return; // unreachable, for the compiler
3234 constrain(anchor
, &gw
, &gh
);
3236 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3237 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3238 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3240 screen
->showGeometry(gw
, gh
);
3244 void BlackboxWindow::endResize(void) {
3245 assert(flags
.resizing
);
3246 assert(blackbox
->getChangingWindow() == this);
3248 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3249 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3250 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3251 XUngrabServer(blackbox
->getXDisplay());
3253 // unset maximized state after resized when fully maximized
3254 if (flags
.maximized
== 1)
3257 flags
.resizing
= False
;
3258 blackbox
->setChangingWindow(0);
3260 configure(frame
.changing
.x(), frame
.changing
.y(),
3261 frame
.changing
.width(), frame
.changing
.height());
3262 screen
->hideGeometry();
3264 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3266 // if there are any left over motions from the resize, drop them now
3267 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3269 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3274 void BlackboxWindow::motionNotifyEvent(const XMotionEvent
*me
) {
3276 fprintf(stderr
, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n",
3281 doMove(me
->x_root
, me
->y_root
);
3282 } else if (flags
.resizing
) {
3283 doResize(me
->x_root
, me
->y_root
);
3285 if (!flags
.resizing
&& me
->state
& Button1Mask
&& (functions
& Func_Move
) &&
3286 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3287 frame
.handle
== me
->window
|| frame
.window
== me
->window
)) {
3288 beginMove(me
->x_root
, me
->y_root
);
3289 } else if ((functions
& Func_Resize
) &&
3290 (me
->state
& Button1Mask
&& (me
->window
== frame
.right_grip
||
3291 me
->window
== frame
.left_grip
)) ||
3292 (me
->state
& Button3Mask
&& me
->state
& Mod1Mask
&&
3293 me
->window
== frame
.window
)) {
3294 unsigned int zones
= screen
->getResizeZones();
3297 if (me
->window
== frame
.left_grip
) {
3298 corner
= BottomLeft
;
3299 } else if (me
->window
== frame
.right_grip
|| zones
== 1) {
3300 corner
= BottomRight
;
3303 bool left
= (me
->x_root
- frame
.rect
.x() <=
3304 static_cast<signed>(frame
.rect
.width() / 2));
3307 else // (zones == 4)
3308 top
= (me
->y_root
- frame
.rect
.y() <=
3309 static_cast<signed>(frame
.rect
.height() / 2));
3310 corner
= (top
? (left
? TopLeft
: TopRight
) :
3311 (left
? BottomLeft
: BottomRight
));
3314 beginResize(me
->x_root
, me
->y_root
, corner
);
3321 void BlackboxWindow::shapeEvent(XShapeEvent
*) {
3322 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
3329 bool BlackboxWindow::validateClient(void) const {
3330 XSync(blackbox
->getXDisplay(), False
);
3333 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3334 DestroyNotify
, &e
) ||
3335 XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3337 XPutBackEvent(blackbox
->getXDisplay(), &e
);
3346 void BlackboxWindow::restore(bool remap
) {
3347 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeDelete
);
3348 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
3349 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, NoEventMask
);
3351 // do not leave a shaded window as an icon unless it was an icon
3352 if (flags
.shaded
&& ! flags
.iconic
) setState(NormalState
);
3354 restoreGravity(client
.rect
);
3356 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
3357 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
3359 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, client
.old_bw
);
3362 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3363 ReparentNotify
, &ev
)) {
3366 // according to the ICCCM - if the client doesn't reparent to
3367 // root, then we have to do it for them
3368 XReparentWindow(blackbox
->getXDisplay(), client
.window
,
3369 screen
->getRootWindow(),
3370 client
.rect
.x(), client
.rect
.y());
3373 if (remap
) XMapWindow(blackbox
->getXDisplay(), client
.window
);
3377 // timer for autoraise
3378 void BlackboxWindow::timeout(void) {
3379 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3383 void BlackboxWindow::changeBlackboxHints(BlackboxHints
*net
) {
3384 if ((net
->flags
& AttribShaded
) &&
3385 ((blackbox_attrib
.attrib
& AttribShaded
) !=
3386 (net
->attrib
& AttribShaded
)))
3389 if (flags
.visible
&& // watch out for requests when we can not be seen
3390 (net
->flags
& (AttribMaxVert
| AttribMaxHoriz
)) &&
3391 ((blackbox_attrib
.attrib
& (AttribMaxVert
| AttribMaxHoriz
)) !=
3392 (net
->attrib
& (AttribMaxVert
| AttribMaxHoriz
)))) {
3393 if (flags
.maximized
) {
3398 if ((net
->flags
& AttribMaxHoriz
) && (net
->flags
& AttribMaxVert
))
3399 button
= ((net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0);
3400 else if (net
->flags
& AttribMaxVert
)
3401 button
= ((net
->attrib
& AttribMaxVert
) ? 2 : 0);
3402 else if (net
->flags
& AttribMaxHoriz
)
3403 button
= ((net
->attrib
& AttribMaxHoriz
) ? 3 : 0);
3409 if ((net
->flags
& AttribOmnipresent
) &&
3410 ((blackbox_attrib
.attrib
& AttribOmnipresent
) !=
3411 (net
->attrib
& AttribOmnipresent
)))
3414 if ((net
->flags
& AttribWorkspace
) &&
3415 (blackbox_attrib
.workspace
!= net
->workspace
)) {
3416 screen
->reassociateWindow(this, net
->workspace
, True
);
3418 if (screen
->getCurrentWorkspaceID() != net
->workspace
) {
3422 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3426 if (net
->flags
& AttribDecoration
) {
3427 switch (net
->decoration
) {
3429 // clear all decorations except close
3430 decorations
&= Decor_Close
;
3436 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Iconify
;
3438 decorations
= ((functions
& Func_Resize
) && !isTransient() ?
3439 decorations
| Decor_Handle
:
3440 decorations
&= ~Decor_Handle
);
3441 decorations
= (functions
& Func_Maximize
?
3442 decorations
| Decor_Maximize
:
3443 decorations
&= ~Decor_Maximize
);
3448 decorations
|= Decor_Titlebar
| Decor_Iconify
;
3449 decorations
&= ~(Decor_Border
| Decor_Handle
);
3451 decorations
= (functions
& Func_Maximize
?
3452 decorations
| Decor_Maximize
:
3453 decorations
&= ~Decor_Maximize
);
3458 decorations
|= Decor_Titlebar
;
3459 decorations
&= ~(Decor_Iconify
| Decor_Border
);
3461 decorations
= ((functions
& Func_Resize
) && !isTransient() ?
3462 decorations
| Decor_Handle
:
3463 decorations
&= ~Decor_Handle
);
3464 decorations
= (functions
& Func_Maximize
?
3465 decorations
| Decor_Maximize
:
3466 decorations
&= ~Decor_Maximize
);
3471 // we can not be shaded if we lack a titlebar
3472 if (flags
.shaded
&& ! (decorations
& Decor_Titlebar
))
3475 if (flags
.visible
&& frame
.window
) {
3476 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
3477 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
3481 setState(current_state
);
3487 * Set the sizes of all components of the window frame
3488 * (the window decorations).
3489 * These values are based upon the current style settings and the client
3490 * window's dimensions.
3492 void BlackboxWindow::upsize(void) {
3493 frame
.bevel_w
= screen
->getBevelWidth();
3495 if (decorations
& Decor_Border
) {
3496 frame
.border_w
= screen
->getBorderWidth();
3497 if (! isTransient())
3498 frame
.mwm_border_w
= screen
->getFrameWidth();
3500 frame
.mwm_border_w
= 0;
3502 frame
.mwm_border_w
= frame
.border_w
= 0;
3505 if (decorations
& Decor_Titlebar
) {
3506 // the height of the titlebar is based upon the height of the font being
3507 // used to display the window's title
3508 WindowStyle
*style
= screen
->getWindowStyle();
3509 frame
.title_h
= style
->font
->height() + (frame
.bevel_w
* 2) + 2;
3511 frame
.label_h
= frame
.title_h
- (frame
.bevel_w
* 2);
3512 frame
.button_w
= (frame
.label_h
- 2);
3514 // set the top frame margin
3515 frame
.margin
.top
= frame
.border_w
+ frame
.title_h
+
3516 frame
.border_w
+ frame
.mwm_border_w
;
3522 // set the top frame margin
3523 frame
.margin
.top
= frame
.border_w
+ frame
.mwm_border_w
;
3526 // set the left/right frame margin
3527 frame
.margin
.left
= frame
.margin
.right
= frame
.border_w
+ frame
.mwm_border_w
;
3529 if (decorations
& Decor_Handle
) {
3530 frame
.grip_w
= frame
.button_w
* 2;
3531 frame
.handle_h
= screen
->getHandleWidth();
3533 // set the bottom frame margin
3534 frame
.margin
.bottom
= frame
.border_w
+ frame
.handle_h
+
3535 frame
.border_w
+ frame
.mwm_border_w
;
3540 // set the bottom frame margin
3541 frame
.margin
.bottom
= frame
.border_w
+ frame
.mwm_border_w
;
3545 We first get the normal dimensions and use this to define the inside_w/h
3546 then we modify the height if shading is in effect.
3547 If the shade state is not considered then frame.rect gets reset to the
3548 normal window size on a reconfigure() call resulting in improper
3549 dimensions appearing in move/resize and other events.
3552 height
= client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
,
3553 width
= client
.rect
.width() + frame
.margin
.left
+ frame
.margin
.right
;
3555 frame
.inside_w
= width
- (frame
.border_w
* 2);
3556 frame
.inside_h
= height
- (frame
.border_w
* 2);
3559 height
= frame
.title_h
+ (frame
.border_w
* 2);
3560 frame
.rect
.setSize(width
, height
);
3565 * Calculate the size of the client window and constrain it to the
3566 * size specified by the size hints of the client window.
3568 * The logical width and height are placed into pw and ph, if they
3569 * are non-zero. Logical size refers to the users perception of
3570 * the window size (for example an xterm resizes in cells, not in pixels).
3572 * The physical geometry is placed into frame.changing_{x,y,width,height}.
3573 * Physical geometry refers to the geometry of the window in pixels.
3575 void BlackboxWindow::constrain(Corner anchor
, int *pw
, int *ph
) {
3576 // frame.changing represents the requested frame size, we need to
3577 // strip the frame margin off and constrain the client size
3578 frame
.changing
.setCoords(frame
.changing
.left() + frame
.margin
.left
,
3579 frame
.changing
.top() + frame
.margin
.top
,
3580 frame
.changing
.right() - frame
.margin
.right
,
3581 frame
.changing
.bottom() - frame
.margin
.bottom
);
3583 int dw
= frame
.changing
.width(), dh
= frame
.changing
.height(),
3584 base_width
= (client
.base_width
) ? client
.base_width
: client
.min_width
,
3585 base_height
= (client
.base_height
) ? client
.base_height
:
3589 if (dw
< static_cast<signed>(client
.min_width
)) dw
= client
.min_width
;
3590 if (dh
< static_cast<signed>(client
.min_height
)) dh
= client
.min_height
;
3591 if (dw
> static_cast<signed>(client
.max_width
)) dw
= client
.max_width
;
3592 if (dh
> static_cast<signed>(client
.max_height
)) dh
= client
.max_height
;
3595 dw
/= client
.width_inc
;
3597 dh
/= client
.height_inc
;
3600 if (client
.width_inc
== 1)
3601 *pw
= dw
+ base_width
;
3606 if (client
.height_inc
== 1)
3607 *ph
= dh
+ base_height
;
3612 dw
*= client
.width_inc
;
3614 dh
*= client
.height_inc
;
3617 frame
.changing
.setSize(dw
, dh
);
3619 // add the frame margin back onto frame.changing
3620 frame
.changing
.setCoords(frame
.changing
.left() - frame
.margin
.left
,
3621 frame
.changing
.top() - frame
.margin
.top
,
3622 frame
.changing
.right() + frame
.margin
.right
,
3623 frame
.changing
.bottom() + frame
.margin
.bottom
);
3625 // move frame.changing to the specified anchor
3633 dx
= frame
.rect
.right() - frame
.changing
.right();
3637 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3641 dx
= frame
.rect
.right() - frame
.changing
.right();
3642 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3646 assert(false); // unhandled corner
3648 frame
.changing
.setPos(frame
.changing
.x() + dx
, frame
.changing
.y() + dy
);
3652 void WindowStyle::doJustify(const std::string
&text
, int &start_pos
,
3653 unsigned int max_length
,
3654 unsigned int modifier
) const {
3655 size_t text_len
= text
.size();
3656 unsigned int length
;
3659 length
= font
->measureString(string(text
, 0, text_len
)) + modifier
;
3660 } while (length
> max_length
&& text_len
-- > 0);
3664 start_pos
+= max_length
- length
;
3668 start_pos
+= (max_length
- length
) / 2;
3678 BWindowGroup::BWindowGroup(Blackbox
*b
, Window _group
)
3679 : blackbox(b
), group(_group
) {
3680 XWindowAttributes wattrib
;
3681 if (! XGetWindowAttributes(blackbox
->getXDisplay(), group
, &wattrib
)) {
3682 // group window doesn't seem to exist anymore
3687 XSelectInput(blackbox
->getXDisplay(), group
,
3688 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
3690 blackbox
->saveGroupSearch(group
, this);
3694 BWindowGroup::~BWindowGroup(void) {
3695 blackbox
->removeGroupSearch(group
);
3700 BWindowGroup::find(BScreen
*screen
, bool allow_transients
) const {
3701 BlackboxWindow
*ret
= blackbox
->getFocusedWindow();
3703 // does the focus window match (or any transient_fors)?
3705 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3706 if (ret
->isTransient() && allow_transients
) break;
3707 else if (! ret
->isTransient()) break;
3710 ret
= ret
->getTransientFor();
3713 if (ret
) return ret
;
3715 // the focus window didn't match, look in the group's window list
3716 BlackboxWindowList::const_iterator it
, end
= windowList
.end();
3717 for (it
= windowList
.begin(); it
!= end
; ++it
) {
3719 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3720 if (ret
->isTransient() && allow_transients
) break;
3721 else if (! ret
->isTransient()) break;