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
,
826 screen
->allowScrollLock());
828 if (functions
& Func_Move
)
829 blackbox
->grabButton(Button1
, Mod1Mask
, frame
.window
, True
,
830 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
831 GrabModeAsync
, frame
.window
, None
,
832 screen
->allowScrollLock());
833 if (functions
& Func_Resize
)
834 blackbox
->grabButton(Button3
, Mod1Mask
, frame
.window
, True
,
835 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
836 GrabModeAsync
, frame
.window
, None
,
837 screen
->allowScrollLock());
838 // alt+middle lowers the window
839 blackbox
->grabButton(Button2
, Mod1Mask
, frame
.window
, True
,
840 ButtonReleaseMask
, GrabModeAsync
, GrabModeAsync
,
842 screen
->allowScrollLock());
846 void BlackboxWindow::ungrabButtons(void) {
847 if ((! screen
->isSloppyFocus()) || screen
->doClickRaise())
848 blackbox
->ungrabButton(Button1
, 0, frame
.plate
);
850 blackbox
->ungrabButton(Button1
, Mod1Mask
, frame
.window
);
851 blackbox
->ungrabButton(Button2
, Mod1Mask
, frame
.window
);
852 blackbox
->ungrabButton(Button3
, Mod1Mask
, frame
.window
);
856 void BlackboxWindow::positionWindows(void) {
857 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.window
,
858 frame
.rect
.x(), frame
.rect
.y(), frame
.inside_w
,
859 (flags
.shaded
) ? frame
.title_h
: frame
.inside_h
);
860 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.window
,
862 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.plate
,
864 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.plate
,
865 frame
.margin
.left
- frame
.mwm_border_w
- frame
.border_w
,
866 frame
.margin
.top
- frame
.mwm_border_w
- frame
.border_w
,
867 client
.rect
.width(), client
.rect
.height());
868 XMoveResizeWindow(blackbox
->getXDisplay(), client
.window
,
869 0, 0, client
.rect
.width(), client
.rect
.height());
870 // ensure client.rect contains the real location
871 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
872 frame
.rect
.top() + frame
.margin
.top
);
874 if (decorations
& Decor_Titlebar
) {
875 if (frame
.title
== None
) createTitlebar();
877 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.title
,
879 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.title
, -frame
.border_w
,
880 -frame
.border_w
, frame
.inside_w
, frame
.title_h
);
883 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
884 XMapWindow(blackbox
->getXDisplay(), frame
.title
);
885 } else if (frame
.title
) {
888 if (decorations
& Decor_Handle
) {
889 if (frame
.handle
== None
) createHandle();
890 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.handle
,
892 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.left_grip
,
894 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.right_grip
,
897 // use client.rect here so the value is correct even if shaded
898 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.handle
,
900 client
.rect
.height() + frame
.margin
.top
+
901 frame
.mwm_border_w
- frame
.border_w
,
902 frame
.inside_w
, frame
.handle_h
);
903 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.left_grip
,
904 -frame
.border_w
, -frame
.border_w
,
905 frame
.grip_w
, frame
.handle_h
);
906 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.right_grip
,
907 frame
.inside_w
- frame
.grip_w
- frame
.border_w
,
908 -frame
.border_w
, frame
.grip_w
, frame
.handle_h
);
910 XMapSubwindows(blackbox
->getXDisplay(), frame
.handle
);
911 XMapWindow(blackbox
->getXDisplay(), frame
.handle
);
912 } else if (frame
.handle
) {
915 XSync(blackbox
->getXDisplay(), False
);
919 void BlackboxWindow::updateStrut(void) {
920 unsigned long num
= 4;
922 if (! xatom
->getValue(client
.window
, XAtom::net_wm_strut
, XAtom::cardinal
,
927 client
.strut
.left
= data
[0];
928 client
.strut
.right
= data
[1];
929 client
.strut
.top
= data
[2];
930 client
.strut
.bottom
= data
[3];
932 screen
->updateAvailableArea();
939 void BlackboxWindow::getWindowType(void) {
941 if (xatom
->getValue(client
.window
, XAtom::net_wm_window_type
, XAtom::atom
,
943 if (val
== xatom
->getAtom(XAtom::net_wm_window_type_desktop
))
944 window_type
= Type_Desktop
;
945 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_dock
))
946 window_type
= Type_Dock
;
947 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_toolbar
))
948 window_type
= Type_Toolbar
;
949 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_menu
))
950 window_type
= Type_Menu
;
951 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_utility
))
952 window_type
= Type_Utility
;
953 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_splash
))
954 window_type
= Type_Splash
;
955 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_dialog
))
956 window_type
= Type_Dialog
;
957 else //if (val[0] == xatom->getAtom(XAtom::net_wm_window_type_normal))
958 window_type
= Type_Normal
;
963 * the window type hint was not set, which means we either classify ourself
964 * as a normal window or a dialog, depending on if we are a transient.
967 window_type
= Type_Dialog
;
969 window_type
= Type_Normal
;
973 void BlackboxWindow::getWMName(void) {
974 if (xatom
->getValue(client
.window
, XAtom::net_wm_name
,
975 XAtom::utf8
, client
.title
) &&
976 !client
.title
.empty()) {
977 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
980 //fall through to using WM_NAME
981 if (xatom
->getValue(client
.window
, XAtom::wm_name
, XAtom::ansi
, client
.title
)
982 && !client
.title
.empty()) {
983 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
986 // fall back to an internal default
987 client
.title
= i18n(WindowSet
, WindowUnnamed
, "Unnamed");
988 xatom
->setValue(client
.window
, XAtom::net_wm_visible_name
, XAtom::utf8
,
993 void BlackboxWindow::getWMIconName(void) {
994 if (xatom
->getValue(client
.window
, XAtom::net_wm_icon_name
,
995 XAtom::utf8
, client
.icon_title
) &&
996 !client
.icon_title
.empty()) {
997 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1000 //fall through to using WM_ICON_NAME
1001 if (xatom
->getValue(client
.window
, XAtom::wm_icon_name
, XAtom::ansi
,
1002 client
.icon_title
) &&
1003 !client
.icon_title
.empty()) {
1004 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1007 // fall back to using the main name
1008 client
.icon_title
= client
.title
;
1009 xatom
->setValue(client
.window
, XAtom::net_wm_visible_icon_name
, XAtom::utf8
,
1015 * Retrieve which WM Protocols are supported by the client window.
1016 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
1017 * window's decorations and allow the close behavior.
1018 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
1021 void BlackboxWindow::getWMProtocols(void) {
1025 if (XGetWMProtocols(blackbox
->getXDisplay(), client
.window
,
1026 &proto
, &num_return
)) {
1027 for (int i
= 0; i
< num_return
; ++i
) {
1028 if (proto
[i
] == xatom
->getAtom(XAtom::wm_delete_window
)) {
1029 decorations
|= Decor_Close
;
1030 functions
|= Func_Close
;
1031 } else if (proto
[i
] == xatom
->getAtom(XAtom::wm_take_focus
))
1032 flags
.send_focus_message
= True
;
1033 else if (proto
[i
] == xatom
->getAtom(XAtom::blackbox_structure_messages
))
1034 screen
->addNetizen(new Netizen(screen
, client
.window
));
1043 * Gets the value of the WM_HINTS property.
1044 * If the property is not set, then use a set of default values.
1046 void BlackboxWindow::getWMHints(void) {
1047 focus_mode
= F_Passive
;
1048 client
.initial_state
= NormalState
;
1050 // remove from current window group
1051 if (client
.window_group
) {
1052 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1053 if (group
) group
->removeWindow(this);
1055 client
.window_group
= None
;
1057 XWMHints
*wmhint
= XGetWMHints(blackbox
->getXDisplay(), client
.window
);
1062 if (wmhint
->flags
& InputHint
) {
1063 if (wmhint
->input
== True
) {
1064 if (flags
.send_focus_message
)
1065 focus_mode
= F_LocallyActive
;
1067 if (flags
.send_focus_message
)
1068 focus_mode
= F_GloballyActive
;
1070 focus_mode
= F_NoInput
;
1074 if (wmhint
->flags
& StateHint
)
1075 client
.initial_state
= wmhint
->initial_state
;
1077 if (wmhint
->flags
& WindowGroupHint
) {
1078 client
.window_group
= wmhint
->window_group
;
1080 // add window to the appropriate group
1081 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1082 if (! group
) { // no group found, create it!
1083 new BWindowGroup(blackbox
, client
.window_group
);
1084 group
= blackbox
->searchGroup(client
.window_group
);
1087 group
->addWindow(this);
1090 client
.wm_hint_flags
= wmhint
->flags
;
1096 * Gets the value of the WM_NORMAL_HINTS property.
1097 * If the property is not set, then use a set of default values.
1099 void BlackboxWindow::getWMNormalHints(void) {
1101 XSizeHints sizehint
;
1103 client
.min_width
= client
.min_height
=
1104 client
.width_inc
= client
.height_inc
= 1;
1105 client
.base_width
= client
.base_height
= 0;
1106 client
.win_gravity
= NorthWestGravity
;
1108 client
.min_aspect_x
= client
.min_aspect_y
=
1109 client
.max_aspect_x
= client
.max_aspect_y
= 1;
1113 use the full screen, not the strut modified size. otherwise when the
1114 availableArea changes max_width/height will be incorrect and lead to odd
1117 const Rect
& screen_area
= screen
->getRect();
1118 client
.max_width
= screen_area
.width();
1119 client
.max_height
= screen_area
.height();
1121 if (! XGetWMNormalHints(blackbox
->getXDisplay(), client
.window
,
1122 &sizehint
, &icccm_mask
))
1125 client
.normal_hint_flags
= sizehint
.flags
;
1127 if (sizehint
.flags
& PMinSize
) {
1128 if (sizehint
.min_width
>= 0)
1129 client
.min_width
= sizehint
.min_width
;
1130 if (sizehint
.min_height
>= 0)
1131 client
.min_height
= sizehint
.min_height
;
1134 if (sizehint
.flags
& PMaxSize
) {
1135 if (sizehint
.max_width
> static_cast<signed>(client
.min_width
))
1136 client
.max_width
= sizehint
.max_width
;
1138 client
.max_width
= client
.min_width
;
1140 if (sizehint
.max_height
> static_cast<signed>(client
.min_height
))
1141 client
.max_height
= sizehint
.max_height
;
1143 client
.max_height
= client
.min_height
;
1146 if (sizehint
.flags
& PResizeInc
) {
1147 client
.width_inc
= sizehint
.width_inc
;
1148 client
.height_inc
= sizehint
.height_inc
;
1151 #if 0 // we do not support this at the moment
1152 if (sizehint
.flags
& PAspect
) {
1153 client
.min_aspect_x
= sizehint
.min_aspect
.x
;
1154 client
.min_aspect_y
= sizehint
.min_aspect
.y
;
1155 client
.max_aspect_x
= sizehint
.max_aspect
.x
;
1156 client
.max_aspect_y
= sizehint
.max_aspect
.y
;
1160 if (sizehint
.flags
& PBaseSize
) {
1161 client
.base_width
= sizehint
.base_width
;
1162 client
.base_height
= sizehint
.base_height
;
1165 if (sizehint
.flags
& PWinGravity
)
1166 client
.win_gravity
= sizehint
.win_gravity
;
1171 * Gets the NETWM hints for the class' contained window.
1173 void BlackboxWindow::getNetWMHints(void) {
1174 unsigned long workspace
;
1176 if (xatom
->getValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1178 if (workspace
== 0xffffffff)
1181 blackbox_attrib
.workspace
= workspace
;
1184 unsigned long *state
;
1185 unsigned long num
= (unsigned) -1;
1186 if (xatom
->getValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
1190 for (unsigned long i
= 0; i
< num
; ++i
) {
1191 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
))
1193 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_shaded
))
1194 flags
.shaded
= True
;
1195 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
))
1196 flags
.skip_taskbar
= True
;
1197 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_pager
))
1198 flags
.skip_pager
= True
;
1199 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_fullscreen
))
1200 flags
.fullscreen
= True
;
1201 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_hidden
))
1202 setState(IconicState
);
1203 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_vert
))
1205 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_horz
))
1209 flags
.maximized
= 1;
1211 flags
.maximized
= 2;
1213 flags
.maximized
= 3;
1221 * Gets the MWM hints for the class' contained window.
1222 * This is used while initializing the window to its first state, and not
1224 * Returns: true if the MWM hints are successfully retreived and applied;
1225 * false if they are not.
1227 void BlackboxWindow::getMWMHints(void) {
1231 num
= PropMwmHintsElements
;
1232 if (! xatom
->getValue(client
.window
, XAtom::motif_wm_hints
,
1233 XAtom::motif_wm_hints
, num
,
1234 (unsigned long **)&mwm_hint
))
1236 if (num
< PropMwmHintsElements
) {
1241 if (mwm_hint
->flags
& MwmHintsDecorations
) {
1242 if (mwm_hint
->decorations
& MwmDecorAll
) {
1243 decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
1244 Decor_Iconify
| Decor_Maximize
| Decor_Close
;
1248 if (mwm_hint
->decorations
& MwmDecorBorder
)
1249 decorations
|= Decor_Border
;
1250 if (mwm_hint
->decorations
& MwmDecorHandle
)
1251 decorations
|= Decor_Handle
;
1252 if (mwm_hint
->decorations
& MwmDecorTitle
)
1253 decorations
|= Decor_Titlebar
;
1254 if (mwm_hint
->decorations
& MwmDecorIconify
)
1255 decorations
|= Decor_Iconify
;
1256 if (mwm_hint
->decorations
& MwmDecorMaximize
)
1257 decorations
|= Decor_Maximize
;
1261 if (mwm_hint
->flags
& MwmHintsFunctions
) {
1262 if (mwm_hint
->functions
& MwmFuncAll
) {
1263 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
|
1268 if (mwm_hint
->functions
& MwmFuncResize
)
1269 functions
|= Func_Resize
;
1270 if (mwm_hint
->functions
& MwmFuncMove
)
1271 functions
|= Func_Move
;
1272 if (mwm_hint
->functions
& MwmFuncIconify
)
1273 functions
|= Func_Iconify
;
1274 if (mwm_hint
->functions
& MwmFuncMaximize
)
1275 functions
|= Func_Maximize
;
1276 if (mwm_hint
->functions
& MwmFuncClose
)
1277 functions
|= Func_Close
;
1285 * Gets the blackbox hints from the class' contained window.
1286 * This is used while initializing the window to its first state, and not
1288 * Returns: true if the hints are successfully retreived and applied; false if
1291 bool BlackboxWindow::getBlackboxHints(void) {
1293 BlackboxHints
*blackbox_hint
;
1295 num
= PropBlackboxHintsElements
;
1296 if (! xatom
->getValue(client
.window
, XAtom::blackbox_hints
,
1297 XAtom::blackbox_hints
, num
,
1298 (unsigned long **)&blackbox_hint
))
1300 if (num
< PropBlackboxHintsElements
) {
1301 delete [] blackbox_hint
;
1305 if (blackbox_hint
->flags
& AttribShaded
)
1306 flags
.shaded
= (blackbox_hint
->attrib
& AttribShaded
);
1308 if ((blackbox_hint
->flags
& AttribMaxHoriz
) &&
1309 (blackbox_hint
->flags
& AttribMaxVert
))
1310 flags
.maximized
= (blackbox_hint
->attrib
&
1311 (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1312 else if (blackbox_hint
->flags
& AttribMaxVert
)
1313 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxVert
) ? 2 : 0;
1314 else if (blackbox_hint
->flags
& AttribMaxHoriz
)
1315 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1317 if (blackbox_hint
->flags
& AttribOmnipresent
)
1318 flags
.stuck
= (blackbox_hint
->attrib
& AttribOmnipresent
);
1320 if (blackbox_hint
->flags
& AttribWorkspace
)
1321 blackbox_attrib
.workspace
= blackbox_hint
->workspace
;
1323 // if (blackbox_hint->flags & AttribStack)
1324 // don't yet have always on top/bottom for blackbox yet... working
1327 if (blackbox_hint
->flags
& AttribDecoration
) {
1328 switch (blackbox_hint
->decoration
) {
1330 // clear all decorations except close
1331 decorations
&= Decor_Close
;
1332 // clear all functions except close
1333 functions
&= Func_Close
;
1338 decorations
|= Decor_Titlebar
| Decor_Iconify
;
1339 decorations
&= ~(Decor_Border
| Decor_Handle
| Decor_Maximize
);
1340 functions
|= Func_Move
| Func_Iconify
;
1341 functions
&= ~(Func_Resize
| Func_Maximize
);
1346 decorations
|= Decor_Titlebar
;
1347 decorations
&= ~(Decor_Iconify
| Decor_Border
| Decor_Handle
);
1348 functions
|= Func_Move
;
1349 functions
&= ~(Func_Resize
| Func_Maximize
| Func_Iconify
);
1355 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Handle
|
1356 Decor_Iconify
| Decor_Maximize
;
1357 functions
|= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
1365 delete [] blackbox_hint
;
1371 void BlackboxWindow::getTransientInfo(void) {
1372 if (client
.transient_for
&&
1373 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1374 // the transient for hint was removed, so we need to tell our
1375 // previous transient_for that we are going away
1376 client
.transient_for
->client
.transientList
.remove(this);
1379 // we have no transient_for until we find a new one
1380 client
.transient_for
= 0;
1383 if (! XGetTransientForHint(blackbox
->getXDisplay(), client
.window
,
1385 // transient_for hint not set
1389 if (trans_for
== client
.window
) {
1390 // wierd client... treat this window as a normal window
1394 if (trans_for
== None
|| trans_for
== screen
->getRootWindow()) {
1395 // this is an undocumented interpretation of the ICCCM. a transient
1396 // associated with None/Root/itself is assumed to be a modal root
1397 // transient. we don't support the concept of a global transient,
1398 // so we just associate this transient with nothing, and perhaps
1399 // we will add support later for global modality.
1400 client
.transient_for
= (BlackboxWindow
*) ~0ul;
1405 client
.transient_for
= blackbox
->searchWindow(trans_for
);
1406 if (! client
.transient_for
&&
1407 client
.window_group
&& trans_for
== client
.window_group
) {
1408 // no direct transient_for, perhaps this is a group transient?
1409 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1410 if (group
) client
.transient_for
= group
->find(screen
);
1413 if (! client
.transient_for
|| client
.transient_for
== this) {
1414 // no transient_for found, or we have a wierd client that wants to be
1415 // a transient for itself, so we treat this window as a normal window
1416 client
.transient_for
= (BlackboxWindow
*) 0;
1420 // register ourselves with our new transient_for
1421 client
.transient_for
->client
.transientList
.push_back(this);
1422 flags
.stuck
= client
.transient_for
->flags
.stuck
;
1426 BlackboxWindow
*BlackboxWindow::getTransientFor(void) const {
1427 if (client
.transient_for
&&
1428 client
.transient_for
!= (BlackboxWindow
*) ~0ul)
1429 return client
.transient_for
;
1435 * This function is responsible for updating both the client and the frame
1437 * According to the ICCCM a client message is not sent for a resize, only a
1440 void BlackboxWindow::configure(int dx
, int dy
,
1441 unsigned int dw
, unsigned int dh
) {
1442 bool send_event
= ((frame
.rect
.x() != dx
|| frame
.rect
.y() != dy
) &&
1445 if (dw
!= frame
.rect
.width() || dh
!= frame
.rect
.height()) {
1446 frame
.rect
.setRect(dx
, dy
, dw
, dh
);
1447 frame
.inside_w
= frame
.rect
.width() - (frame
.border_w
* 2);
1448 frame
.inside_h
= frame
.rect
.height() - (frame
.border_w
* 2);
1450 if (frame
.rect
.right() <= 0 || frame
.rect
.bottom() <= 0)
1451 frame
.rect
.setPos(0, 0);
1453 client
.rect
.setCoords(frame
.rect
.left() + frame
.margin
.left
,
1454 frame
.rect
.top() + frame
.margin
.top
,
1455 frame
.rect
.right() - frame
.margin
.right
,
1456 frame
.rect
.bottom() - frame
.margin
.bottom
);
1459 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
1466 redrawWindowFrame();
1468 frame
.rect
.setPos(dx
, dy
);
1470 XMoveWindow(blackbox
->getXDisplay(), frame
.window
,
1471 frame
.rect
.x(), frame
.rect
.y());
1473 we may have been called just after an opaque window move, so even though
1474 the old coords match the new ones no ConfigureNotify has been sent yet.
1475 There are likely other times when this will be relevant as well.
1477 if (! flags
.moving
) send_event
= True
;
1481 // if moving, the update and event will occur when the move finishes
1482 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1483 frame
.rect
.top() + frame
.margin
.top
);
1486 event
.type
= ConfigureNotify
;
1488 event
.xconfigure
.display
= blackbox
->getXDisplay();
1489 event
.xconfigure
.event
= client
.window
;
1490 event
.xconfigure
.window
= client
.window
;
1491 event
.xconfigure
.x
= client
.rect
.x();
1492 event
.xconfigure
.y
= client
.rect
.y();
1493 event
.xconfigure
.width
= client
.rect
.width();
1494 event
.xconfigure
.height
= client
.rect
.height();
1495 event
.xconfigure
.border_width
= client
.old_bw
;
1496 event
.xconfigure
.above
= frame
.window
;
1497 event
.xconfigure
.override_redirect
= False
;
1499 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1500 StructureNotifyMask
, &event
);
1501 screen
->updateNetizenConfigNotify(&event
);
1502 XFlush(blackbox
->getXDisplay());
1508 void BlackboxWindow::configureShape(void) {
1509 XShapeCombineShape(blackbox
->getXDisplay(), frame
.window
, ShapeBounding
,
1510 frame
.margin
.left
- frame
.border_w
,
1511 frame
.margin
.top
- frame
.border_w
,
1512 client
.window
, ShapeBounding
, ShapeSet
);
1515 XRectangle xrect
[2];
1517 if (decorations
& Decor_Titlebar
) {
1518 xrect
[0].x
= xrect
[0].y
= -frame
.border_w
;
1519 xrect
[0].width
= frame
.rect
.width();
1520 xrect
[0].height
= frame
.title_h
+ (frame
.border_w
* 2);
1524 if (decorations
& Decor_Handle
) {
1525 xrect
[1].x
= -frame
.border_w
;
1526 xrect
[1].y
= frame
.rect
.height() - frame
.margin
.bottom
+
1527 frame
.mwm_border_w
- frame
.border_w
;
1528 xrect
[1].width
= frame
.rect
.width();
1529 xrect
[1].height
= frame
.handle_h
+ (frame
.border_w
* 2);
1533 XShapeCombineRectangles(blackbox
->getXDisplay(), frame
.window
,
1534 ShapeBounding
, 0, 0, xrect
, num
,
1535 ShapeUnion
, Unsorted
);
1540 bool BlackboxWindow::setInputFocus(void) {
1541 if (flags
.focused
) return True
;
1543 assert(! flags
.iconic
&&
1544 (flags
.stuck
|| // window must be on the current workspace or sticky
1545 blackbox_attrib
.workspace
== screen
->getCurrentWorkspaceID()));
1547 // if the window is not visible, mark the window as wanting focus rather
1548 // than give it focus.
1549 if (! flags
.visible
) {
1550 Workspace
*wkspc
= screen
->getWorkspace(blackbox_attrib
.workspace
);
1551 wkspc
->setLastFocusedWindow(this);
1556 We only do this check for normal windows and dialogs because other windows
1557 do this on purpose, such as kde's kicker, and we don't want to go moving
1560 if (window_type
== Type_Normal
|| window_type
== Type_Dialog
)
1561 if (! frame
.rect
.intersects(screen
->getRect())) {
1562 // client is outside the screen, move it to the center
1563 configure((screen
->getWidth() - frame
.rect
.width()) / 2,
1564 (screen
->getHeight() - frame
.rect
.height()) / 2,
1565 frame
.rect
.width(), frame
.rect
.height());
1568 if (client
.transientList
.size() > 0) {
1569 // transfer focus to any modal transients
1570 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1571 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1572 if ((*it
)->flags
.modal
) return (*it
)->setInputFocus();
1577 if (focus_mode
== F_LocallyActive
|| focus_mode
== F_Passive
) {
1578 XSetInputFocus(blackbox
->getXDisplay(), client
.window
,
1579 RevertToPointerRoot
, CurrentTime
);
1581 blackbox
->setFocusedWindow(this);
1583 /* we could set the focus to none, since the window doesn't accept focus,
1584 * but we shouldn't set focus to nothing since this would surely make
1590 if (flags
.send_focus_message
) {
1592 ce
.xclient
.type
= ClientMessage
;
1593 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1594 ce
.xclient
.display
= blackbox
->getXDisplay();
1595 ce
.xclient
.window
= client
.window
;
1596 ce
.xclient
.format
= 32;
1597 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_take_focus
);
1598 ce
.xclient
.data
.l
[1] = blackbox
->getLastTime();
1599 ce
.xclient
.data
.l
[2] = 0l;
1600 ce
.xclient
.data
.l
[3] = 0l;
1601 ce
.xclient
.data
.l
[4] = 0l;
1602 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1604 XFlush(blackbox
->getXDisplay());
1611 void BlackboxWindow::iconify(void) {
1612 if (flags
.iconic
) return;
1614 // We don't need to worry about resizing because resizing always grabs the X
1615 // server. This should only ever happen if using opaque moving.
1619 if (windowmenu
) windowmenu
->hide();
1622 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1623 * we need to clear the event mask on client.window for a split second.
1624 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1625 * split second, leaving us with a ghost window... so, we need to do this
1626 * while the X server is grabbed
1628 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1629 StructureNotifyMask
;
1630 XGrabServer(blackbox
->getXDisplay());
1631 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1632 event_mask
& ~StructureNotifyMask
);
1633 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1634 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1635 XUngrabServer(blackbox
->getXDisplay());
1637 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1638 flags
.visible
= False
;
1639 flags
.iconic
= True
;
1641 setState(IconicState
);
1643 screen
->getWorkspace(blackbox_attrib
.workspace
)->removeWindow(this);
1645 if (isTransient()) {
1646 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1647 ! client
.transient_for
->flags
.iconic
) {
1648 // iconify our transient_for
1649 client
.transient_for
->iconify();
1653 screen
->addIcon(this);
1655 if (client
.transientList
.size() > 0) {
1656 // iconify all transients
1657 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1658 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1659 if (! (*it
)->flags
.iconic
) (*it
)->iconify();
1662 screen
->updateStackingList();
1666 void BlackboxWindow::show(void) {
1667 flags
.visible
= True
;
1668 flags
.iconic
= False
;
1670 current_state
= (flags
.shaded
) ? IconicState
: NormalState
;
1671 setState(current_state
);
1673 XMapWindow(blackbox
->getXDisplay(), client
.window
);
1674 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
1675 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
1680 XTranslateCoordinates(blackbox
->getXDisplay(), client
.window
,
1681 screen
->getRootWindow(),
1682 0, 0, &real_x
, &real_y
, &child
);
1683 fprintf(stderr
, "%s -- assumed: (%d, %d), real: (%d, %d)\n", getTitle(),
1684 client
.rect
.left(), client
.rect
.top(), real_x
, real_y
);
1685 assert(client
.rect
.left() == real_x
&& client
.rect
.top() == real_y
);
1690 void BlackboxWindow::deiconify(bool reassoc
, bool raise
) {
1691 if (flags
.iconic
|| reassoc
)
1692 screen
->reassociateWindow(this, BSENTINEL
, False
);
1693 else if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID())
1698 // reassociate and deiconify all transients
1699 if (reassoc
&& client
.transientList
.size() > 0) {
1700 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1701 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1702 (*it
)->deiconify(True
, False
);
1707 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1711 void BlackboxWindow::close(void) {
1713 ce
.xclient
.type
= ClientMessage
;
1714 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1715 ce
.xclient
.display
= blackbox
->getXDisplay();
1716 ce
.xclient
.window
= client
.window
;
1717 ce
.xclient
.format
= 32;
1718 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_delete_window
);
1719 ce
.xclient
.data
.l
[1] = CurrentTime
;
1720 ce
.xclient
.data
.l
[2] = 0l;
1721 ce
.xclient
.data
.l
[3] = 0l;
1722 ce
.xclient
.data
.l
[4] = 0l;
1723 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
, NoEventMask
, &ce
);
1724 XFlush(blackbox
->getXDisplay());
1728 void BlackboxWindow::withdraw(void) {
1729 // We don't need to worry about resizing because resizing always grabs the X
1730 // server. This should only ever happen if using opaque moving.
1734 flags
.visible
= False
;
1735 flags
.iconic
= False
;
1737 setState(current_state
);
1739 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1741 XGrabServer(blackbox
->getXDisplay());
1743 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1744 StructureNotifyMask
;
1745 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1746 event_mask
& ~StructureNotifyMask
);
1747 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1748 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1750 XUngrabServer(blackbox
->getXDisplay());
1752 if (windowmenu
) windowmenu
->hide();
1756 void BlackboxWindow::maximize(unsigned int button
) {
1757 // We don't need to worry about resizing because resizing always grabs the X
1758 // server. This should only ever happen if using opaque moving.
1762 // handle case where menu is open then the max button is used instead
1763 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
1765 if (flags
.maximized
) {
1766 flags
.maximized
= 0;
1768 blackbox_attrib
.flags
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1769 blackbox_attrib
.attrib
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1772 when a resize finishes, maximize(0) is called to clear any maximization
1773 flags currently set. Otherwise it still thinks it is maximized.
1774 so we do not need to call configure() because resizing will handle it
1776 if (! flags
.resizing
)
1777 configure(blackbox_attrib
.premax_x
, blackbox_attrib
.premax_y
,
1778 blackbox_attrib
.premax_w
, blackbox_attrib
.premax_h
);
1780 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
1781 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
1783 redrawAllButtons(); // in case it is not called in configure()
1784 setState(current_state
);
1788 blackbox_attrib
.premax_x
= frame
.rect
.x();
1789 blackbox_attrib
.premax_y
= frame
.rect
.y();
1790 blackbox_attrib
.premax_w
= frame
.rect
.width();
1791 // use client.rect so that clients can be restored even if shaded
1792 blackbox_attrib
.premax_h
=
1793 client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
;
1795 const Rect
&screen_area
= screen
->availableArea();
1796 frame
.changing
= screen_area
;
1800 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1801 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1805 blackbox_attrib
.flags
|= AttribMaxVert
;
1806 blackbox_attrib
.attrib
|= AttribMaxVert
;
1808 frame
.changing
.setX(frame
.rect
.x());
1809 frame
.changing
.setWidth(frame
.rect
.width());
1813 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1814 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1816 frame
.changing
.setY(frame
.rect
.y());
1817 frame
.changing
.setHeight(frame
.rect
.height());
1824 blackbox_attrib
.flags
^= AttribShaded
;
1825 blackbox_attrib
.attrib
^= AttribShaded
;
1826 flags
.shaded
= False
;
1829 flags
.maximized
= button
;
1831 configure(frame
.changing
.x(), frame
.changing
.y(),
1832 frame
.changing
.width(), frame
.changing
.height());
1834 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1835 redrawAllButtons(); // in case it is not called in configure()
1836 setState(current_state
);
1840 // re-maximizes the window to take into account availableArea changes
1841 void BlackboxWindow::remaximize(void) {
1842 // save the original dimensions because maximize will wipe them out
1843 int premax_x
= blackbox_attrib
.premax_x
,
1844 premax_y
= blackbox_attrib
.premax_y
,
1845 premax_w
= blackbox_attrib
.premax_w
,
1846 premax_h
= blackbox_attrib
.premax_h
;
1848 unsigned int button
= flags
.maximized
;
1849 flags
.maximized
= 0; // trick maximize() into working
1852 // restore saved values
1853 blackbox_attrib
.premax_x
= premax_x
;
1854 blackbox_attrib
.premax_y
= premax_y
;
1855 blackbox_attrib
.premax_w
= premax_w
;
1856 blackbox_attrib
.premax_h
= premax_h
;
1860 void BlackboxWindow::setWorkspace(unsigned int n
) {
1861 blackbox_attrib
.flags
|= AttribWorkspace
;
1862 blackbox_attrib
.workspace
= n
;
1863 if (n
== BSENTINEL
) { // iconified window
1865 we set the workspace to 'all workspaces' so that taskbars will show the
1866 window. otherwise, it made uniconifying a window imposible without the
1867 blackbox workspace menu
1871 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
, n
);
1875 void BlackboxWindow::shade(void) {
1877 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1878 frame
.inside_w
, frame
.inside_h
);
1879 flags
.shaded
= False
;
1880 blackbox_attrib
.flags
^= AttribShaded
;
1881 blackbox_attrib
.attrib
^= AttribShaded
;
1883 setState(NormalState
);
1885 // set the frame rect to the normal size
1886 frame
.rect
.setHeight(client
.rect
.height() + frame
.margin
.top
+
1887 frame
.margin
.bottom
);
1889 if (! (decorations
& Decor_Titlebar
))
1890 return; // can't shade it without a titlebar!
1892 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1893 frame
.inside_w
, frame
.title_h
);
1894 flags
.shaded
= True
;
1895 blackbox_attrib
.flags
|= AttribShaded
;
1896 blackbox_attrib
.attrib
|= AttribShaded
;
1898 setState(IconicState
);
1900 // set the frame rect to the shaded size
1901 frame
.rect
.setHeight(frame
.title_h
+ (frame
.border_w
* 2));
1907 * (Un)Sticks a window and its relatives.
1909 void BlackboxWindow::stick(void) {
1911 blackbox_attrib
.flags
^= AttribOmnipresent
;
1912 blackbox_attrib
.attrib
^= AttribOmnipresent
;
1914 flags
.stuck
= False
;
1917 screen
->reassociateWindow(this, BSENTINEL
, True
);
1918 // temporary fix since sticky windows suck. set the hint to what we
1919 // actually hold in our data.
1920 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1921 blackbox_attrib
.workspace
);
1923 setState(current_state
);
1927 blackbox_attrib
.flags
|= AttribOmnipresent
;
1928 blackbox_attrib
.attrib
|= AttribOmnipresent
;
1930 // temporary fix since sticky windows suck. set the hint to a different
1931 // value than that contained in the class' data.
1932 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1935 setState(current_state
);
1938 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1939 client
.transient_for
->isStuck() != flags
.stuck
)
1940 client
.transient_for
->stick();
1941 // go down the chain
1942 BlackboxWindowList::iterator it
;
1943 const BlackboxWindowList::iterator end
= client
.transientList
.end();
1944 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1945 if ((*it
)->isStuck() != flags
.stuck
)
1950 void BlackboxWindow::redrawWindowFrame(void) const {
1951 if (decorations
& Decor_Titlebar
) {
1952 if (flags
.focused
) {
1954 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1955 frame
.title
, frame
.ftitle
);
1957 XSetWindowBackground(blackbox
->getXDisplay(),
1958 frame
.title
, frame
.ftitle_pixel
);
1961 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1962 frame
.title
, frame
.utitle
);
1964 XSetWindowBackground(blackbox
->getXDisplay(),
1965 frame
.title
, frame
.utitle_pixel
);
1967 XClearWindow(blackbox
->getXDisplay(), frame
.title
);
1973 if (decorations
& Decor_Handle
) {
1974 if (flags
.focused
) {
1976 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1977 frame
.handle
, frame
.fhandle
);
1979 XSetWindowBackground(blackbox
->getXDisplay(),
1980 frame
.handle
, frame
.fhandle_pixel
);
1983 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1984 frame
.left_grip
, frame
.fgrip
);
1985 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1986 frame
.right_grip
, frame
.fgrip
);
1988 XSetWindowBackground(blackbox
->getXDisplay(),
1989 frame
.left_grip
, frame
.fgrip_pixel
);
1990 XSetWindowBackground(blackbox
->getXDisplay(),
1991 frame
.right_grip
, frame
.fgrip_pixel
);
1995 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1996 frame
.handle
, frame
.uhandle
);
1998 XSetWindowBackground(blackbox
->getXDisplay(),
1999 frame
.handle
, frame
.uhandle_pixel
);
2002 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2003 frame
.left_grip
, frame
.ugrip
);
2004 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2005 frame
.right_grip
, frame
.ugrip
);
2007 XSetWindowBackground(blackbox
->getXDisplay(),
2008 frame
.left_grip
, frame
.ugrip_pixel
);
2009 XSetWindowBackground(blackbox
->getXDisplay(),
2010 frame
.right_grip
, frame
.ugrip_pixel
);
2013 XClearWindow(blackbox
->getXDisplay(), frame
.handle
);
2014 XClearWindow(blackbox
->getXDisplay(), frame
.left_grip
);
2015 XClearWindow(blackbox
->getXDisplay(), frame
.right_grip
);
2018 if (decorations
& Decor_Border
) {
2020 XSetWindowBorder(blackbox
->getXDisplay(),
2021 frame
.plate
, frame
.fborder_pixel
);
2023 XSetWindowBorder(blackbox
->getXDisplay(),
2024 frame
.plate
, frame
.uborder_pixel
);
2029 void BlackboxWindow::setFocusFlag(bool focus
) {
2030 // only focus a window if it is visible
2031 if (focus
&& !flags
.visible
)
2034 flags
.focused
= focus
;
2036 redrawWindowFrame();
2038 if (screen
->isSloppyFocus() && screen
->doAutoRaise()) {
2039 if (isFocused()) timer
->start();
2044 blackbox
->setFocusedWindow(this);
2046 Clientmenu
*menu
= screen
->getWorkspace(blackbox_attrib
.workspace
)->getMenu();
2047 menu
->setItemSelected(window_number
, isFocused());
2051 void BlackboxWindow::installColormap(bool install
) {
2052 int i
= 0, ncmap
= 0;
2053 Colormap
*cmaps
= XListInstalledColormaps(blackbox
->getXDisplay(),
2054 client
.window
, &ncmap
);
2056 XWindowAttributes wattrib
;
2057 if (XGetWindowAttributes(blackbox
->getXDisplay(),
2058 client
.window
, &wattrib
)) {
2060 // install the window's colormap
2061 for (i
= 0; i
< ncmap
; i
++) {
2062 if (*(cmaps
+ i
) == wattrib
.colormap
)
2063 // this window is using an installed color map... do not install
2066 // otherwise, install the window's colormap
2068 XInstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2070 // uninstall the window's colormap
2071 for (i
= 0; i
< ncmap
; i
++) {
2072 if (*(cmaps
+ i
) == wattrib
.colormap
)
2073 // we found the colormap to uninstall
2074 XUninstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2084 void BlackboxWindow::setAllowedActions(void) {
2088 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_shade
);
2089 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_change_desktop
);
2090 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_close
);
2092 if (functions
& Func_Move
)
2093 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_move
);
2094 if (functions
& Func_Resize
)
2095 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_resize
);
2096 if (functions
& Func_Maximize
) {
2097 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_horz
);
2098 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_vert
);
2101 xatom
->setValue(client
.window
, XAtom::net_wm_allowed_actions
, XAtom::atom
,
2106 void BlackboxWindow::setState(unsigned long new_state
) {
2107 current_state
= new_state
;
2109 unsigned long state
[2];
2110 state
[0] = current_state
;
2112 xatom
->setValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
, state
, 2);
2114 xatom
->setValue(client
.window
, XAtom::blackbox_attributes
,
2115 XAtom::blackbox_attributes
, (unsigned long *)&blackbox_attrib
,
2116 PropBlackboxAttributesElements
);
2121 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_modal
);
2123 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_shaded
);
2125 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_hidden
);
2126 if (flags
.skip_taskbar
)
2127 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
);
2128 if (flags
.skip_pager
)
2129 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_pager
);
2130 if (flags
.fullscreen
)
2131 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_fullscreen
);
2132 if (flags
.maximized
== 1 || flags
.maximized
== 2)
2133 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_vert
);
2134 if (flags
.maximized
== 1 || flags
.maximized
== 3)
2135 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_horz
);
2136 xatom
->setValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
2141 bool BlackboxWindow::getState(void) {
2142 bool ret
= xatom
->getValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
,
2144 if (! ret
) current_state
= 0;
2149 void BlackboxWindow::restoreAttributes(void) {
2150 unsigned long num
= PropBlackboxAttributesElements
;
2151 BlackboxAttributes
*net
;
2152 if (! xatom
->getValue(client
.window
, XAtom::blackbox_attributes
,
2153 XAtom::blackbox_attributes
, num
,
2154 (unsigned long **)&net
))
2156 if (num
< PropBlackboxAttributesElements
) {
2161 if (net
->flags
& AttribShaded
&& net
->attrib
& AttribShaded
) {
2162 flags
.shaded
= False
;
2163 unsigned long orig_state
= current_state
;
2167 At this point in the life of a window, current_state should only be set
2168 to IconicState if the window was an *icon*, not if it was shaded.
2170 if (orig_state
!= IconicState
)
2171 current_state
= WithdrawnState
;
2174 if (net
->workspace
!= screen
->getCurrentWorkspaceID() &&
2175 net
->workspace
< screen
->getWorkspaceCount())
2176 screen
->reassociateWindow(this, net
->workspace
, True
);
2178 if ((blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID()) &&
2179 (blackbox_attrib
.workspace
< screen
->getWorkspaceCount())) {
2180 // set to WithdrawnState so it will be mapped on the new workspace
2181 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2182 } else if (current_state
== WithdrawnState
) {
2183 // the window is on this workspace and is Withdrawn, so it is waiting to
2185 current_state
= NormalState
;
2188 if (net
->flags
& AttribOmnipresent
&& net
->attrib
& AttribOmnipresent
) {
2189 flags
.stuck
= False
;
2192 // if the window was on another workspace, it was going to be hidden. this
2193 // specifies that the window should be mapped since it is sticky.
2194 if (current_state
== WithdrawnState
) current_state
= NormalState
;
2197 if (net
->flags
& AttribMaxHoriz
|| net
->flags
& AttribMaxVert
) {
2198 int x
= net
->premax_x
, y
= net
->premax_y
;
2199 unsigned int w
= net
->premax_w
, h
= net
->premax_h
;
2200 flags
.maximized
= 0;
2203 if ((net
->flags
& AttribMaxHoriz
) &&
2204 (net
->flags
& AttribMaxVert
))
2205 m
= (net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
2206 else if (net
->flags
& AttribMaxVert
)
2207 m
= (net
->attrib
& AttribMaxVert
) ? 2 : 0;
2208 else if (net
->flags
& AttribMaxHoriz
)
2209 m
= (net
->attrib
& AttribMaxHoriz
) ? 3 : 0;
2213 blackbox_attrib
.premax_x
= x
;
2214 blackbox_attrib
.premax_y
= y
;
2215 blackbox_attrib
.premax_w
= w
;
2216 blackbox_attrib
.premax_h
= h
;
2219 // with the state set it will then be the map event's job to read the
2220 // window's state and behave accordingly
2227 * Positions the Rect r according the the client window position and
2230 void BlackboxWindow::applyGravity(Rect
&r
) {
2231 // apply horizontal window gravity
2232 switch (client
.win_gravity
) {
2234 case NorthWestGravity
:
2235 case SouthWestGravity
:
2237 r
.setX(client
.rect
.x());
2243 r
.setX(client
.rect
.x() - (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2246 case NorthEastGravity
:
2247 case SouthEastGravity
:
2249 r
.setX(client
.rect
.x() - frame
.margin
.left
- frame
.margin
.right
+ 2);
2254 r
.setX(client
.rect
.x() - frame
.margin
.left
);
2258 // apply vertical window gravity
2259 switch (client
.win_gravity
) {
2261 case NorthWestGravity
:
2262 case NorthEastGravity
:
2264 r
.setY(client
.rect
.y());
2270 r
.setY(client
.rect
.y() - (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2273 case SouthWestGravity
:
2274 case SouthEastGravity
:
2276 r
.setY(client
.rect
.y() - frame
.margin
.top
- frame
.margin
.bottom
+ 2);
2281 r
.setY(client
.rect
.y() - frame
.margin
.top
);
2288 * The reverse of the applyGravity function.
2290 * Positions the Rect r according to the frame window position and
2293 void BlackboxWindow::restoreGravity(Rect
&r
) {
2294 // restore horizontal window gravity
2295 switch (client
.win_gravity
) {
2297 case NorthWestGravity
:
2298 case SouthWestGravity
:
2300 r
.setX(frame
.rect
.x());
2306 r
.setX(frame
.rect
.x() + (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2309 case NorthEastGravity
:
2310 case SouthEastGravity
:
2312 r
.setX(frame
.rect
.x() + frame
.margin
.left
+ frame
.margin
.right
- 2);
2317 r
.setX(frame
.rect
.x() + frame
.margin
.left
);
2321 // restore vertical window gravity
2322 switch (client
.win_gravity
) {
2324 case NorthWestGravity
:
2325 case NorthEastGravity
:
2327 r
.setY(frame
.rect
.y());
2333 r
.setY(frame
.rect
.y() + (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2336 case SouthWestGravity
:
2337 case SouthEastGravity
:
2339 r
.setY(frame
.rect
.y() + frame
.margin
.top
+ frame
.margin
.bottom
- 2);
2344 r
.setY(frame
.rect
.y() + frame
.margin
.top
);
2350 void BlackboxWindow::redrawLabel(void) const {
2351 if (flags
.focused
) {
2353 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2354 frame
.label
, frame
.flabel
);
2356 XSetWindowBackground(blackbox
->getXDisplay(),
2357 frame
.label
, frame
.flabel_pixel
);
2360 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2361 frame
.label
, frame
.ulabel
);
2363 XSetWindowBackground(blackbox
->getXDisplay(),
2364 frame
.label
, frame
.ulabel_pixel
);
2366 XClearWindow(blackbox
->getXDisplay(), frame
.label
);
2368 WindowStyle
*style
= screen
->getWindowStyle();
2370 int pos
= frame
.bevel_w
* 2;
2371 style
->doJustify(client
.title
.c_str(), pos
, frame
.label_w
, frame
.bevel_w
* 4);
2372 style
->font
->drawString(frame
.label
, pos
, 1,
2373 (flags
.focused
? style
->l_text_focus
:
2374 style
->l_text_unfocus
),
2379 void BlackboxWindow::redrawAllButtons(void) const {
2380 if (frame
.iconify_button
) redrawIconifyButton(False
);
2381 if (frame
.maximize_button
) redrawMaximizeButton(flags
.maximized
);
2382 if (frame
.close_button
) redrawCloseButton(False
);
2386 void BlackboxWindow::redrawIconifyButton(bool pressed
) const {
2388 if (flags
.focused
) {
2390 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2391 frame
.iconify_button
, frame
.fbutton
);
2393 XSetWindowBackground(blackbox
->getXDisplay(),
2394 frame
.iconify_button
, frame
.fbutton_pixel
);
2397 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2398 frame
.iconify_button
, frame
.ubutton
);
2400 XSetWindowBackground(blackbox
->getXDisplay(), frame
.iconify_button
,
2401 frame
.ubutton_pixel
);
2405 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2406 frame
.iconify_button
, frame
.pbutton
);
2408 XSetWindowBackground(blackbox
->getXDisplay(),
2409 frame
.iconify_button
, frame
.pbutton_pixel
);
2411 XClearWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
2413 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2414 screen
->getWindowStyle()->b_pic_unfocus
);
2415 XDrawRectangle(blackbox
->getXDisplay(), frame
.iconify_button
, pen
.gc(),
2416 2, (frame
.button_w
- 5), (frame
.button_w
- 5), 2);
2420 void BlackboxWindow::redrawMaximizeButton(bool pressed
) const {
2422 if (flags
.focused
) {
2424 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2425 frame
.maximize_button
, frame
.fbutton
);
2427 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2428 frame
.fbutton_pixel
);
2431 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2432 frame
.maximize_button
, frame
.ubutton
);
2434 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2435 frame
.ubutton_pixel
);
2439 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2440 frame
.maximize_button
, frame
.pbutton
);
2442 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2443 frame
.pbutton_pixel
);
2445 XClearWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
2447 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2448 screen
->getWindowStyle()->b_pic_unfocus
);
2449 XDrawRectangle(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2450 2, 2, (frame
.button_w
- 5), (frame
.button_w
- 5));
2451 XDrawLine(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2452 2, 3, (frame
.button_w
- 3), 3);
2456 void BlackboxWindow::redrawCloseButton(bool pressed
) const {
2458 if (flags
.focused
) {
2460 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2463 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2464 frame
.fbutton_pixel
);
2467 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2470 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2471 frame
.ubutton_pixel
);
2475 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2476 frame
.close_button
, frame
.pbutton
);
2478 XSetWindowBackground(blackbox
->getXDisplay(),
2479 frame
.close_button
, frame
.pbutton_pixel
);
2481 XClearWindow(blackbox
->getXDisplay(), frame
.close_button
);
2483 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2484 screen
->getWindowStyle()->b_pic_unfocus
);
2485 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2486 2, 2, (frame
.button_w
- 3), (frame
.button_w
- 3));
2487 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2488 2, (frame
.button_w
- 3), (frame
.button_w
- 3), 2);
2492 void BlackboxWindow::mapRequestEvent(const XMapRequestEvent
*re
) {
2493 if (re
->window
!= client
.window
)
2497 fprintf(stderr
, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2501 switch (current_state
) {
2506 case WithdrawnState
:
2515 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2517 if (! blackbox
->isStartup()) {
2518 XSync(blackbox
->getXDisplay(), False
); // make sure the frame is mapped
2519 if (screen
->doFocusNew()|| (isTransient() && getTransientFor() &&
2520 getTransientFor()->isFocused())) {
2523 if (screen
->getPlacementPolicy() == BScreen::ClickMousePlacement
) {
2527 XQueryPointer(blackbox
->getXDisplay(), screen
->getRootWindow(),
2528 &r
, &c
, &rx
, &ry
, &x
, &y
, &m
);
2538 void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent
*ue
) {
2539 if (ue
->window
!= client
.window
)
2543 fprintf(stderr
, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2547 screen
->unmanageWindow(this, False
);
2551 void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent
*de
) {
2552 if (de
->window
!= client
.window
)
2556 fprintf(stderr
, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2560 screen
->unmanageWindow(this, False
);
2564 void BlackboxWindow::reparentNotifyEvent(const XReparentEvent
*re
) {
2565 if (re
->window
!= client
.window
|| re
->parent
== frame
.plate
)
2569 fprintf(stderr
, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2570 "0x%lx.\n", client
.window
, re
->parent
);
2575 XPutBackEvent(blackbox
->getXDisplay(), &ev
);
2576 screen
->unmanageWindow(this, True
);
2580 void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent
*pe
) {
2581 if (pe
->state
== PropertyDelete
)
2585 fprintf(stderr
, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n",
2591 case XA_WM_CLIENT_MACHINE
:
2595 case XA_WM_TRANSIENT_FOR
: {
2596 // determine if this is a transient window
2599 // adjust the window decorations based on transience
2600 if (isTransient()) {
2601 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2602 functions
&= ~Func_Maximize
;
2603 setAllowedActions();
2614 case XA_WM_ICON_NAME
:
2616 if (flags
.iconic
) screen
->propagateWindowName(this);
2619 case XAtom::net_wm_name
:
2623 if (decorations
& Decor_Titlebar
)
2626 screen
->propagateWindowName(this);
2629 case XA_WM_NORMAL_HINTS
: {
2632 if ((client
.normal_hint_flags
& PMinSize
) &&
2633 (client
.normal_hint_flags
& PMaxSize
)) {
2634 // the window now can/can't resize itself, so the buttons need to be
2637 if (client
.max_width
<= client
.min_width
&&
2638 client
.max_height
<= client
.min_height
) {
2639 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2640 functions
&= ~(Func_Resize
| Func_Maximize
);
2642 if (! isTransient()) {
2643 decorations
|= Decor_Maximize
| Decor_Handle
;
2644 functions
|= Func_Maximize
;
2646 functions
|= Func_Resize
;
2649 setAllowedActions();
2652 Rect old_rect
= frame
.rect
;
2656 if (old_rect
!= frame
.rect
)
2663 if (pe
->atom
== xatom
->getAtom(XAtom::wm_protocols
)) {
2666 if ((decorations
& Decor_Close
) && (! frame
.close_button
)) {
2667 createCloseButton();
2668 if (decorations
& Decor_Titlebar
) {
2669 positionButtons(True
);
2670 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
2672 if (windowmenu
) windowmenu
->reconfigure();
2674 } else if (pe
->atom
== xatom
->getAtom(XAtom::net_wm_strut
)) {
2683 void BlackboxWindow::exposeEvent(const XExposeEvent
*ee
) {
2685 fprintf(stderr
, "BlackboxWindow::exposeEvent() for 0x%lx\n", client
.window
);
2688 if (frame
.label
== ee
->window
&& (decorations
& Decor_Titlebar
))
2690 else if (frame
.close_button
== ee
->window
)
2691 redrawCloseButton(False
);
2692 else if (frame
.maximize_button
== ee
->window
)
2693 redrawMaximizeButton(flags
.maximized
);
2694 else if (frame
.iconify_button
== ee
->window
)
2695 redrawIconifyButton(False
);
2699 void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent
*cr
) {
2700 if (cr
->window
!= client
.window
|| flags
.iconic
)
2703 if (cr
->value_mask
& CWBorderWidth
)
2704 client
.old_bw
= cr
->border_width
;
2706 if (cr
->value_mask
& (CWX
| CWY
| CWWidth
| CWHeight
)) {
2707 Rect req
= frame
.rect
;
2709 if (cr
->value_mask
& (CWX
| CWY
)) {
2710 if (cr
->value_mask
& CWX
)
2711 client
.rect
.setX(cr
->x
);
2712 if (cr
->value_mask
& CWY
)
2713 client
.rect
.setY(cr
->y
);
2718 if (cr
->value_mask
& CWWidth
)
2719 req
.setWidth(cr
->width
+ frame
.margin
.left
+ frame
.margin
.right
);
2721 if (cr
->value_mask
& CWHeight
)
2722 req
.setHeight(cr
->height
+ frame
.margin
.top
+ frame
.margin
.bottom
);
2724 configure(req
.x(), req
.y(), req
.width(), req
.height());
2727 if (cr
->value_mask
& CWStackMode
&& !isDesktop()) {
2728 switch (cr
->detail
) {
2731 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2737 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2744 void BlackboxWindow::buttonPressEvent(const XButtonEvent
*be
) {
2746 fprintf(stderr
, "BlackboxWindow::buttonPressEvent() for 0x%lx\n",
2750 if (frame
.maximize_button
== be
->window
&& be
->button
<= 3) {
2751 redrawMaximizeButton(True
);
2752 } else if (be
->button
== 1 || (be
->button
== 3 && be
->state
== Mod1Mask
)) {
2753 if (! flags
.focused
)
2756 if (frame
.iconify_button
== be
->window
) {
2757 redrawIconifyButton(True
);
2758 } else if (frame
.close_button
== be
->window
) {
2759 redrawCloseButton(True
);
2760 } else if (frame
.plate
== be
->window
) {
2761 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2763 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2765 XAllowEvents(blackbox
->getXDisplay(), ReplayPointer
, be
->time
);
2767 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
2768 if (((be
->time
- lastButtonPressTime
) <=
2769 blackbox
->getDoubleClickInterval()) ||
2770 (be
->state
== ControlMask
)) {
2771 lastButtonPressTime
= 0;
2774 lastButtonPressTime
= be
->time
;
2778 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2780 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2782 } else if (be
->button
== 2 && (be
->window
!= frame
.iconify_button
) &&
2783 (be
->window
!= frame
.close_button
)) {
2784 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2785 } else if (windowmenu
&& be
->button
== 3 &&
2786 (frame
.title
== be
->window
|| frame
.label
== be
->window
||
2787 frame
.handle
== be
->window
|| frame
.window
== be
->window
)) {
2788 if (windowmenu
->isVisible()) {
2791 int mx
= be
->x_root
- windowmenu
->getWidth() / 2,
2792 my
= be
->y_root
- windowmenu
->getHeight() / 2;
2794 // snap the window menu into a corner/side if necessary
2795 int left_edge
, right_edge
, top_edge
, bottom_edge
;
2798 the " + (frame.border_w * 2) - 1" bits are to get the proper width
2799 and height of the menu, as the sizes returned by it do not include
2802 left_edge
= frame
.rect
.x();
2803 right_edge
= frame
.rect
.right() -
2804 (windowmenu
->getWidth() + (frame
.border_w
* 2) - 1);
2805 top_edge
= client
.rect
.top() - (frame
.border_w
+ frame
.mwm_border_w
);
2806 bottom_edge
= client
.rect
.bottom() -
2807 (windowmenu
->getHeight() + (frame
.border_w
* 2) - 1) +
2808 (frame
.border_w
+ frame
.mwm_border_w
);
2812 if (mx
> right_edge
)
2816 if (my
> bottom_edge
)
2819 windowmenu
->move(mx
, my
);
2821 XRaiseWindow(blackbox
->getXDisplay(), windowmenu
->getWindowID());
2822 XRaiseWindow(blackbox
->getXDisplay(),
2823 windowmenu
->getSendToMenu()->getWindowID());
2826 } else if (be
->button
== 4) {
2827 if ((be
->window
== frame
.label
||
2828 be
->window
== frame
.title
||
2829 be
->window
== frame
.maximize_button
||
2830 be
->window
== frame
.iconify_button
||
2831 be
->window
== frame
.close_button
) &&
2835 } else if (be
->button
== 5) {
2836 if ((be
->window
== frame
.label
||
2837 be
->window
== frame
.title
||
2838 be
->window
== frame
.maximize_button
||
2839 be
->window
== frame
.iconify_button
||
2840 be
->window
== frame
.close_button
) &&
2847 void BlackboxWindow::buttonReleaseEvent(const XButtonEvent
*re
) {
2849 fprintf(stderr
, "BlackboxWindow::buttonReleaseEvent() for 0x%lx\n",
2853 if (re
->window
== frame
.maximize_button
&&
2854 re
->button
>= 1 && re
->button
<= 3) {
2855 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2856 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2857 maximize(re
->button
);
2859 redrawMaximizeButton(flags
.maximized
);
2861 } else if (re
->window
== frame
.iconify_button
&& re
->button
== 1) {
2862 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2863 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2866 redrawIconifyButton(False
);
2868 } else if (re
->window
== frame
.close_button
& re
->button
== 1) {
2869 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2870 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
)))
2872 redrawCloseButton(False
);
2873 } else if (flags
.moving
) {
2875 } else if (flags
.resizing
) {
2877 } else if (re
->window
== frame
.window
) {
2878 if (re
->button
== 2 && re
->state
== Mod1Mask
)
2879 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
2885 void BlackboxWindow::beginMove(int x_root
, int y_root
) {
2886 assert(! (flags
.resizing
|| flags
.moving
));
2889 Only one window can be moved/resized at a time. If another window is already
2890 being moved or resized, then stop it before whating to work with this one.
2892 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
2893 if (changing
&& changing
!= this) {
2894 if (changing
->flags
.moving
)
2895 changing
->endMove();
2896 else // if (changing->flags.resizing)
2897 changing
->endResize();
2900 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
2901 PointerMotionMask
| ButtonReleaseMask
,
2902 GrabModeAsync
, GrabModeAsync
,
2903 None
, blackbox
->getMoveCursor(), CurrentTime
);
2905 if (windowmenu
&& windowmenu
->isVisible())
2908 flags
.moving
= True
;
2909 blackbox
->setChangingWindow(this);
2911 if (! screen
->doOpaqueMove()) {
2912 XGrabServer(blackbox
->getXDisplay());
2914 frame
.changing
= frame
.rect
;
2915 screen
->showPosition(frame
.changing
.x(), frame
.changing
.y());
2917 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2921 frame
.changing
.width() - 1,
2922 frame
.changing
.height() - 1);
2925 frame
.grab_x
= x_root
- frame
.rect
.x() - frame
.border_w
;
2926 frame
.grab_y
= y_root
- frame
.rect
.y() - frame
.border_w
;
2930 void BlackboxWindow::doMove(int x_root
, int y_root
) {
2931 assert(flags
.moving
);
2932 assert(blackbox
->getChangingWindow() == this);
2934 int dx
= x_root
- frame
.grab_x
, dy
= y_root
- frame
.grab_y
;
2935 dx
-= frame
.border_w
;
2936 dy
-= frame
.border_w
;
2938 const int snap_distance
= screen
->getEdgeSnapThreshold();
2940 if (snap_distance
) {
2942 const int wleft
= dx
,
2943 wright
= dx
+ frame
.rect
.width() - 1,
2945 wbottom
= dy
+ frame
.rect
.height() - 1;
2947 if (screen
->getWindowToWindowSnap()) {
2948 Workspace
*w
= screen
->getWorkspace(getWorkspaceNumber());
2951 // try snap to another window
2952 for (unsigned int i
= 0, c
= w
->getCount(); i
< c
; ++i
) {
2953 BlackboxWindow
*snapwin
= w
->getWindow(i
);
2954 if (snapwin
== this)
2955 continue; // don't snap to self
2957 bool snapped
= False
;
2959 const Rect
&winrect
= snapwin
->frameRect();
2960 int dleft
= std::abs(wright
- winrect
.left()),
2961 dright
= std::abs(wleft
- winrect
.right()),
2962 dtop
= std::abs(wbottom
- winrect
.top()),
2963 dbottom
= std::abs(wtop
- winrect
.bottom());
2965 if (wtop
>= (signed)(winrect
.y() - frame
.rect
.height() + 1) &&
2966 wtop
< (signed)(winrect
.y() + winrect
.height() - 1)) {
2968 // snap left of other window?
2969 if (dleft
< snap_distance
&& dleft
<= dright
) {
2970 dx
= winrect
.left() - frame
.rect
.width();
2973 // snap right of other window?
2974 else if (dright
< snap_distance
) {
2975 dx
= winrect
.right() + 1;
2980 if (screen
->getWindowCornerSnap()) {
2981 // try corner-snap to its other sides
2982 dtop
= std::abs(wtop
- winrect
.top());
2983 dbottom
= std::abs(wbottom
- winrect
.bottom());
2984 if (dtop
< snap_distance
&& dtop
<= dbottom
)
2986 else if (dbottom
< snap_distance
)
2987 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
2994 if (wleft
>= (signed)(winrect
.x() - frame
.rect
.width() + 1) &&
2995 wleft
< (signed)(winrect
.x() + winrect
.width() - 1)) {
2997 // snap top of other window?
2998 if (dtop
< snap_distance
&& dtop
<= dbottom
) {
2999 dy
= winrect
.top() - frame
.rect
.height();
3002 // snap bottom of other window?
3003 else if (dbottom
< snap_distance
) {
3004 dy
= winrect
.bottom() + 1;
3009 if (screen
->getWindowCornerSnap()) {
3010 // try corner-snap to its other sides
3011 dleft
= std::abs(wleft
- winrect
.left());
3012 dright
= std::abs(wright
- winrect
.right());
3013 if (dleft
< snap_distance
&& dleft
<= dright
)
3014 dx
= winrect
.left();
3015 else if (dright
< snap_distance
)
3016 dx
= winrect
.right() - frame
.rect
.width() + 1;
3025 // try snap to the screen's available area
3026 Rect srect
= screen
->availableArea();
3028 int dleft
= std::abs(wleft
- srect
.left()),
3029 dright
= std::abs(wright
- srect
.right()),
3030 dtop
= std::abs(wtop
- srect
.top()),
3031 dbottom
= std::abs(wbottom
- srect
.bottom());
3034 if (dleft
< snap_distance
&& dleft
<= dright
)
3037 else if (dright
< snap_distance
)
3038 dx
= srect
.right() - frame
.rect
.width() + 1;
3041 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3044 else if (dbottom
< snap_distance
)
3045 dy
= srect
.bottom() - frame
.rect
.height() + 1;
3047 srect
= screen
->getRect(); // now get the full screen
3049 dleft
= std::abs(wleft
- srect
.left()),
3050 dright
= std::abs(wright
- srect
.right()),
3051 dtop
= std::abs(wtop
- srect
.top()),
3052 dbottom
= std::abs(wbottom
- srect
.bottom());
3055 if (dleft
< snap_distance
&& dleft
<= dright
)
3058 else if (dright
< snap_distance
)
3059 dx
= srect
.right() - frame
.rect
.width() + 1;
3062 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3065 else if (dbottom
< snap_distance
)
3066 dy
= srect
.bottom() - frame
.rect
.height() + 1;
3069 if (screen
->doOpaqueMove()) {
3070 configure(dx
, dy
, frame
.rect
.width(), frame
.rect
.height());
3072 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3076 frame
.changing
.width() - 1,
3077 frame
.changing
.height() - 1);
3079 frame
.changing
.setPos(dx
, dy
);
3081 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3085 frame
.changing
.width() - 1,
3086 frame
.changing
.height() - 1);
3089 screen
->showPosition(dx
, dy
);
3093 void BlackboxWindow::endMove(void) {
3094 assert(flags
.moving
);
3095 assert(blackbox
->getChangingWindow() == this);
3097 flags
.moving
= False
;
3098 blackbox
->setChangingWindow(0);
3100 if (! screen
->doOpaqueMove()) {
3101 /* when drawing the rubber band, we need to make sure we only draw inside
3102 * the frame... frame.changing_* contain the new coords for the window,
3103 * so we need to subtract 1 from changing_w/changing_h every where we
3104 * draw the rubber band (for both moving and resizing)
3106 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3107 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3108 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3109 XUngrabServer(blackbox
->getXDisplay());
3111 configure(frame
.changing
.x(), frame
.changing
.y(),
3112 frame
.changing
.width(), frame
.changing
.height());
3114 configure(frame
.rect
.x(), frame
.rect
.y(),
3115 frame
.rect
.width(), frame
.rect
.height());
3117 screen
->hideGeometry();
3119 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3121 // if there are any left over motions from the move, drop them now
3122 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3124 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3129 void BlackboxWindow::beginResize(int x_root
, int y_root
, Corner dir
) {
3130 assert(! (flags
.resizing
|| flags
.moving
));
3133 Only one window can be moved/resized at a time. If another window is already
3134 being moved or resized, then stop it before whating to work with this one.
3136 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3137 if (changing
&& changing
!= this) {
3138 if (changing
->flags
.moving
)
3139 changing
->endMove();
3140 else // if (changing->flags.resizing)
3141 changing
->endResize();
3149 switch (resize_dir
) {
3152 cursor
= blackbox
->getLowerLeftAngleCursor();
3157 cursor
= blackbox
->getLowerRightAngleCursor();
3161 anchor
= BottomRight
;
3162 cursor
= blackbox
->getUpperLeftAngleCursor();
3166 anchor
= BottomLeft
;
3167 cursor
= blackbox
->getUpperRightAngleCursor();
3171 assert(false); // unhandled Corner
3172 return; // unreachable, for the compiler
3175 XGrabServer(blackbox
->getXDisplay());
3176 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3177 PointerMotionMask
| ButtonReleaseMask
,
3178 GrabModeAsync
, GrabModeAsync
, None
, cursor
, CurrentTime
);
3180 flags
.resizing
= True
;
3181 blackbox
->setChangingWindow(this);
3184 frame
.changing
= frame
.rect
;
3186 constrain(anchor
, &gw
, &gh
);
3188 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3189 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3190 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3192 screen
->showGeometry(gw
, gh
);
3194 frame
.grab_x
= x_root
;
3195 frame
.grab_y
= y_root
;
3199 void BlackboxWindow::doResize(int x_root
, int y_root
) {
3200 assert(flags
.resizing
);
3201 assert(blackbox
->getChangingWindow() == this);
3203 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3204 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3205 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3210 switch (resize_dir
) {
3213 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3214 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3218 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3219 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3222 anchor
= BottomRight
;
3223 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3224 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3227 anchor
= BottomLeft
;
3228 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3229 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3233 assert(false); // unhandled Corner
3234 return; // unreachable, for the compiler
3237 constrain(anchor
, &gw
, &gh
);
3239 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3240 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3241 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3243 screen
->showGeometry(gw
, gh
);
3247 void BlackboxWindow::endResize(void) {
3248 assert(flags
.resizing
);
3249 assert(blackbox
->getChangingWindow() == this);
3251 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3252 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3253 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3254 XUngrabServer(blackbox
->getXDisplay());
3256 // unset maximized state after resized when fully maximized
3257 if (flags
.maximized
== 1)
3260 flags
.resizing
= False
;
3261 blackbox
->setChangingWindow(0);
3263 configure(frame
.changing
.x(), frame
.changing
.y(),
3264 frame
.changing
.width(), frame
.changing
.height());
3265 screen
->hideGeometry();
3267 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3269 // if there are any left over motions from the resize, drop them now
3270 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3272 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3277 void BlackboxWindow::motionNotifyEvent(const XMotionEvent
*me
) {
3279 fprintf(stderr
, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n",
3284 doMove(me
->x_root
, me
->y_root
);
3285 } else if (flags
.resizing
) {
3286 doResize(me
->x_root
, me
->y_root
);
3288 if (!flags
.resizing
&& me
->state
& Button1Mask
&& (functions
& Func_Move
) &&
3289 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3290 frame
.handle
== me
->window
|| frame
.window
== me
->window
)) {
3291 beginMove(me
->x_root
, me
->y_root
);
3292 } else if ((functions
& Func_Resize
) &&
3293 (me
->state
& Button1Mask
&& (me
->window
== frame
.right_grip
||
3294 me
->window
== frame
.left_grip
)) ||
3295 (me
->state
& Button3Mask
&& me
->state
& Mod1Mask
&&
3296 me
->window
== frame
.window
)) {
3297 unsigned int zones
= screen
->getResizeZones();
3300 if (me
->window
== frame
.left_grip
) {
3301 corner
= BottomLeft
;
3302 } else if (me
->window
== frame
.right_grip
|| zones
== 1) {
3303 corner
= BottomRight
;
3306 bool left
= (me
->x_root
- frame
.rect
.x() <=
3307 static_cast<signed>(frame
.rect
.width() / 2));
3310 else // (zones == 4)
3311 top
= (me
->y_root
- frame
.rect
.y() <=
3312 static_cast<signed>(frame
.rect
.height() / 2));
3313 corner
= (top
? (left
? TopLeft
: TopRight
) :
3314 (left
? BottomLeft
: BottomRight
));
3317 beginResize(me
->x_root
, me
->y_root
, corner
);
3324 void BlackboxWindow::shapeEvent(XShapeEvent
*) {
3325 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
3332 bool BlackboxWindow::validateClient(void) const {
3333 XSync(blackbox
->getXDisplay(), False
);
3336 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3337 DestroyNotify
, &e
) ||
3338 XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3340 XPutBackEvent(blackbox
->getXDisplay(), &e
);
3349 void BlackboxWindow::restore(bool remap
) {
3350 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeDelete
);
3351 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
3352 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, NoEventMask
);
3354 // do not leave a shaded window as an icon unless it was an icon
3355 if (flags
.shaded
&& ! flags
.iconic
) setState(NormalState
);
3357 restoreGravity(client
.rect
);
3359 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
3360 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
3362 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, client
.old_bw
);
3365 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3366 ReparentNotify
, &ev
)) {
3369 // according to the ICCCM - if the client doesn't reparent to
3370 // root, then we have to do it for them
3371 XReparentWindow(blackbox
->getXDisplay(), client
.window
,
3372 screen
->getRootWindow(),
3373 client
.rect
.x(), client
.rect
.y());
3376 if (remap
) XMapWindow(blackbox
->getXDisplay(), client
.window
);
3380 // timer for autoraise
3381 void BlackboxWindow::timeout(void) {
3382 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3386 void BlackboxWindow::changeBlackboxHints(BlackboxHints
*net
) {
3387 if ((net
->flags
& AttribShaded
) &&
3388 ((blackbox_attrib
.attrib
& AttribShaded
) !=
3389 (net
->attrib
& AttribShaded
)))
3392 if (flags
.visible
&& // watch out for requests when we can not be seen
3393 (net
->flags
& (AttribMaxVert
| AttribMaxHoriz
)) &&
3394 ((blackbox_attrib
.attrib
& (AttribMaxVert
| AttribMaxHoriz
)) !=
3395 (net
->attrib
& (AttribMaxVert
| AttribMaxHoriz
)))) {
3396 if (flags
.maximized
) {
3401 if ((net
->flags
& AttribMaxHoriz
) && (net
->flags
& AttribMaxVert
))
3402 button
= ((net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0);
3403 else if (net
->flags
& AttribMaxVert
)
3404 button
= ((net
->attrib
& AttribMaxVert
) ? 2 : 0);
3405 else if (net
->flags
& AttribMaxHoriz
)
3406 button
= ((net
->attrib
& AttribMaxHoriz
) ? 3 : 0);
3412 if ((net
->flags
& AttribOmnipresent
) &&
3413 ((blackbox_attrib
.attrib
& AttribOmnipresent
) !=
3414 (net
->attrib
& AttribOmnipresent
)))
3417 if ((net
->flags
& AttribWorkspace
) &&
3418 (blackbox_attrib
.workspace
!= net
->workspace
)) {
3419 screen
->reassociateWindow(this, net
->workspace
, True
);
3421 if (screen
->getCurrentWorkspaceID() != net
->workspace
) {
3425 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3429 if (net
->flags
& AttribDecoration
) {
3430 switch (net
->decoration
) {
3432 // clear all decorations except close
3433 decorations
&= Decor_Close
;
3439 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Iconify
;
3441 decorations
= ((functions
& Func_Resize
) && !isTransient() ?
3442 decorations
| Decor_Handle
:
3443 decorations
&= ~Decor_Handle
);
3444 decorations
= (functions
& Func_Maximize
?
3445 decorations
| Decor_Maximize
:
3446 decorations
&= ~Decor_Maximize
);
3451 decorations
|= Decor_Titlebar
| Decor_Iconify
;
3452 decorations
&= ~(Decor_Border
| Decor_Handle
);
3454 decorations
= (functions
& Func_Maximize
?
3455 decorations
| Decor_Maximize
:
3456 decorations
&= ~Decor_Maximize
);
3461 decorations
|= Decor_Titlebar
;
3462 decorations
&= ~(Decor_Iconify
| Decor_Border
);
3464 decorations
= ((functions
& Func_Resize
) && !isTransient() ?
3465 decorations
| Decor_Handle
:
3466 decorations
&= ~Decor_Handle
);
3467 decorations
= (functions
& Func_Maximize
?
3468 decorations
| Decor_Maximize
:
3469 decorations
&= ~Decor_Maximize
);
3474 // we can not be shaded if we lack a titlebar
3475 if (flags
.shaded
&& ! (decorations
& Decor_Titlebar
))
3478 if (flags
.visible
&& frame
.window
) {
3479 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
3480 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
3484 setState(current_state
);
3490 * Set the sizes of all components of the window frame
3491 * (the window decorations).
3492 * These values are based upon the current style settings and the client
3493 * window's dimensions.
3495 void BlackboxWindow::upsize(void) {
3496 frame
.bevel_w
= screen
->getBevelWidth();
3498 if (decorations
& Decor_Border
) {
3499 frame
.border_w
= screen
->getBorderWidth();
3500 if (! isTransient())
3501 frame
.mwm_border_w
= screen
->getFrameWidth();
3503 frame
.mwm_border_w
= 0;
3505 frame
.mwm_border_w
= frame
.border_w
= 0;
3508 if (decorations
& Decor_Titlebar
) {
3509 // the height of the titlebar is based upon the height of the font being
3510 // used to display the window's title
3511 WindowStyle
*style
= screen
->getWindowStyle();
3512 frame
.title_h
= style
->font
->height() + (frame
.bevel_w
* 2) + 2;
3514 frame
.label_h
= frame
.title_h
- (frame
.bevel_w
* 2);
3515 frame
.button_w
= (frame
.label_h
- 2);
3517 // set the top frame margin
3518 frame
.margin
.top
= frame
.border_w
+ frame
.title_h
+
3519 frame
.border_w
+ frame
.mwm_border_w
;
3525 // set the top frame margin
3526 frame
.margin
.top
= frame
.border_w
+ frame
.mwm_border_w
;
3529 // set the left/right frame margin
3530 frame
.margin
.left
= frame
.margin
.right
= frame
.border_w
+ frame
.mwm_border_w
;
3532 if (decorations
& Decor_Handle
) {
3533 frame
.grip_w
= frame
.button_w
* 2;
3534 frame
.handle_h
= screen
->getHandleWidth();
3536 // set the bottom frame margin
3537 frame
.margin
.bottom
= frame
.border_w
+ frame
.handle_h
+
3538 frame
.border_w
+ frame
.mwm_border_w
;
3543 // set the bottom frame margin
3544 frame
.margin
.bottom
= frame
.border_w
+ frame
.mwm_border_w
;
3548 We first get the normal dimensions and use this to define the inside_w/h
3549 then we modify the height if shading is in effect.
3550 If the shade state is not considered then frame.rect gets reset to the
3551 normal window size on a reconfigure() call resulting in improper
3552 dimensions appearing in move/resize and other events.
3555 height
= client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
,
3556 width
= client
.rect
.width() + frame
.margin
.left
+ frame
.margin
.right
;
3558 frame
.inside_w
= width
- (frame
.border_w
* 2);
3559 frame
.inside_h
= height
- (frame
.border_w
* 2);
3562 height
= frame
.title_h
+ (frame
.border_w
* 2);
3563 frame
.rect
.setSize(width
, height
);
3568 * Calculate the size of the client window and constrain it to the
3569 * size specified by the size hints of the client window.
3571 * The logical width and height are placed into pw and ph, if they
3572 * are non-zero. Logical size refers to the users perception of
3573 * the window size (for example an xterm resizes in cells, not in pixels).
3575 * The physical geometry is placed into frame.changing_{x,y,width,height}.
3576 * Physical geometry refers to the geometry of the window in pixels.
3578 void BlackboxWindow::constrain(Corner anchor
, int *pw
, int *ph
) {
3579 // frame.changing represents the requested frame size, we need to
3580 // strip the frame margin off and constrain the client size
3581 frame
.changing
.setCoords(frame
.changing
.left() + frame
.margin
.left
,
3582 frame
.changing
.top() + frame
.margin
.top
,
3583 frame
.changing
.right() - frame
.margin
.right
,
3584 frame
.changing
.bottom() - frame
.margin
.bottom
);
3586 int dw
= frame
.changing
.width(), dh
= frame
.changing
.height(),
3587 base_width
= (client
.base_width
) ? client
.base_width
: client
.min_width
,
3588 base_height
= (client
.base_height
) ? client
.base_height
:
3592 if (dw
< static_cast<signed>(client
.min_width
)) dw
= client
.min_width
;
3593 if (dh
< static_cast<signed>(client
.min_height
)) dh
= client
.min_height
;
3594 if (dw
> static_cast<signed>(client
.max_width
)) dw
= client
.max_width
;
3595 if (dh
> static_cast<signed>(client
.max_height
)) dh
= client
.max_height
;
3598 dw
/= client
.width_inc
;
3600 dh
/= client
.height_inc
;
3603 if (client
.width_inc
== 1)
3604 *pw
= dw
+ base_width
;
3609 if (client
.height_inc
== 1)
3610 *ph
= dh
+ base_height
;
3615 dw
*= client
.width_inc
;
3617 dh
*= client
.height_inc
;
3620 frame
.changing
.setSize(dw
, dh
);
3622 // add the frame margin back onto frame.changing
3623 frame
.changing
.setCoords(frame
.changing
.left() - frame
.margin
.left
,
3624 frame
.changing
.top() - frame
.margin
.top
,
3625 frame
.changing
.right() + frame
.margin
.right
,
3626 frame
.changing
.bottom() + frame
.margin
.bottom
);
3628 // move frame.changing to the specified anchor
3636 dx
= frame
.rect
.right() - frame
.changing
.right();
3640 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3644 dx
= frame
.rect
.right() - frame
.changing
.right();
3645 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3649 assert(false); // unhandled corner
3651 frame
.changing
.setPos(frame
.changing
.x() + dx
, frame
.changing
.y() + dy
);
3655 void WindowStyle::doJustify(const std::string
&text
, int &start_pos
,
3656 unsigned int max_length
,
3657 unsigned int modifier
) const {
3658 size_t text_len
= text
.size();
3659 unsigned int length
;
3662 length
= font
->measureString(string(text
, 0, text_len
)) + modifier
;
3663 } while (length
> max_length
&& text_len
-- > 0);
3667 start_pos
+= max_length
- length
;
3671 start_pos
+= (max_length
- length
) / 2;
3681 BWindowGroup::BWindowGroup(Blackbox
*b
, Window _group
)
3682 : blackbox(b
), group(_group
) {
3683 XWindowAttributes wattrib
;
3684 if (! XGetWindowAttributes(blackbox
->getXDisplay(), group
, &wattrib
)) {
3685 // group window doesn't seem to exist anymore
3690 XSelectInput(blackbox
->getXDisplay(), group
,
3691 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
3693 blackbox
->saveGroupSearch(group
, this);
3697 BWindowGroup::~BWindowGroup(void) {
3698 blackbox
->removeGroupSearch(group
);
3703 BWindowGroup::find(BScreen
*screen
, bool allow_transients
) const {
3704 BlackboxWindow
*ret
= blackbox
->getFocusedWindow();
3706 // does the focus window match (or any transient_fors)?
3708 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3709 if (ret
->isTransient() && allow_transients
) break;
3710 else if (! ret
->isTransient()) break;
3713 ret
= ret
->getTransientFor();
3716 if (ret
) return ret
;
3718 // the focus window didn't match, look in the group's window list
3719 BlackboxWindowList::const_iterator it
, end
= windowList
.end();
3720 for (it
= windowList
.begin(); it
!= end
; ++it
) {
3722 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3723 if (ret
->isTransient() && allow_transients
) break;
3724 else if (! ret
->isTransient()) break;