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
;
1796 if (screen
->isXineramaActive() && blackbox
->doXineramaMaximizing()) {
1797 // find the area to use
1798 RectList availableAreas
= screen
->allAvailableAreas();
1799 RectList::iterator it
, end
= availableAreas
.end();
1801 for (it
= availableAreas
.begin(); it
!= end
; ++it
)
1802 if (it
->intersects(frame
.rect
)) break;
1803 if (it
== end
) // the window isn't inside an area
1804 it
= availableAreas
.begin(); // so just default to the first one
1806 frame
.changing
= *it
;
1809 frame
.changing
= screen
->availableArea();
1813 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1814 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1818 blackbox_attrib
.flags
|= AttribMaxVert
;
1819 blackbox_attrib
.attrib
|= AttribMaxVert
;
1821 frame
.changing
.setX(frame
.rect
.x());
1822 frame
.changing
.setWidth(frame
.rect
.width());
1826 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1827 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1829 frame
.changing
.setY(frame
.rect
.y());
1830 frame
.changing
.setHeight(frame
.rect
.height());
1837 blackbox_attrib
.flags
^= AttribShaded
;
1838 blackbox_attrib
.attrib
^= AttribShaded
;
1839 flags
.shaded
= False
;
1842 flags
.maximized
= button
;
1844 configure(frame
.changing
.x(), frame
.changing
.y(),
1845 frame
.changing
.width(), frame
.changing
.height());
1847 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1848 redrawAllButtons(); // in case it is not called in configure()
1849 setState(current_state
);
1853 // re-maximizes the window to take into account availableArea changes
1854 void BlackboxWindow::remaximize(void) {
1855 // save the original dimensions because maximize will wipe them out
1856 int premax_x
= blackbox_attrib
.premax_x
,
1857 premax_y
= blackbox_attrib
.premax_y
,
1858 premax_w
= blackbox_attrib
.premax_w
,
1859 premax_h
= blackbox_attrib
.premax_h
;
1861 unsigned int button
= flags
.maximized
;
1862 flags
.maximized
= 0; // trick maximize() into working
1865 // restore saved values
1866 blackbox_attrib
.premax_x
= premax_x
;
1867 blackbox_attrib
.premax_y
= premax_y
;
1868 blackbox_attrib
.premax_w
= premax_w
;
1869 blackbox_attrib
.premax_h
= premax_h
;
1873 void BlackboxWindow::setWorkspace(unsigned int n
) {
1874 blackbox_attrib
.flags
|= AttribWorkspace
;
1875 blackbox_attrib
.workspace
= n
;
1876 if (n
== BSENTINEL
) { // iconified window
1878 we set the workspace to 'all workspaces' so that taskbars will show the
1879 window. otherwise, it made uniconifying a window imposible without the
1880 blackbox workspace menu
1884 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
, n
);
1888 void BlackboxWindow::shade(void) {
1890 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1891 frame
.inside_w
, frame
.inside_h
);
1892 flags
.shaded
= False
;
1893 blackbox_attrib
.flags
^= AttribShaded
;
1894 blackbox_attrib
.attrib
^= AttribShaded
;
1896 setState(NormalState
);
1898 // set the frame rect to the normal size
1899 frame
.rect
.setHeight(client
.rect
.height() + frame
.margin
.top
+
1900 frame
.margin
.bottom
);
1902 if (! (decorations
& Decor_Titlebar
))
1903 return; // can't shade it without a titlebar!
1905 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1906 frame
.inside_w
, frame
.title_h
);
1907 flags
.shaded
= True
;
1908 blackbox_attrib
.flags
|= AttribShaded
;
1909 blackbox_attrib
.attrib
|= AttribShaded
;
1911 setState(IconicState
);
1913 // set the frame rect to the shaded size
1914 frame
.rect
.setHeight(frame
.title_h
+ (frame
.border_w
* 2));
1920 * (Un)Sticks a window and its relatives.
1922 void BlackboxWindow::stick(void) {
1924 blackbox_attrib
.flags
^= AttribOmnipresent
;
1925 blackbox_attrib
.attrib
^= AttribOmnipresent
;
1927 flags
.stuck
= False
;
1930 screen
->reassociateWindow(this, BSENTINEL
, True
);
1931 // temporary fix since sticky windows suck. set the hint to what we
1932 // actually hold in our data.
1933 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1934 blackbox_attrib
.workspace
);
1936 setState(current_state
);
1940 blackbox_attrib
.flags
|= AttribOmnipresent
;
1941 blackbox_attrib
.attrib
|= AttribOmnipresent
;
1943 // temporary fix since sticky windows suck. set the hint to a different
1944 // value than that contained in the class' data.
1945 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1948 setState(current_state
);
1951 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1952 client
.transient_for
->isStuck() != flags
.stuck
)
1953 client
.transient_for
->stick();
1954 // go down the chain
1955 BlackboxWindowList::iterator it
;
1956 const BlackboxWindowList::iterator end
= client
.transientList
.end();
1957 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1958 if ((*it
)->isStuck() != flags
.stuck
)
1963 void BlackboxWindow::redrawWindowFrame(void) const {
1964 if (decorations
& Decor_Titlebar
) {
1965 if (flags
.focused
) {
1967 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1968 frame
.title
, frame
.ftitle
);
1970 XSetWindowBackground(blackbox
->getXDisplay(),
1971 frame
.title
, frame
.ftitle_pixel
);
1974 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1975 frame
.title
, frame
.utitle
);
1977 XSetWindowBackground(blackbox
->getXDisplay(),
1978 frame
.title
, frame
.utitle_pixel
);
1980 XClearWindow(blackbox
->getXDisplay(), frame
.title
);
1986 if (decorations
& Decor_Handle
) {
1987 if (flags
.focused
) {
1989 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1990 frame
.handle
, frame
.fhandle
);
1992 XSetWindowBackground(blackbox
->getXDisplay(),
1993 frame
.handle
, frame
.fhandle_pixel
);
1996 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1997 frame
.left_grip
, frame
.fgrip
);
1998 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1999 frame
.right_grip
, frame
.fgrip
);
2001 XSetWindowBackground(blackbox
->getXDisplay(),
2002 frame
.left_grip
, frame
.fgrip_pixel
);
2003 XSetWindowBackground(blackbox
->getXDisplay(),
2004 frame
.right_grip
, frame
.fgrip_pixel
);
2008 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2009 frame
.handle
, frame
.uhandle
);
2011 XSetWindowBackground(blackbox
->getXDisplay(),
2012 frame
.handle
, frame
.uhandle_pixel
);
2015 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2016 frame
.left_grip
, frame
.ugrip
);
2017 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2018 frame
.right_grip
, frame
.ugrip
);
2020 XSetWindowBackground(blackbox
->getXDisplay(),
2021 frame
.left_grip
, frame
.ugrip_pixel
);
2022 XSetWindowBackground(blackbox
->getXDisplay(),
2023 frame
.right_grip
, frame
.ugrip_pixel
);
2026 XClearWindow(blackbox
->getXDisplay(), frame
.handle
);
2027 XClearWindow(blackbox
->getXDisplay(), frame
.left_grip
);
2028 XClearWindow(blackbox
->getXDisplay(), frame
.right_grip
);
2031 if (decorations
& Decor_Border
) {
2033 XSetWindowBorder(blackbox
->getXDisplay(),
2034 frame
.plate
, frame
.fborder_pixel
);
2036 XSetWindowBorder(blackbox
->getXDisplay(),
2037 frame
.plate
, frame
.uborder_pixel
);
2042 void BlackboxWindow::setFocusFlag(bool focus
) {
2043 // only focus a window if it is visible
2044 if (focus
&& !flags
.visible
)
2047 flags
.focused
= focus
;
2049 redrawWindowFrame();
2051 if (screen
->isSloppyFocus() && screen
->doAutoRaise()) {
2052 if (isFocused()) timer
->start();
2057 blackbox
->setFocusedWindow(this);
2059 Clientmenu
*menu
= screen
->getWorkspace(blackbox_attrib
.workspace
)->getMenu();
2060 menu
->setItemSelected(window_number
, isFocused());
2064 void BlackboxWindow::installColormap(bool install
) {
2065 int i
= 0, ncmap
= 0;
2066 Colormap
*cmaps
= XListInstalledColormaps(blackbox
->getXDisplay(),
2067 client
.window
, &ncmap
);
2069 XWindowAttributes wattrib
;
2070 if (XGetWindowAttributes(blackbox
->getXDisplay(),
2071 client
.window
, &wattrib
)) {
2073 // install the window's colormap
2074 for (i
= 0; i
< ncmap
; i
++) {
2075 if (*(cmaps
+ i
) == wattrib
.colormap
)
2076 // this window is using an installed color map... do not install
2079 // otherwise, install the window's colormap
2081 XInstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2083 // uninstall the window's colormap
2084 for (i
= 0; i
< ncmap
; i
++) {
2085 if (*(cmaps
+ i
) == wattrib
.colormap
)
2086 // we found the colormap to uninstall
2087 XUninstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2097 void BlackboxWindow::setAllowedActions(void) {
2101 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_shade
);
2102 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_change_desktop
);
2103 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_close
);
2105 if (functions
& Func_Move
)
2106 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_move
);
2107 if (functions
& Func_Resize
)
2108 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_resize
);
2109 if (functions
& Func_Maximize
) {
2110 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_horz
);
2111 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_vert
);
2114 xatom
->setValue(client
.window
, XAtom::net_wm_allowed_actions
, XAtom::atom
,
2119 void BlackboxWindow::setState(unsigned long new_state
) {
2120 current_state
= new_state
;
2122 unsigned long state
[2];
2123 state
[0] = current_state
;
2125 xatom
->setValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
, state
, 2);
2127 xatom
->setValue(client
.window
, XAtom::blackbox_attributes
,
2128 XAtom::blackbox_attributes
, (unsigned long *)&blackbox_attrib
,
2129 PropBlackboxAttributesElements
);
2134 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_modal
);
2136 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_shaded
);
2138 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_hidden
);
2139 if (flags
.skip_taskbar
)
2140 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
);
2141 if (flags
.skip_pager
)
2142 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_pager
);
2143 if (flags
.fullscreen
)
2144 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_fullscreen
);
2145 if (flags
.maximized
== 1 || flags
.maximized
== 2)
2146 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_vert
);
2147 if (flags
.maximized
== 1 || flags
.maximized
== 3)
2148 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_horz
);
2149 xatom
->setValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
2154 bool BlackboxWindow::getState(void) {
2155 bool ret
= xatom
->getValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
,
2157 if (! ret
) current_state
= 0;
2162 void BlackboxWindow::restoreAttributes(void) {
2163 unsigned long num
= PropBlackboxAttributesElements
;
2164 BlackboxAttributes
*net
;
2165 if (! xatom
->getValue(client
.window
, XAtom::blackbox_attributes
,
2166 XAtom::blackbox_attributes
, num
,
2167 (unsigned long **)&net
))
2169 if (num
< PropBlackboxAttributesElements
) {
2174 if (net
->flags
& AttribShaded
&& net
->attrib
& AttribShaded
) {
2175 flags
.shaded
= False
;
2176 unsigned long orig_state
= current_state
;
2180 At this point in the life of a window, current_state should only be set
2181 to IconicState if the window was an *icon*, not if it was shaded.
2183 if (orig_state
!= IconicState
)
2184 current_state
= WithdrawnState
;
2187 if (net
->workspace
!= screen
->getCurrentWorkspaceID() &&
2188 net
->workspace
< screen
->getWorkspaceCount())
2189 screen
->reassociateWindow(this, net
->workspace
, True
);
2191 if ((blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID()) &&
2192 (blackbox_attrib
.workspace
< screen
->getWorkspaceCount())) {
2193 // set to WithdrawnState so it will be mapped on the new workspace
2194 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2195 } else if (current_state
== WithdrawnState
) {
2196 // the window is on this workspace and is Withdrawn, so it is waiting to
2198 current_state
= NormalState
;
2201 if (net
->flags
& AttribOmnipresent
&& net
->attrib
& AttribOmnipresent
) {
2202 flags
.stuck
= False
;
2205 // if the window was on another workspace, it was going to be hidden. this
2206 // specifies that the window should be mapped since it is sticky.
2207 if (current_state
== WithdrawnState
) current_state
= NormalState
;
2210 if (net
->flags
& AttribMaxHoriz
|| net
->flags
& AttribMaxVert
) {
2211 int x
= net
->premax_x
, y
= net
->premax_y
;
2212 unsigned int w
= net
->premax_w
, h
= net
->premax_h
;
2213 flags
.maximized
= 0;
2216 if ((net
->flags
& AttribMaxHoriz
) &&
2217 (net
->flags
& AttribMaxVert
))
2218 m
= (net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
2219 else if (net
->flags
& AttribMaxVert
)
2220 m
= (net
->attrib
& AttribMaxVert
) ? 2 : 0;
2221 else if (net
->flags
& AttribMaxHoriz
)
2222 m
= (net
->attrib
& AttribMaxHoriz
) ? 3 : 0;
2226 blackbox_attrib
.premax_x
= x
;
2227 blackbox_attrib
.premax_y
= y
;
2228 blackbox_attrib
.premax_w
= w
;
2229 blackbox_attrib
.premax_h
= h
;
2232 // with the state set it will then be the map event's job to read the
2233 // window's state and behave accordingly
2240 * Positions the Rect r according the the client window position and
2243 void BlackboxWindow::applyGravity(Rect
&r
) {
2244 // apply horizontal window gravity
2245 switch (client
.win_gravity
) {
2247 case NorthWestGravity
:
2248 case SouthWestGravity
:
2250 r
.setX(client
.rect
.x());
2256 r
.setX(client
.rect
.x() - (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2259 case NorthEastGravity
:
2260 case SouthEastGravity
:
2262 r
.setX(client
.rect
.x() - frame
.margin
.left
- frame
.margin
.right
+ 2);
2267 r
.setX(client
.rect
.x() - frame
.margin
.left
);
2271 // apply vertical window gravity
2272 switch (client
.win_gravity
) {
2274 case NorthWestGravity
:
2275 case NorthEastGravity
:
2277 r
.setY(client
.rect
.y());
2283 r
.setY(client
.rect
.y() - (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2286 case SouthWestGravity
:
2287 case SouthEastGravity
:
2289 r
.setY(client
.rect
.y() - frame
.margin
.top
- frame
.margin
.bottom
+ 2);
2294 r
.setY(client
.rect
.y() - frame
.margin
.top
);
2301 * The reverse of the applyGravity function.
2303 * Positions the Rect r according to the frame window position and
2306 void BlackboxWindow::restoreGravity(Rect
&r
) {
2307 // restore horizontal window gravity
2308 switch (client
.win_gravity
) {
2310 case NorthWestGravity
:
2311 case SouthWestGravity
:
2313 r
.setX(frame
.rect
.x());
2319 r
.setX(frame
.rect
.x() + (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2322 case NorthEastGravity
:
2323 case SouthEastGravity
:
2325 r
.setX(frame
.rect
.x() + frame
.margin
.left
+ frame
.margin
.right
- 2);
2330 r
.setX(frame
.rect
.x() + frame
.margin
.left
);
2334 // restore vertical window gravity
2335 switch (client
.win_gravity
) {
2337 case NorthWestGravity
:
2338 case NorthEastGravity
:
2340 r
.setY(frame
.rect
.y());
2346 r
.setY(frame
.rect
.y() + (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2349 case SouthWestGravity
:
2350 case SouthEastGravity
:
2352 r
.setY(frame
.rect
.y() + frame
.margin
.top
+ frame
.margin
.bottom
- 2);
2357 r
.setY(frame
.rect
.y() + frame
.margin
.top
);
2363 void BlackboxWindow::redrawLabel(void) const {
2364 if (flags
.focused
) {
2366 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2367 frame
.label
, frame
.flabel
);
2369 XSetWindowBackground(blackbox
->getXDisplay(),
2370 frame
.label
, frame
.flabel_pixel
);
2373 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2374 frame
.label
, frame
.ulabel
);
2376 XSetWindowBackground(blackbox
->getXDisplay(),
2377 frame
.label
, frame
.ulabel_pixel
);
2379 XClearWindow(blackbox
->getXDisplay(), frame
.label
);
2381 WindowStyle
*style
= screen
->getWindowStyle();
2383 int pos
= frame
.bevel_w
* 2;
2384 style
->doJustify(client
.title
.c_str(), pos
, frame
.label_w
, frame
.bevel_w
* 4);
2385 style
->font
->drawString(frame
.label
, pos
, 1,
2386 (flags
.focused
? style
->l_text_focus
:
2387 style
->l_text_unfocus
),
2392 void BlackboxWindow::redrawAllButtons(void) const {
2393 if (frame
.iconify_button
) redrawIconifyButton(False
);
2394 if (frame
.maximize_button
) redrawMaximizeButton(flags
.maximized
);
2395 if (frame
.close_button
) redrawCloseButton(False
);
2399 void BlackboxWindow::redrawIconifyButton(bool pressed
) const {
2401 if (flags
.focused
) {
2403 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2404 frame
.iconify_button
, frame
.fbutton
);
2406 XSetWindowBackground(blackbox
->getXDisplay(),
2407 frame
.iconify_button
, frame
.fbutton_pixel
);
2410 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2411 frame
.iconify_button
, frame
.ubutton
);
2413 XSetWindowBackground(blackbox
->getXDisplay(), frame
.iconify_button
,
2414 frame
.ubutton_pixel
);
2418 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2419 frame
.iconify_button
, frame
.pbutton
);
2421 XSetWindowBackground(blackbox
->getXDisplay(),
2422 frame
.iconify_button
, frame
.pbutton_pixel
);
2424 XClearWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
2426 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2427 screen
->getWindowStyle()->b_pic_unfocus
);
2428 XDrawRectangle(blackbox
->getXDisplay(), frame
.iconify_button
, pen
.gc(),
2429 2, (frame
.button_w
- 5), (frame
.button_w
- 5), 2);
2433 void BlackboxWindow::redrawMaximizeButton(bool pressed
) const {
2435 if (flags
.focused
) {
2437 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2438 frame
.maximize_button
, frame
.fbutton
);
2440 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2441 frame
.fbutton_pixel
);
2444 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2445 frame
.maximize_button
, frame
.ubutton
);
2447 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2448 frame
.ubutton_pixel
);
2452 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2453 frame
.maximize_button
, frame
.pbutton
);
2455 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2456 frame
.pbutton_pixel
);
2458 XClearWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
2460 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2461 screen
->getWindowStyle()->b_pic_unfocus
);
2462 XDrawRectangle(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2463 2, 2, (frame
.button_w
- 5), (frame
.button_w
- 5));
2464 XDrawLine(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2465 2, 3, (frame
.button_w
- 3), 3);
2469 void BlackboxWindow::redrawCloseButton(bool pressed
) const {
2471 if (flags
.focused
) {
2473 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2476 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2477 frame
.fbutton_pixel
);
2480 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2483 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2484 frame
.ubutton_pixel
);
2488 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2489 frame
.close_button
, frame
.pbutton
);
2491 XSetWindowBackground(blackbox
->getXDisplay(),
2492 frame
.close_button
, frame
.pbutton_pixel
);
2494 XClearWindow(blackbox
->getXDisplay(), frame
.close_button
);
2496 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2497 screen
->getWindowStyle()->b_pic_unfocus
);
2498 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2499 2, 2, (frame
.button_w
- 3), (frame
.button_w
- 3));
2500 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2501 2, (frame
.button_w
- 3), (frame
.button_w
- 3), 2);
2505 void BlackboxWindow::mapRequestEvent(const XMapRequestEvent
*re
) {
2506 if (re
->window
!= client
.window
)
2510 fprintf(stderr
, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2514 switch (current_state
) {
2519 case WithdrawnState
:
2528 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2530 if (! blackbox
->isStartup()) {
2531 XSync(blackbox
->getXDisplay(), False
); // make sure the frame is mapped
2532 if (screen
->doFocusNew()|| (isTransient() && getTransientFor() &&
2533 getTransientFor()->isFocused())) {
2536 if (screen
->getPlacementPolicy() == BScreen::ClickMousePlacement
) {
2540 XQueryPointer(blackbox
->getXDisplay(), screen
->getRootWindow(),
2541 &r
, &c
, &rx
, &ry
, &x
, &y
, &m
);
2551 void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent
*ue
) {
2552 if (ue
->window
!= client
.window
)
2556 fprintf(stderr
, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2560 screen
->unmanageWindow(this, False
);
2564 void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent
*de
) {
2565 if (de
->window
!= client
.window
)
2569 fprintf(stderr
, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2573 screen
->unmanageWindow(this, False
);
2577 void BlackboxWindow::reparentNotifyEvent(const XReparentEvent
*re
) {
2578 if (re
->window
!= client
.window
|| re
->parent
== frame
.plate
)
2582 fprintf(stderr
, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2583 "0x%lx.\n", client
.window
, re
->parent
);
2588 XPutBackEvent(blackbox
->getXDisplay(), &ev
);
2589 screen
->unmanageWindow(this, True
);
2593 void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent
*pe
) {
2594 if (pe
->state
== PropertyDelete
)
2598 fprintf(stderr
, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n",
2604 case XA_WM_CLIENT_MACHINE
:
2608 case XA_WM_TRANSIENT_FOR
: {
2609 // determine if this is a transient window
2612 // adjust the window decorations based on transience
2613 if (isTransient()) {
2614 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2615 functions
&= ~Func_Maximize
;
2616 setAllowedActions();
2627 case XA_WM_ICON_NAME
:
2629 if (flags
.iconic
) screen
->propagateWindowName(this);
2632 case XAtom::net_wm_name
:
2636 if (decorations
& Decor_Titlebar
)
2639 screen
->propagateWindowName(this);
2642 case XA_WM_NORMAL_HINTS
: {
2645 if ((client
.normal_hint_flags
& PMinSize
) &&
2646 (client
.normal_hint_flags
& PMaxSize
)) {
2647 // the window now can/can't resize itself, so the buttons need to be
2650 if (client
.max_width
<= client
.min_width
&&
2651 client
.max_height
<= client
.min_height
) {
2652 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2653 functions
&= ~(Func_Resize
| Func_Maximize
);
2655 if (! isTransient()) {
2656 decorations
|= Decor_Maximize
| Decor_Handle
;
2657 functions
|= Func_Maximize
;
2659 functions
|= Func_Resize
;
2662 setAllowedActions();
2665 Rect old_rect
= frame
.rect
;
2669 if (old_rect
!= frame
.rect
)
2676 if (pe
->atom
== xatom
->getAtom(XAtom::wm_protocols
)) {
2679 if ((decorations
& Decor_Close
) && (! frame
.close_button
)) {
2680 createCloseButton();
2681 if (decorations
& Decor_Titlebar
) {
2682 positionButtons(True
);
2683 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
2685 if (windowmenu
) windowmenu
->reconfigure();
2687 } else if (pe
->atom
== xatom
->getAtom(XAtom::net_wm_strut
)) {
2696 void BlackboxWindow::exposeEvent(const XExposeEvent
*ee
) {
2698 fprintf(stderr
, "BlackboxWindow::exposeEvent() for 0x%lx\n", client
.window
);
2701 if (frame
.label
== ee
->window
&& (decorations
& Decor_Titlebar
))
2703 else if (frame
.close_button
== ee
->window
)
2704 redrawCloseButton(False
);
2705 else if (frame
.maximize_button
== ee
->window
)
2706 redrawMaximizeButton(flags
.maximized
);
2707 else if (frame
.iconify_button
== ee
->window
)
2708 redrawIconifyButton(False
);
2712 void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent
*cr
) {
2713 if (cr
->window
!= client
.window
|| flags
.iconic
)
2716 if (cr
->value_mask
& CWBorderWidth
)
2717 client
.old_bw
= cr
->border_width
;
2719 if (cr
->value_mask
& (CWX
| CWY
| CWWidth
| CWHeight
)) {
2720 Rect req
= frame
.rect
;
2722 if (cr
->value_mask
& (CWX
| CWY
)) {
2723 if (cr
->value_mask
& CWX
)
2724 client
.rect
.setX(cr
->x
);
2725 if (cr
->value_mask
& CWY
)
2726 client
.rect
.setY(cr
->y
);
2731 if (cr
->value_mask
& CWWidth
)
2732 req
.setWidth(cr
->width
+ frame
.margin
.left
+ frame
.margin
.right
);
2734 if (cr
->value_mask
& CWHeight
)
2735 req
.setHeight(cr
->height
+ frame
.margin
.top
+ frame
.margin
.bottom
);
2737 configure(req
.x(), req
.y(), req
.width(), req
.height());
2740 if (cr
->value_mask
& CWStackMode
&& !isDesktop()) {
2741 switch (cr
->detail
) {
2744 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2750 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2757 void BlackboxWindow::buttonPressEvent(const XButtonEvent
*be
) {
2759 fprintf(stderr
, "BlackboxWindow::buttonPressEvent() for 0x%lx\n",
2763 if (frame
.maximize_button
== be
->window
&& be
->button
<= 3) {
2764 redrawMaximizeButton(True
);
2765 } else if (be
->button
== 1 || (be
->button
== 3 && be
->state
== Mod1Mask
)) {
2766 if (! flags
.focused
)
2769 if (frame
.iconify_button
== be
->window
) {
2770 redrawIconifyButton(True
);
2771 } else if (frame
.close_button
== be
->window
) {
2772 redrawCloseButton(True
);
2773 } else if (frame
.plate
== be
->window
) {
2774 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2776 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2778 XAllowEvents(blackbox
->getXDisplay(), ReplayPointer
, be
->time
);
2780 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
2781 if (((be
->time
- lastButtonPressTime
) <=
2782 blackbox
->getDoubleClickInterval()) ||
2783 (be
->state
== ControlMask
)) {
2784 lastButtonPressTime
= 0;
2787 lastButtonPressTime
= be
->time
;
2791 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2793 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2795 } else if (be
->button
== 2 && (be
->window
!= frame
.iconify_button
) &&
2796 (be
->window
!= frame
.close_button
)) {
2797 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2798 } else if (windowmenu
&& be
->button
== 3 &&
2799 (frame
.title
== be
->window
|| frame
.label
== be
->window
||
2800 frame
.handle
== be
->window
|| frame
.window
== be
->window
)) {
2801 if (windowmenu
->isVisible()) {
2804 int mx
= be
->x_root
- windowmenu
->getWidth() / 2,
2805 my
= be
->y_root
- windowmenu
->getHeight() / 2;
2807 // snap the window menu into a corner/side if necessary
2808 int left_edge
, right_edge
, top_edge
, bottom_edge
;
2811 the " + (frame.border_w * 2) - 1" bits are to get the proper width
2812 and height of the menu, as the sizes returned by it do not include
2815 left_edge
= frame
.rect
.x();
2816 right_edge
= frame
.rect
.right() -
2817 (windowmenu
->getWidth() + (frame
.border_w
* 2) - 1);
2818 top_edge
= client
.rect
.top() - (frame
.border_w
+ frame
.mwm_border_w
);
2819 bottom_edge
= client
.rect
.bottom() -
2820 (windowmenu
->getHeight() + (frame
.border_w
* 2) - 1) +
2821 (frame
.border_w
+ frame
.mwm_border_w
);
2825 if (mx
> right_edge
)
2829 if (my
> bottom_edge
)
2832 windowmenu
->move(mx
, my
);
2834 XRaiseWindow(blackbox
->getXDisplay(), windowmenu
->getWindowID());
2835 XRaiseWindow(blackbox
->getXDisplay(),
2836 windowmenu
->getSendToMenu()->getWindowID());
2839 } else if (be
->button
== 4) {
2840 if ((be
->window
== frame
.label
||
2841 be
->window
== frame
.title
||
2842 be
->window
== frame
.maximize_button
||
2843 be
->window
== frame
.iconify_button
||
2844 be
->window
== frame
.close_button
) &&
2848 } else if (be
->button
== 5) {
2849 if ((be
->window
== frame
.label
||
2850 be
->window
== frame
.title
||
2851 be
->window
== frame
.maximize_button
||
2852 be
->window
== frame
.iconify_button
||
2853 be
->window
== frame
.close_button
) &&
2860 void BlackboxWindow::buttonReleaseEvent(const XButtonEvent
*re
) {
2862 fprintf(stderr
, "BlackboxWindow::buttonReleaseEvent() for 0x%lx\n",
2866 if (re
->window
== frame
.maximize_button
&&
2867 re
->button
>= 1 && re
->button
<= 3) {
2868 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2869 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2870 maximize(re
->button
);
2872 redrawMaximizeButton(flags
.maximized
);
2874 } else if (re
->window
== frame
.iconify_button
&& re
->button
== 1) {
2875 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2876 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2879 redrawIconifyButton(False
);
2881 } else if (re
->window
== frame
.close_button
& re
->button
== 1) {
2882 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2883 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
)))
2885 redrawCloseButton(False
);
2886 } else if (flags
.moving
) {
2888 } else if (flags
.resizing
) {
2890 } else if (re
->window
== frame
.window
) {
2891 if (re
->button
== 2 && re
->state
== Mod1Mask
)
2892 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
2898 void BlackboxWindow::beginMove(int x_root
, int y_root
) {
2899 assert(! (flags
.resizing
|| flags
.moving
));
2902 Only one window can be moved/resized at a time. If another window is already
2903 being moved or resized, then stop it before whating to work with this one.
2905 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
2906 if (changing
&& changing
!= this) {
2907 if (changing
->flags
.moving
)
2908 changing
->endMove();
2909 else // if (changing->flags.resizing)
2910 changing
->endResize();
2913 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
2914 PointerMotionMask
| ButtonReleaseMask
,
2915 GrabModeAsync
, GrabModeAsync
,
2916 None
, blackbox
->getMoveCursor(), CurrentTime
);
2918 if (windowmenu
&& windowmenu
->isVisible())
2921 flags
.moving
= True
;
2922 blackbox
->setChangingWindow(this);
2924 if (! screen
->doOpaqueMove()) {
2925 XGrabServer(blackbox
->getXDisplay());
2927 frame
.changing
= frame
.rect
;
2928 screen
->showPosition(frame
.changing
.x(), frame
.changing
.y());
2930 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2934 frame
.changing
.width() - 1,
2935 frame
.changing
.height() - 1);
2938 frame
.grab_x
= x_root
- frame
.rect
.x() - frame
.border_w
;
2939 frame
.grab_y
= y_root
- frame
.rect
.y() - frame
.border_w
;
2943 void BlackboxWindow::doMove(int x_root
, int y_root
) {
2944 assert(flags
.moving
);
2945 assert(blackbox
->getChangingWindow() == this);
2947 int dx
= x_root
- frame
.grab_x
, dy
= y_root
- frame
.grab_y
;
2948 dx
-= frame
.border_w
;
2949 dy
-= frame
.border_w
;
2951 const int snap_distance
= screen
->getEdgeSnapThreshold();
2953 if (snap_distance
) {
2955 const int wleft
= dx
,
2956 wright
= dx
+ frame
.rect
.width() - 1,
2958 wbottom
= dy
+ frame
.rect
.height() - 1;
2960 if (screen
->getWindowToWindowSnap()) {
2961 Workspace
*w
= screen
->getWorkspace(getWorkspaceNumber());
2964 // try snap to another window
2965 for (unsigned int i
= 0, c
= w
->getCount(); i
< c
; ++i
) {
2966 BlackboxWindow
*snapwin
= w
->getWindow(i
);
2967 if (snapwin
== this)
2968 continue; // don't snap to self
2970 bool snapped
= False
;
2972 const Rect
&winrect
= snapwin
->frameRect();
2973 int dleft
= std::abs(wright
- winrect
.left()),
2974 dright
= std::abs(wleft
- winrect
.right()),
2975 dtop
= std::abs(wbottom
- winrect
.top()),
2976 dbottom
= std::abs(wtop
- winrect
.bottom());
2978 if (wtop
>= (signed)(winrect
.y() - frame
.rect
.height() + 1) &&
2979 wtop
< (signed)(winrect
.y() + winrect
.height() - 1)) {
2981 // snap left of other window?
2982 if (dleft
< snap_distance
&& dleft
<= dright
) {
2983 dx
= winrect
.left() - frame
.rect
.width();
2986 // snap right of other window?
2987 else if (dright
< snap_distance
) {
2988 dx
= winrect
.right() + 1;
2993 if (screen
->getWindowCornerSnap()) {
2994 // try corner-snap to its other sides
2995 dtop
= std::abs(wtop
- winrect
.top());
2996 dbottom
= std::abs(wbottom
- winrect
.bottom());
2997 if (dtop
< snap_distance
&& dtop
<= dbottom
)
2999 else if (dbottom
< snap_distance
)
3000 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
3007 if (wleft
>= (signed)(winrect
.x() - frame
.rect
.width() + 1) &&
3008 wleft
< (signed)(winrect
.x() + winrect
.width() - 1)) {
3010 // snap top of other window?
3011 if (dtop
< snap_distance
&& dtop
<= dbottom
) {
3012 dy
= winrect
.top() - frame
.rect
.height();
3015 // snap bottom of other window?
3016 else if (dbottom
< snap_distance
) {
3017 dy
= winrect
.bottom() + 1;
3022 if (screen
->getWindowCornerSnap()) {
3023 // try corner-snap to its other sides
3024 dleft
= std::abs(wleft
- winrect
.left());
3025 dright
= std::abs(wright
- winrect
.right());
3026 if (dleft
< snap_distance
&& dleft
<= dright
)
3027 dx
= winrect
.left();
3028 else if (dright
< snap_distance
)
3029 dx
= winrect
.right() - frame
.rect
.width() + 1;
3038 // try snap to the screen's available area
3039 Rect srect
= screen
->availableArea();
3041 int dleft
= std::abs(wleft
- srect
.left()),
3042 dright
= std::abs(wright
- srect
.right()),
3043 dtop
= std::abs(wtop
- srect
.top()),
3044 dbottom
= std::abs(wbottom
- srect
.bottom());
3047 if (dleft
< snap_distance
&& dleft
<= dright
)
3050 else if (dright
< snap_distance
)
3051 dx
= srect
.right() - frame
.rect
.width() + 1;
3054 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3057 else if (dbottom
< snap_distance
)
3058 dy
= srect
.bottom() - frame
.rect
.height() + 1;
3060 srect
= screen
->getRect(); // now get the full screen
3062 dleft
= std::abs(wleft
- srect
.left()),
3063 dright
= std::abs(wright
- srect
.right()),
3064 dtop
= std::abs(wtop
- srect
.top()),
3065 dbottom
= std::abs(wbottom
- srect
.bottom());
3068 if (dleft
< snap_distance
&& dleft
<= dright
)
3071 else if (dright
< snap_distance
)
3072 dx
= srect
.right() - frame
.rect
.width() + 1;
3075 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3078 else if (dbottom
< snap_distance
)
3079 dy
= srect
.bottom() - frame
.rect
.height() + 1;
3082 if (screen
->doOpaqueMove()) {
3083 configure(dx
, dy
, frame
.rect
.width(), frame
.rect
.height());
3085 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3089 frame
.changing
.width() - 1,
3090 frame
.changing
.height() - 1);
3092 frame
.changing
.setPos(dx
, dy
);
3094 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3098 frame
.changing
.width() - 1,
3099 frame
.changing
.height() - 1);
3102 screen
->showPosition(dx
, dy
);
3106 void BlackboxWindow::endMove(void) {
3107 assert(flags
.moving
);
3108 assert(blackbox
->getChangingWindow() == this);
3110 flags
.moving
= False
;
3111 blackbox
->setChangingWindow(0);
3113 if (! screen
->doOpaqueMove()) {
3114 /* when drawing the rubber band, we need to make sure we only draw inside
3115 * the frame... frame.changing_* contain the new coords for the window,
3116 * so we need to subtract 1 from changing_w/changing_h every where we
3117 * draw the rubber band (for both moving and resizing)
3119 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3120 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3121 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3122 XUngrabServer(blackbox
->getXDisplay());
3124 configure(frame
.changing
.x(), frame
.changing
.y(),
3125 frame
.changing
.width(), frame
.changing
.height());
3127 configure(frame
.rect
.x(), frame
.rect
.y(),
3128 frame
.rect
.width(), frame
.rect
.height());
3130 screen
->hideGeometry();
3132 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3134 // if there are any left over motions from the move, drop them now
3135 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3137 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3142 void BlackboxWindow::beginResize(int x_root
, int y_root
, Corner dir
) {
3143 assert(! (flags
.resizing
|| flags
.moving
));
3146 Only one window can be moved/resized at a time. If another window is already
3147 being moved or resized, then stop it before whating to work with this one.
3149 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3150 if (changing
&& changing
!= this) {
3151 if (changing
->flags
.moving
)
3152 changing
->endMove();
3153 else // if (changing->flags.resizing)
3154 changing
->endResize();
3162 switch (resize_dir
) {
3165 cursor
= blackbox
->getLowerLeftAngleCursor();
3170 cursor
= blackbox
->getLowerRightAngleCursor();
3174 anchor
= BottomRight
;
3175 cursor
= blackbox
->getUpperLeftAngleCursor();
3179 anchor
= BottomLeft
;
3180 cursor
= blackbox
->getUpperRightAngleCursor();
3184 assert(false); // unhandled Corner
3185 return; // unreachable, for the compiler
3188 XGrabServer(blackbox
->getXDisplay());
3189 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3190 PointerMotionMask
| ButtonReleaseMask
,
3191 GrabModeAsync
, GrabModeAsync
, None
, cursor
, CurrentTime
);
3193 flags
.resizing
= True
;
3194 blackbox
->setChangingWindow(this);
3197 frame
.changing
= frame
.rect
;
3199 constrain(anchor
, &gw
, &gh
);
3201 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3202 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3203 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3205 screen
->showGeometry(gw
, gh
);
3207 frame
.grab_x
= x_root
;
3208 frame
.grab_y
= y_root
;
3212 void BlackboxWindow::doResize(int x_root
, int y_root
) {
3213 assert(flags
.resizing
);
3214 assert(blackbox
->getChangingWindow() == this);
3216 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3217 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3218 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3223 switch (resize_dir
) {
3226 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3227 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3231 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3232 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3235 anchor
= BottomRight
;
3236 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3237 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3240 anchor
= BottomLeft
;
3241 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3242 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3246 assert(false); // unhandled Corner
3247 return; // unreachable, for the compiler
3250 constrain(anchor
, &gw
, &gh
);
3252 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3253 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3254 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3256 screen
->showGeometry(gw
, gh
);
3260 void BlackboxWindow::endResize(void) {
3261 assert(flags
.resizing
);
3262 assert(blackbox
->getChangingWindow() == this);
3264 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3265 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3266 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3267 XUngrabServer(blackbox
->getXDisplay());
3269 // unset maximized state after resized when fully maximized
3270 if (flags
.maximized
== 1)
3273 flags
.resizing
= False
;
3274 blackbox
->setChangingWindow(0);
3276 configure(frame
.changing
.x(), frame
.changing
.y(),
3277 frame
.changing
.width(), frame
.changing
.height());
3278 screen
->hideGeometry();
3280 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3282 // if there are any left over motions from the resize, drop them now
3283 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3285 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3290 void BlackboxWindow::motionNotifyEvent(const XMotionEvent
*me
) {
3292 fprintf(stderr
, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n",
3297 doMove(me
->x_root
, me
->y_root
);
3298 } else if (flags
.resizing
) {
3299 doResize(me
->x_root
, me
->y_root
);
3301 if (!flags
.resizing
&& me
->state
& Button1Mask
&& (functions
& Func_Move
) &&
3302 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3303 frame
.handle
== me
->window
|| frame
.window
== me
->window
)) {
3304 beginMove(me
->x_root
, me
->y_root
);
3305 } else if ((functions
& Func_Resize
) &&
3306 (me
->state
& Button1Mask
&& (me
->window
== frame
.right_grip
||
3307 me
->window
== frame
.left_grip
)) ||
3308 (me
->state
& Button3Mask
&& me
->state
& Mod1Mask
&&
3309 me
->window
== frame
.window
)) {
3310 unsigned int zones
= screen
->getResizeZones();
3313 if (me
->window
== frame
.left_grip
) {
3314 corner
= BottomLeft
;
3315 } else if (me
->window
== frame
.right_grip
|| zones
== 1) {
3316 corner
= BottomRight
;
3319 bool left
= (me
->x_root
- frame
.rect
.x() <=
3320 static_cast<signed>(frame
.rect
.width() / 2));
3323 else // (zones == 4)
3324 top
= (me
->y_root
- frame
.rect
.y() <=
3325 static_cast<signed>(frame
.rect
.height() / 2));
3326 corner
= (top
? (left
? TopLeft
: TopRight
) :
3327 (left
? BottomLeft
: BottomRight
));
3330 beginResize(me
->x_root
, me
->y_root
, corner
);
3337 void BlackboxWindow::shapeEvent(XShapeEvent
*) {
3338 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
3345 bool BlackboxWindow::validateClient(void) const {
3346 XSync(blackbox
->getXDisplay(), False
);
3349 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3350 DestroyNotify
, &e
) ||
3351 XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3353 XPutBackEvent(blackbox
->getXDisplay(), &e
);
3362 void BlackboxWindow::restore(bool remap
) {
3363 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeDelete
);
3364 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
3365 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, NoEventMask
);
3367 // do not leave a shaded window as an icon unless it was an icon
3368 if (flags
.shaded
&& ! flags
.iconic
) setState(NormalState
);
3370 restoreGravity(client
.rect
);
3372 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
3373 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
3375 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, client
.old_bw
);
3378 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3379 ReparentNotify
, &ev
)) {
3382 // according to the ICCCM - if the client doesn't reparent to
3383 // root, then we have to do it for them
3384 XReparentWindow(blackbox
->getXDisplay(), client
.window
,
3385 screen
->getRootWindow(),
3386 client
.rect
.x(), client
.rect
.y());
3389 if (remap
) XMapWindow(blackbox
->getXDisplay(), client
.window
);
3393 // timer for autoraise
3394 void BlackboxWindow::timeout(void) {
3395 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3399 void BlackboxWindow::changeBlackboxHints(BlackboxHints
*net
) {
3400 if ((net
->flags
& AttribShaded
) &&
3401 ((blackbox_attrib
.attrib
& AttribShaded
) !=
3402 (net
->attrib
& AttribShaded
)))
3405 if (flags
.visible
&& // watch out for requests when we can not be seen
3406 (net
->flags
& (AttribMaxVert
| AttribMaxHoriz
)) &&
3407 ((blackbox_attrib
.attrib
& (AttribMaxVert
| AttribMaxHoriz
)) !=
3408 (net
->attrib
& (AttribMaxVert
| AttribMaxHoriz
)))) {
3409 if (flags
.maximized
) {
3414 if ((net
->flags
& AttribMaxHoriz
) && (net
->flags
& AttribMaxVert
))
3415 button
= ((net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0);
3416 else if (net
->flags
& AttribMaxVert
)
3417 button
= ((net
->attrib
& AttribMaxVert
) ? 2 : 0);
3418 else if (net
->flags
& AttribMaxHoriz
)
3419 button
= ((net
->attrib
& AttribMaxHoriz
) ? 3 : 0);
3425 if ((net
->flags
& AttribOmnipresent
) &&
3426 ((blackbox_attrib
.attrib
& AttribOmnipresent
) !=
3427 (net
->attrib
& AttribOmnipresent
)))
3430 if ((net
->flags
& AttribWorkspace
) &&
3431 (blackbox_attrib
.workspace
!= net
->workspace
)) {
3432 screen
->reassociateWindow(this, net
->workspace
, True
);
3434 if (screen
->getCurrentWorkspaceID() != net
->workspace
) {
3438 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3442 if (net
->flags
& AttribDecoration
) {
3443 switch (net
->decoration
) {
3445 // clear all decorations except close
3446 decorations
&= Decor_Close
;
3452 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Iconify
;
3454 decorations
= ((functions
& Func_Resize
) && !isTransient() ?
3455 decorations
| Decor_Handle
:
3456 decorations
&= ~Decor_Handle
);
3457 decorations
= (functions
& Func_Maximize
?
3458 decorations
| Decor_Maximize
:
3459 decorations
&= ~Decor_Maximize
);
3464 decorations
|= Decor_Titlebar
| Decor_Iconify
;
3465 decorations
&= ~(Decor_Border
| Decor_Handle
);
3467 decorations
= (functions
& Func_Maximize
?
3468 decorations
| Decor_Maximize
:
3469 decorations
&= ~Decor_Maximize
);
3474 decorations
|= Decor_Titlebar
;
3475 decorations
&= ~(Decor_Iconify
| Decor_Border
);
3477 decorations
= ((functions
& Func_Resize
) && !isTransient() ?
3478 decorations
| Decor_Handle
:
3479 decorations
&= ~Decor_Handle
);
3480 decorations
= (functions
& Func_Maximize
?
3481 decorations
| Decor_Maximize
:
3482 decorations
&= ~Decor_Maximize
);
3487 // we can not be shaded if we lack a titlebar
3488 if (flags
.shaded
&& ! (decorations
& Decor_Titlebar
))
3491 if (flags
.visible
&& frame
.window
) {
3492 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
3493 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
3497 setState(current_state
);
3503 * Set the sizes of all components of the window frame
3504 * (the window decorations).
3505 * These values are based upon the current style settings and the client
3506 * window's dimensions.
3508 void BlackboxWindow::upsize(void) {
3509 frame
.bevel_w
= screen
->getBevelWidth();
3511 if (decorations
& Decor_Border
) {
3512 frame
.border_w
= screen
->getBorderWidth();
3513 if (! isTransient())
3514 frame
.mwm_border_w
= screen
->getFrameWidth();
3516 frame
.mwm_border_w
= 0;
3518 frame
.mwm_border_w
= frame
.border_w
= 0;
3521 if (decorations
& Decor_Titlebar
) {
3522 // the height of the titlebar is based upon the height of the font being
3523 // used to display the window's title
3524 WindowStyle
*style
= screen
->getWindowStyle();
3525 frame
.title_h
= style
->font
->height() + (frame
.bevel_w
* 2) + 2;
3527 frame
.label_h
= frame
.title_h
- (frame
.bevel_w
* 2);
3528 frame
.button_w
= (frame
.label_h
- 2);
3530 // set the top frame margin
3531 frame
.margin
.top
= frame
.border_w
+ frame
.title_h
+
3532 frame
.border_w
+ frame
.mwm_border_w
;
3538 // set the top frame margin
3539 frame
.margin
.top
= frame
.border_w
+ frame
.mwm_border_w
;
3542 // set the left/right frame margin
3543 frame
.margin
.left
= frame
.margin
.right
= frame
.border_w
+ frame
.mwm_border_w
;
3545 if (decorations
& Decor_Handle
) {
3546 frame
.grip_w
= frame
.button_w
* 2;
3547 frame
.handle_h
= screen
->getHandleWidth();
3549 // set the bottom frame margin
3550 frame
.margin
.bottom
= frame
.border_w
+ frame
.handle_h
+
3551 frame
.border_w
+ frame
.mwm_border_w
;
3556 // set the bottom frame margin
3557 frame
.margin
.bottom
= frame
.border_w
+ frame
.mwm_border_w
;
3561 We first get the normal dimensions and use this to define the inside_w/h
3562 then we modify the height if shading is in effect.
3563 If the shade state is not considered then frame.rect gets reset to the
3564 normal window size on a reconfigure() call resulting in improper
3565 dimensions appearing in move/resize and other events.
3568 height
= client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
,
3569 width
= client
.rect
.width() + frame
.margin
.left
+ frame
.margin
.right
;
3571 frame
.inside_w
= width
- (frame
.border_w
* 2);
3572 frame
.inside_h
= height
- (frame
.border_w
* 2);
3575 height
= frame
.title_h
+ (frame
.border_w
* 2);
3576 frame
.rect
.setSize(width
, height
);
3581 * Calculate the size of the client window and constrain it to the
3582 * size specified by the size hints of the client window.
3584 * The logical width and height are placed into pw and ph, if they
3585 * are non-zero. Logical size refers to the users perception of
3586 * the window size (for example an xterm resizes in cells, not in pixels).
3588 * The physical geometry is placed into frame.changing_{x,y,width,height}.
3589 * Physical geometry refers to the geometry of the window in pixels.
3591 void BlackboxWindow::constrain(Corner anchor
, int *pw
, int *ph
) {
3592 // frame.changing represents the requested frame size, we need to
3593 // strip the frame margin off and constrain the client size
3594 frame
.changing
.setCoords(frame
.changing
.left() + frame
.margin
.left
,
3595 frame
.changing
.top() + frame
.margin
.top
,
3596 frame
.changing
.right() - frame
.margin
.right
,
3597 frame
.changing
.bottom() - frame
.margin
.bottom
);
3599 int dw
= frame
.changing
.width(), dh
= frame
.changing
.height(),
3600 base_width
= (client
.base_width
) ? client
.base_width
: client
.min_width
,
3601 base_height
= (client
.base_height
) ? client
.base_height
:
3605 if (dw
< static_cast<signed>(client
.min_width
)) dw
= client
.min_width
;
3606 if (dh
< static_cast<signed>(client
.min_height
)) dh
= client
.min_height
;
3607 if (dw
> static_cast<signed>(client
.max_width
)) dw
= client
.max_width
;
3608 if (dh
> static_cast<signed>(client
.max_height
)) dh
= client
.max_height
;
3611 dw
/= client
.width_inc
;
3613 dh
/= client
.height_inc
;
3616 if (client
.width_inc
== 1)
3617 *pw
= dw
+ base_width
;
3622 if (client
.height_inc
== 1)
3623 *ph
= dh
+ base_height
;
3628 dw
*= client
.width_inc
;
3630 dh
*= client
.height_inc
;
3633 frame
.changing
.setSize(dw
, dh
);
3635 // add the frame margin back onto frame.changing
3636 frame
.changing
.setCoords(frame
.changing
.left() - frame
.margin
.left
,
3637 frame
.changing
.top() - frame
.margin
.top
,
3638 frame
.changing
.right() + frame
.margin
.right
,
3639 frame
.changing
.bottom() + frame
.margin
.bottom
);
3641 // move frame.changing to the specified anchor
3649 dx
= frame
.rect
.right() - frame
.changing
.right();
3653 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3657 dx
= frame
.rect
.right() - frame
.changing
.right();
3658 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3662 assert(false); // unhandled corner
3664 frame
.changing
.setPos(frame
.changing
.x() + dx
, frame
.changing
.y() + dy
);
3668 void WindowStyle::doJustify(const std::string
&text
, int &start_pos
,
3669 unsigned int max_length
,
3670 unsigned int modifier
) const {
3671 size_t text_len
= text
.size();
3672 unsigned int length
;
3675 length
= font
->measureString(string(text
, 0, text_len
)) + modifier
;
3676 } while (length
> max_length
&& text_len
-- > 0);
3680 start_pos
+= max_length
- length
;
3684 start_pos
+= (max_length
- length
) / 2;
3694 BWindowGroup::BWindowGroup(Blackbox
*b
, Window _group
)
3695 : blackbox(b
), group(_group
) {
3696 XWindowAttributes wattrib
;
3697 if (! XGetWindowAttributes(blackbox
->getXDisplay(), group
, &wattrib
)) {
3698 // group window doesn't seem to exist anymore
3703 XSelectInput(blackbox
->getXDisplay(), group
,
3704 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
3706 blackbox
->saveGroupSearch(group
, this);
3710 BWindowGroup::~BWindowGroup(void) {
3711 blackbox
->removeGroupSearch(group
);
3716 BWindowGroup::find(BScreen
*screen
, bool allow_transients
) const {
3717 BlackboxWindow
*ret
= blackbox
->getFocusedWindow();
3719 // does the focus window match (or any transient_fors)?
3721 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3722 if (ret
->isTransient() && allow_transients
) break;
3723 else if (! ret
->isTransient()) break;
3726 ret
= ret
->getTransientFor();
3729 if (ret
) return ret
;
3731 // the focus window didn't match, look in the group's window list
3732 BlackboxWindowList::const_iterator it
, end
= windowList
.end();
3733 for (it
= windowList
.begin(); it
!= end
; ++it
) {
3735 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3736 if (ret
->isTransient() && allow_transients
) break;
3737 else if (! ret
->isTransient()) break;