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"
49 #include "Iconmenu.hh"
55 #include "Windowmenu.hh"
56 #include "Workspace.hh"
62 * Initializes the class with default values/the window's set initial values.
64 BlackboxWindow::BlackboxWindow(Blackbox
*b
, Window w
, BScreen
*s
) {
65 // fprintf(stderr, "BlackboxWindow size: %d bytes\n",
66 // sizeof(BlackboxWindow));
69 fprintf(stderr
, "BlackboxWindow::BlackboxWindow(): creating 0x%lx\n", w
);
73 set timer to zero... it is initialized properly later, so we check
74 if timer is zero in the destructor, and assume that the window is not
75 fully constructed if timer is zero...
81 xatom
= blackbox
->getXAtom();
83 if (! validateClient()) {
88 // set the eventmask early in the game so that we make sure we get
89 // all the events we are interested in
90 XSetWindowAttributes attrib_set
;
91 attrib_set
.event_mask
= PropertyChangeMask
| FocusChangeMask
|
93 attrib_set
.do_not_propagate_mask
= ButtonPressMask
| ButtonReleaseMask
|
95 XChangeWindowAttributes(blackbox
->getXDisplay(), client
.window
,
96 CWEventMask
|CWDontPropagate
, &attrib_set
);
98 // fetch client size and placement
99 XWindowAttributes wattrib
;
100 if ((! XGetWindowAttributes(blackbox
->getXDisplay(),
101 client
.window
, &wattrib
)) ||
102 (! wattrib
.screen
) || wattrib
.override_redirect
) {
105 "BlackboxWindow::BlackboxWindow(): XGetWindowAttributes failed\n");
112 flags
.moving
= flags
.resizing
= flags
.shaded
= flags
.visible
=
113 flags
.iconic
= flags
.focused
= flags
.stuck
= flags
.modal
=
114 flags
.send_focus_message
= flags
.shaped
= flags
.skip_taskbar
=
115 flags
.skip_pager
= flags
.fullscreen
= False
;
118 blackbox_attrib
.workspace
= window_number
= BSENTINEL
;
120 blackbox_attrib
.flags
= blackbox_attrib
.attrib
= blackbox_attrib
.stack
121 = blackbox_attrib
.decoration
= 0l;
122 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
123 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
126 frame
.window
= frame
.plate
= frame
.title
= frame
.handle
= None
;
127 frame
.close_button
= frame
.iconify_button
= frame
.maximize_button
= None
;
128 frame
.right_grip
= frame
.left_grip
= None
;
130 frame
.ulabel_pixel
= frame
.flabel_pixel
= frame
.utitle_pixel
=
131 frame
.ftitle_pixel
= frame
.uhandle_pixel
= frame
.fhandle_pixel
=
132 frame
.ubutton_pixel
= frame
.fbutton_pixel
= frame
.pbutton_pixel
=
133 frame
.uborder_pixel
= frame
.fborder_pixel
= frame
.ugrip_pixel
=
134 frame
.fgrip_pixel
= 0;
135 frame
.utitle
= frame
.ftitle
= frame
.uhandle
= frame
.fhandle
= None
;
136 frame
.ulabel
= frame
.flabel
= frame
.ubutton
= frame
.fbutton
= None
;
137 frame
.pbutton
= frame
.ugrip
= frame
.fgrip
= None
;
139 decorations
= Decor_Titlebar
| Decor_Border
| Decor_Handle
|
140 Decor_Iconify
| Decor_Maximize
;
141 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
143 client
.wm_hint_flags
= client
.normal_hint_flags
= 0;
144 client
.window_group
= None
;
145 client
.transient_for
= 0;
148 get the initial size and location of client window (relative to the
149 _root window_). This position is the reference point used with the
150 window's gravity to find the window's initial position.
152 client
.rect
.setRect(wattrib
.x
, wattrib
.y
, wattrib
.width
, wattrib
.height
);
153 client
.old_bw
= wattrib
.border_width
;
157 lastButtonPressTime
= 0;
159 // get size, aspect, minimum/maximum size and other hints set by the
165 if (client
.initial_state
== WithdrawnState
) {
166 screen
->getSlit()->addClient(client
.window
);
171 timer
= new BTimer(blackbox
, this);
172 timer
->setTimeout(blackbox
->getAutoRaiseDelay());
174 if (! getBlackboxHints()) {
179 frame
.window
= createToplevelWindow();
180 frame
.plate
= createChildWindow(frame
.window
);
181 associateClientWindow();
183 blackbox
->saveWindowSearch(frame
.window
, this);
184 blackbox
->saveWindowSearch(frame
.plate
, this);
185 blackbox
->saveWindowSearch(client
.window
, this);
187 // determine if this is a transient window
190 // determine the window's type, so we can decide its decorations and
191 // functionality, or if we should not manage it at all
194 // adjust the window decorations/behavior based on the window type
195 switch (window_type
) {
202 // none of these windows are decorated or manipulated by the window manager
205 blackbox_attrib
.workspace
= 0; // we do need to belong to a workspace
206 flags
.stuck
= True
; // we show up on all workspaces
210 // dialogs cannot be maximized, and don't display a handle
211 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
212 functions
&= ~Func_Maximize
;
216 // normal windows retain all of the possible decorations and functionality
220 // further adjeust the window's decorations/behavior based on window sizes
221 if ((client
.normal_hint_flags
& PMinSize
) &&
222 (client
.normal_hint_flags
& PMaxSize
) &&
223 client
.max_width
<= client
.min_width
&&
224 client
.max_height
<= client
.min_height
) {
225 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
226 functions
&= ~(Func_Resize
| Func_Maximize
);
232 bool place_window
= True
;
233 if (blackbox
->isStartup() || isTransient() ||
234 client
.normal_hint_flags
& (PPosition
|USPosition
)) {
235 applyGravity(frame
.rect
);
237 if (blackbox
->isStartup() || client
.rect
.intersects(screen
->getRect()))
238 place_window
= False
;
241 // add the window's strut. note this is done *after* placing the window.
242 screen
->addStrut(&client
.strut
);
245 if (decorations
& Decor_Titlebar
)
248 if (decorations
& Decor_Handle
)
252 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
257 windowmenu
= new Windowmenu(this);
259 if (blackbox_attrib
.workspace
>= screen
->getWorkspaceCount())
260 screen
->getCurrentWorkspace()->addWindow(this, place_window
);
262 screen
->getWorkspace(blackbox_attrib
.workspace
)->
263 addWindow(this, place_window
);
265 if (! place_window
) {
266 // don't need to call configure if we are letting the workspace
268 configure(frame
.rect
.x(), frame
.rect
.y(),
269 frame
.rect
.width(), frame
.rect
.height());
272 // preserve the window's initial state on first map, and its current state
275 if (client
.wm_hint_flags
& StateHint
)
276 current_state
= client
.initial_state
;
278 current_state
= NormalState
;
281 // get sticky state from our parent window if we've got one
282 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
283 client
.transient_for
->isStuck() != flags
.stuck
)
287 flags
.shaded
= False
;
288 unsigned long orig_state
= current_state
;
292 At this point in the life of a window, current_state should only be set
293 to IconicState if the window was an *icon*, not if it was shaded.
295 if (orig_state
!= IconicState
)
296 current_state
= NormalState
;
304 if (flags
.maximized
&& (functions
& Func_Maximize
)) {
309 When the window is mapped (and also when its attributes are restored), the
310 current_state that was set here will be used.
311 It is set to Normal if the window is to be mapped or it is set to Iconic
312 if the window is to be iconified.
313 *Note* that for sticky windows, the same rules apply here, they are in
314 fact never set to Iconic since there is no way for us to tell if a sticky
315 window was iconified previously.
322 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
328 BlackboxWindow::~BlackboxWindow(void) {
330 fprintf(stderr
, "BlackboxWindow::~BlackboxWindow: destroying 0x%lx\n",
334 if (! timer
) // window not managed...
337 screen
->removeStrut(&client
.strut
);
338 screen
->updateAvailableArea();
340 // We don't need to worry about resizing because resizing always grabs the X
341 // server. This should only ever happen if using opaque moving.
349 if (client
.window_group
) {
350 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
351 if (group
) group
->removeWindow(this);
354 // remove ourselves from our transient_for
356 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
357 client
.transient_for
->client
.transientList
.remove(this);
359 client
.transient_for
= (BlackboxWindow
*) 0;
362 if (client
.transientList
.size() > 0) {
363 // reset transient_for for all transients
364 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
365 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
366 (*it
)->client
.transient_for
= (BlackboxWindow
*) 0;
377 blackbox
->removeWindowSearch(frame
.plate
);
378 XDestroyWindow(blackbox
->getXDisplay(), frame
.plate
);
382 blackbox
->removeWindowSearch(frame
.window
);
383 XDestroyWindow(blackbox
->getXDisplay(), frame
.window
);
386 blackbox
->removeWindowSearch(client
.window
);
391 * Creates a new top level window, with a given location, size, and border
393 * Returns: the newly created window
395 Window
BlackboxWindow::createToplevelWindow(void) {
396 XSetWindowAttributes attrib_create
;
397 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
| CWColormap
|
398 CWOverrideRedirect
| CWEventMask
;
400 attrib_create
.background_pixmap
= None
;
401 attrib_create
.colormap
= screen
->getColormap();
402 attrib_create
.override_redirect
= True
;
403 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
404 ButtonMotionMask
| EnterWindowMask
;
406 return XCreateWindow(blackbox
->getXDisplay(), screen
->getRootWindow(),
407 0, 0, 1, 1, frame
.border_w
, screen
->getDepth(),
408 InputOutput
, screen
->getVisual(), create_mask
,
414 * Creates a child window, and optionally associates a given cursor with
417 Window
BlackboxWindow::createChildWindow(Window parent
, Cursor cursor
) {
418 XSetWindowAttributes attrib_create
;
419 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
|
422 attrib_create
.background_pixmap
= None
;
423 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
424 ButtonMotionMask
| ExposureMask
;
427 create_mask
|= CWCursor
;
428 attrib_create
.cursor
= cursor
;
431 return XCreateWindow(blackbox
->getXDisplay(), parent
, 0, 0, 1, 1, 0,
432 screen
->getDepth(), InputOutput
, screen
->getVisual(),
433 create_mask
, &attrib_create
);
437 void BlackboxWindow::associateClientWindow(void) {
438 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, 0);
442 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeInsert
);
444 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, SubstructureRedirectMask
);
446 XGrabServer(blackbox
->getXDisplay());
448 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
450 XSelectInput(blackbox
->getXDisplay(), client
.window
,
451 event_mask
& ~StructureNotifyMask
);
452 XReparentWindow(blackbox
->getXDisplay(), client
.window
, frame
.plate
, 0, 0);
453 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
455 XUngrabServer(blackbox
->getXDisplay());
457 XRaiseWindow(blackbox
->getXDisplay(), frame
.plate
);
458 XMapSubwindows(blackbox
->getXDisplay(), frame
.plate
);
462 if (blackbox
->hasShapeExtensions()) {
463 XShapeSelectInput(blackbox
->getXDisplay(), client
.window
,
470 XShapeQueryExtents(blackbox
->getXDisplay(), client
.window
, &shaped
,
471 &foo
, &foo
, &ufoo
, &ufoo
, &foo
, &foo
, &foo
,
473 flags
.shaped
= shaped
;
479 void BlackboxWindow::decorate(void) {
482 texture
= &(screen
->getWindowStyle()->b_focus
);
483 frame
.fbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
486 frame
.fbutton_pixel
= texture
->color().pixel();
488 texture
= &(screen
->getWindowStyle()->b_unfocus
);
489 frame
.ubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
492 frame
.ubutton_pixel
= texture
->color().pixel();
494 texture
= &(screen
->getWindowStyle()->b_pressed
);
495 frame
.pbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
498 frame
.pbutton_pixel
= texture
->color().pixel();
500 if (decorations
& Decor_Titlebar
) {
501 texture
= &(screen
->getWindowStyle()->t_focus
);
502 frame
.ftitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
505 frame
.ftitle_pixel
= texture
->color().pixel();
507 texture
= &(screen
->getWindowStyle()->t_unfocus
);
508 frame
.utitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
511 frame
.utitle_pixel
= texture
->color().pixel();
513 XSetWindowBorder(blackbox
->getXDisplay(), frame
.title
,
514 screen
->getBorderColor()->pixel());
519 if (decorations
& Decor_Border
) {
520 frame
.fborder_pixel
= screen
->getWindowStyle()->f_focus
.pixel();
521 frame
.uborder_pixel
= screen
->getWindowStyle()->f_unfocus
.pixel();
522 blackbox_attrib
.flags
|= AttribDecoration
;
523 blackbox_attrib
.decoration
= DecorNormal
;
525 blackbox_attrib
.flags
|= AttribDecoration
;
526 blackbox_attrib
.decoration
= DecorNone
;
529 if (decorations
& Decor_Handle
) {
530 texture
= &(screen
->getWindowStyle()->h_focus
);
531 frame
.fhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
534 frame
.fhandle_pixel
= texture
->color().pixel();
536 texture
= &(screen
->getWindowStyle()->h_unfocus
);
537 frame
.uhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
540 frame
.uhandle_pixel
= texture
->color().pixel();
542 texture
= &(screen
->getWindowStyle()->g_focus
);
543 frame
.fgrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.fgrip
);
545 frame
.fgrip_pixel
= texture
->color().pixel();
547 texture
= &(screen
->getWindowStyle()->g_unfocus
);
548 frame
.ugrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.ugrip
);
550 frame
.ugrip_pixel
= texture
->color().pixel();
552 XSetWindowBorder(blackbox
->getXDisplay(), frame
.handle
,
553 screen
->getBorderColor()->pixel());
554 XSetWindowBorder(blackbox
->getXDisplay(), frame
.left_grip
,
555 screen
->getBorderColor()->pixel());
556 XSetWindowBorder(blackbox
->getXDisplay(), frame
.right_grip
,
557 screen
->getBorderColor()->pixel());
560 XSetWindowBorder(blackbox
->getXDisplay(), frame
.window
,
561 screen
->getBorderColor()->pixel());
565 void BlackboxWindow::decorateLabel(void) {
568 texture
= &(screen
->getWindowStyle()->l_focus
);
569 frame
.flabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.flabel
);
571 frame
.flabel_pixel
= texture
->color().pixel();
573 texture
= &(screen
->getWindowStyle()->l_unfocus
);
574 frame
.ulabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.ulabel
);
576 frame
.ulabel_pixel
= texture
->color().pixel();
580 void BlackboxWindow::createHandle(void) {
581 frame
.handle
= createChildWindow(frame
.window
);
582 blackbox
->saveWindowSearch(frame
.handle
, this);
585 createChildWindow(frame
.handle
, blackbox
->getLowerLeftAngleCursor());
586 blackbox
->saveWindowSearch(frame
.left_grip
, this);
589 createChildWindow(frame
.handle
, blackbox
->getLowerRightAngleCursor());
590 blackbox
->saveWindowSearch(frame
.right_grip
, this);
594 void BlackboxWindow::destroyHandle(void) {
596 screen
->getImageControl()->removeImage(frame
.fhandle
);
599 screen
->getImageControl()->removeImage(frame
.uhandle
);
602 screen
->getImageControl()->removeImage(frame
.fgrip
);
605 screen
->getImageControl()->removeImage(frame
.ugrip
);
607 blackbox
->removeWindowSearch(frame
.left_grip
);
608 blackbox
->removeWindowSearch(frame
.right_grip
);
610 XDestroyWindow(blackbox
->getXDisplay(), frame
.left_grip
);
611 XDestroyWindow(blackbox
->getXDisplay(), frame
.right_grip
);
612 frame
.left_grip
= frame
.right_grip
= None
;
614 blackbox
->removeWindowSearch(frame
.handle
);
615 XDestroyWindow(blackbox
->getXDisplay(), frame
.handle
);
620 void BlackboxWindow::createTitlebar(void) {
621 frame
.title
= createChildWindow(frame
.window
);
622 frame
.label
= createChildWindow(frame
.title
);
623 blackbox
->saveWindowSearch(frame
.title
, this);
624 blackbox
->saveWindowSearch(frame
.label
, this);
626 if (decorations
& Decor_Iconify
) createIconifyButton();
627 if (decorations
& Decor_Maximize
) createMaximizeButton();
628 if (decorations
& Decor_Close
) createCloseButton();
632 void BlackboxWindow::destroyTitlebar(void) {
633 if (frame
.close_button
)
634 destroyCloseButton();
636 if (frame
.iconify_button
)
637 destroyIconifyButton();
639 if (frame
.maximize_button
)
640 destroyMaximizeButton();
643 screen
->getImageControl()->removeImage(frame
.ftitle
);
646 screen
->getImageControl()->removeImage(frame
.utitle
);
649 screen
->getImageControl()->removeImage(frame
.flabel
);
652 screen
->getImageControl()->removeImage(frame
.ulabel
);
655 screen
->getImageControl()->removeImage(frame
.fbutton
);
658 screen
->getImageControl()->removeImage(frame
.ubutton
);
661 screen
->getImageControl()->removeImage(frame
.pbutton
);
663 blackbox
->removeWindowSearch(frame
.title
);
664 blackbox
->removeWindowSearch(frame
.label
);
666 XDestroyWindow(blackbox
->getXDisplay(), frame
.label
);
667 XDestroyWindow(blackbox
->getXDisplay(), frame
.title
);
668 frame
.title
= frame
.label
= None
;
672 void BlackboxWindow::createCloseButton(void) {
673 if (frame
.title
!= None
) {
674 frame
.close_button
= createChildWindow(frame
.title
);
675 blackbox
->saveWindowSearch(frame
.close_button
, this);
680 void BlackboxWindow::destroyCloseButton(void) {
681 blackbox
->removeWindowSearch(frame
.close_button
);
682 XDestroyWindow(blackbox
->getXDisplay(), frame
.close_button
);
683 frame
.close_button
= None
;
687 void BlackboxWindow::createIconifyButton(void) {
688 if (frame
.title
!= None
) {
689 frame
.iconify_button
= createChildWindow(frame
.title
);
690 blackbox
->saveWindowSearch(frame
.iconify_button
, this);
695 void BlackboxWindow::destroyIconifyButton(void) {
696 blackbox
->removeWindowSearch(frame
.iconify_button
);
697 XDestroyWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
698 frame
.iconify_button
= None
;
702 void BlackboxWindow::createMaximizeButton(void) {
703 if (frame
.title
!= None
) {
704 frame
.maximize_button
= createChildWindow(frame
.title
);
705 blackbox
->saveWindowSearch(frame
.maximize_button
, this);
710 void BlackboxWindow::destroyMaximizeButton(void) {
711 blackbox
->removeWindowSearch(frame
.maximize_button
);
712 XDestroyWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
713 frame
.maximize_button
= None
;
717 void BlackboxWindow::positionButtons(bool redecorate_label
) {
718 string layout
= blackbox
->getTitlebarLayout();
721 bool hasclose
, hasiconify
, hasmaximize
, haslabel
;
722 hasclose
= hasiconify
= hasmaximize
= haslabel
= false;
724 string::const_iterator it
, end
;
725 for (it
= layout
.begin(), end
= layout
.end(); it
!= end
; ++it
) {
728 if (! hasclose
&& (decorations
& Decor_Close
)) {
734 if (! hasiconify
&& (decorations
& Decor_Iconify
)) {
740 if (! hasmaximize
&& (decorations
& Decor_Maximize
)) {
752 if (! hasclose
&& frame
.close_button
)
753 destroyCloseButton();
754 if (! hasiconify
&& frame
.iconify_button
)
755 destroyIconifyButton();
756 if (! hasmaximize
&& frame
.maximize_button
)
757 destroyMaximizeButton();
759 parsed
+= 'L'; // require that the label be in the layout
761 const unsigned int bsep
= frame
.bevel_w
+ 1; // separation between elements
762 const unsigned int by
= frame
.bevel_w
+ 1;
763 const unsigned int ty
= frame
.bevel_w
;
765 frame
.label_w
= frame
.inside_w
- bsep
* 2 -
766 (frame
.button_w
+ bsep
) * (parsed
.size() - 1);
768 unsigned int x
= bsep
;
769 for (it
= parsed
.begin(), end
= parsed
.end(); it
!= end
; ++it
) {
772 if (! frame
.close_button
) createCloseButton();
773 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.close_button
, x
, by
,
774 frame
.button_w
, frame
.button_w
);
775 x
+= frame
.button_w
+ bsep
;
778 if (! frame
.iconify_button
) createIconifyButton();
779 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.iconify_button
, x
, by
,
780 frame
.button_w
, frame
.button_w
);
781 x
+= frame
.button_w
+ bsep
;
784 if (! frame
.maximize_button
) createMaximizeButton();
785 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.maximize_button
, x
, by
,
786 frame
.button_w
, frame
.button_w
);
787 x
+= frame
.button_w
+ bsep
;
790 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.label
, x
, ty
,
791 frame
.label_w
, frame
.label_h
);
792 x
+= frame
.label_w
+ bsep
;
797 if (redecorate_label
) decorateLabel();
803 void BlackboxWindow::reconfigure(void) {
804 restoreGravity(client
.rect
);
806 applyGravity(frame
.rect
);
815 windowmenu
->move(windowmenu
->getX(), frame
.rect
.y() + frame
.title_h
);
816 windowmenu
->reconfigure();
821 void BlackboxWindow::grabButtons(void) {
822 if ((! screen
->isSloppyFocus()) || screen
->doClickRaise())
823 // grab button 1 for changing focus/raising
824 blackbox
->grabButton(Button1
, 0, frame
.plate
, True
, ButtonPressMask
,
825 GrabModeSync
, GrabModeSync
, frame
.plate
, None
);
827 if (functions
& Func_Move
)
828 blackbox
->grabButton(Button1
, Mod1Mask
, frame
.window
, True
,
829 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
830 GrabModeAsync
, frame
.window
,
831 blackbox
->getMoveCursor());
832 if (functions
& Func_Resize
)
833 blackbox
->grabButton(Button3
, Mod1Mask
, frame
.window
, True
,
834 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
835 GrabModeAsync
, frame
.window
, None
);
836 // alt+middle lowers the window
837 blackbox
->grabButton(Button2
, Mod1Mask
, frame
.window
, True
,
838 ButtonReleaseMask
, GrabModeAsync
, GrabModeAsync
,
843 void BlackboxWindow::ungrabButtons(void) {
844 if ((! screen
->isSloppyFocus()) || screen
->doClickRaise())
845 blackbox
->ungrabButton(Button1
, 0, frame
.plate
);
847 blackbox
->ungrabButton(Button1
, Mod1Mask
, frame
.window
);
848 blackbox
->ungrabButton(Button2
, Mod1Mask
, frame
.window
);
849 blackbox
->ungrabButton(Button3
, Mod1Mask
, frame
.window
);
853 void BlackboxWindow::positionWindows(void) {
854 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.window
,
855 frame
.rect
.x(), frame
.rect
.y(), frame
.inside_w
,
856 (flags
.shaded
) ? frame
.title_h
: frame
.inside_h
);
857 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.window
,
859 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.plate
,
861 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.plate
,
862 frame
.margin
.left
- frame
.mwm_border_w
- frame
.border_w
,
863 frame
.margin
.top
- frame
.mwm_border_w
- frame
.border_w
,
864 client
.rect
.width(), client
.rect
.height());
865 XMoveResizeWindow(blackbox
->getXDisplay(), client
.window
,
866 0, 0, client
.rect
.width(), client
.rect
.height());
867 // ensure client.rect contains the real location
868 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
869 frame
.rect
.top() + frame
.margin
.top
);
871 if (decorations
& Decor_Titlebar
) {
872 if (frame
.title
== None
) createTitlebar();
874 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.title
,
876 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.title
, -frame
.border_w
,
877 -frame
.border_w
, frame
.inside_w
, frame
.title_h
);
880 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
881 XMapWindow(blackbox
->getXDisplay(), frame
.title
);
882 } else if (frame
.title
) {
885 if (decorations
& Decor_Handle
) {
886 if (frame
.handle
== None
) createHandle();
887 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.handle
,
889 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.left_grip
,
891 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.right_grip
,
894 // use client.rect here so the value is correct even if shaded
895 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.handle
,
897 client
.rect
.height() + frame
.margin
.top
+
898 frame
.mwm_border_w
- frame
.border_w
,
899 frame
.inside_w
, frame
.handle_h
);
900 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.left_grip
,
901 -frame
.border_w
, -frame
.border_w
,
902 frame
.grip_w
, frame
.handle_h
);
903 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.right_grip
,
904 frame
.inside_w
- frame
.grip_w
- frame
.border_w
,
905 -frame
.border_w
, frame
.grip_w
, frame
.handle_h
);
907 XMapSubwindows(blackbox
->getXDisplay(), frame
.handle
);
908 XMapWindow(blackbox
->getXDisplay(), frame
.handle
);
909 } else if (frame
.handle
) {
912 XSync(blackbox
->getXDisplay(), False
);
916 void BlackboxWindow::updateStrut(void) {
917 unsigned long num
= 4;
919 if (! xatom
->getValue(client
.window
, XAtom::net_wm_strut
, XAtom::cardinal
,
924 client
.strut
.left
= data
[0];
925 client
.strut
.right
= data
[1];
926 client
.strut
.top
= data
[2];
927 client
.strut
.bottom
= data
[3];
929 screen
->updateAvailableArea();
936 void BlackboxWindow::getWindowType(void) {
938 if (xatom
->getValue(client
.window
, XAtom::net_wm_window_type
, XAtom::atom
,
940 if (val
== xatom
->getAtom(XAtom::net_wm_window_type_desktop
))
941 window_type
= Type_Desktop
;
942 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_dock
))
943 window_type
= Type_Dock
;
944 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_toolbar
))
945 window_type
= Type_Toolbar
;
946 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_menu
))
947 window_type
= Type_Menu
;
948 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_utility
))
949 window_type
= Type_Utility
;
950 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_splash
))
951 window_type
= Type_Splash
;
952 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_dialog
))
953 window_type
= Type_Dialog
;
954 else //if (val[0] == xatom->getAtom(XAtom::net_wm_window_type_normal))
955 window_type
= Type_Normal
;
960 * the window type hint was not set, which means we either classify ourself
961 * as a normal window or a dialog, depending on if we are a transient.
964 window_type
= Type_Dialog
;
966 window_type
= Type_Normal
;
970 void BlackboxWindow::getWMName(void) {
971 if (xatom
->getValue(client
.window
, XAtom::net_wm_name
,
972 XAtom::utf8
, client
.title
) &&
973 !client
.title
.empty()) {
974 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
977 //fall through to using WM_NAME
978 if (xatom
->getValue(client
.window
, XAtom::wm_name
, XAtom::ansi
, client
.title
)
979 && !client
.title
.empty()) {
980 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
983 // fall back to an internal default
984 client
.title
= i18n(WindowSet
, WindowUnnamed
, "Unnamed");
985 xatom
->setValue(client
.window
, XAtom::net_wm_visible_name
, XAtom::utf8
,
990 void BlackboxWindow::getWMIconName(void) {
991 if (xatom
->getValue(client
.window
, XAtom::net_wm_icon_name
,
992 XAtom::utf8
, client
.icon_title
) &&
993 !client
.icon_title
.empty()) {
994 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
997 //fall through to using WM_ICON_NAME
998 if (xatom
->getValue(client
.window
, XAtom::wm_icon_name
, XAtom::ansi
,
999 client
.icon_title
) &&
1000 !client
.icon_title
.empty()) {
1001 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1004 // fall back to using the main name
1005 client
.icon_title
= client
.title
;
1006 xatom
->setValue(client
.window
, XAtom::net_wm_visible_icon_name
, XAtom::utf8
,
1012 * Retrieve which WM Protocols are supported by the client window.
1013 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
1014 * window's decorations and allow the close behavior.
1015 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
1018 void BlackboxWindow::getWMProtocols(void) {
1022 if (XGetWMProtocols(blackbox
->getXDisplay(), client
.window
,
1023 &proto
, &num_return
)) {
1024 for (int i
= 0; i
< num_return
; ++i
) {
1025 if (proto
[i
] == xatom
->getAtom(XAtom::wm_delete_window
)) {
1026 decorations
|= Decor_Close
;
1027 functions
|= Func_Close
;
1028 } else if (proto
[i
] == xatom
->getAtom(XAtom::wm_take_focus
))
1029 flags
.send_focus_message
= True
;
1030 else if (proto
[i
] == xatom
->getAtom(XAtom::blackbox_structure_messages
))
1031 screen
->addNetizen(new Netizen(screen
, client
.window
));
1040 * Gets the value of the WM_HINTS property.
1041 * If the property is not set, then use a set of default values.
1043 void BlackboxWindow::getWMHints(void) {
1044 focus_mode
= F_Passive
;
1045 client
.initial_state
= NormalState
;
1047 // remove from current window group
1048 if (client
.window_group
) {
1049 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1050 if (group
) group
->removeWindow(this);
1052 client
.window_group
= None
;
1054 XWMHints
*wmhint
= XGetWMHints(blackbox
->getXDisplay(), client
.window
);
1059 if (wmhint
->flags
& InputHint
) {
1060 if (wmhint
->input
== True
) {
1061 if (flags
.send_focus_message
)
1062 focus_mode
= F_LocallyActive
;
1064 if (flags
.send_focus_message
)
1065 focus_mode
= F_GloballyActive
;
1067 focus_mode
= F_NoInput
;
1071 if (wmhint
->flags
& StateHint
)
1072 client
.initial_state
= wmhint
->initial_state
;
1074 if (wmhint
->flags
& WindowGroupHint
) {
1075 client
.window_group
= wmhint
->window_group
;
1077 // add window to the appropriate group
1078 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1079 if (! group
) { // no group found, create it!
1080 new BWindowGroup(blackbox
, client
.window_group
);
1081 group
= blackbox
->searchGroup(client
.window_group
);
1084 group
->addWindow(this);
1087 client
.wm_hint_flags
= wmhint
->flags
;
1093 * Gets the value of the WM_NORMAL_HINTS property.
1094 * If the property is not set, then use a set of default values.
1096 void BlackboxWindow::getWMNormalHints(void) {
1098 XSizeHints sizehint
;
1100 client
.min_width
= client
.min_height
=
1101 client
.width_inc
= client
.height_inc
= 1;
1102 client
.base_width
= client
.base_height
= 0;
1103 client
.win_gravity
= NorthWestGravity
;
1105 client
.min_aspect_x
= client
.min_aspect_y
=
1106 client
.max_aspect_x
= client
.max_aspect_y
= 1;
1110 use the full screen, not the strut modified size. otherwise when the
1111 availableArea changes max_width/height will be incorrect and lead to odd
1114 const Rect
& screen_area
= screen
->getRect();
1115 client
.max_width
= screen_area
.width();
1116 client
.max_height
= screen_area
.height();
1118 if (! XGetWMNormalHints(blackbox
->getXDisplay(), client
.window
,
1119 &sizehint
, &icccm_mask
))
1122 client
.normal_hint_flags
= sizehint
.flags
;
1124 if (sizehint
.flags
& PMinSize
) {
1125 if (sizehint
.min_width
>= 0)
1126 client
.min_width
= sizehint
.min_width
;
1127 if (sizehint
.min_height
>= 0)
1128 client
.min_height
= sizehint
.min_height
;
1131 if (sizehint
.flags
& PMaxSize
) {
1132 if (sizehint
.max_width
> static_cast<signed>(client
.min_width
))
1133 client
.max_width
= sizehint
.max_width
;
1135 client
.max_width
= client
.min_width
;
1137 if (sizehint
.max_height
> static_cast<signed>(client
.min_height
))
1138 client
.max_height
= sizehint
.max_height
;
1140 client
.max_height
= client
.min_height
;
1143 if (sizehint
.flags
& PResizeInc
) {
1144 client
.width_inc
= sizehint
.width_inc
;
1145 client
.height_inc
= sizehint
.height_inc
;
1148 #if 0 // we do not support this at the moment
1149 if (sizehint
.flags
& PAspect
) {
1150 client
.min_aspect_x
= sizehint
.min_aspect
.x
;
1151 client
.min_aspect_y
= sizehint
.min_aspect
.y
;
1152 client
.max_aspect_x
= sizehint
.max_aspect
.x
;
1153 client
.max_aspect_y
= sizehint
.max_aspect
.y
;
1157 if (sizehint
.flags
& PBaseSize
) {
1158 client
.base_width
= sizehint
.base_width
;
1159 client
.base_height
= sizehint
.base_height
;
1162 if (sizehint
.flags
& PWinGravity
)
1163 client
.win_gravity
= sizehint
.win_gravity
;
1168 * Gets the NETWM hints for the class' contained window.
1170 void BlackboxWindow::getNetWMHints(void) {
1171 unsigned long workspace
;
1173 if (xatom
->getValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1175 if (workspace
== 0xffffffff)
1178 blackbox_attrib
.workspace
= workspace
;
1181 unsigned long *state
;
1182 unsigned long num
= (unsigned) -1;
1183 if (xatom
->getValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
1187 for (unsigned long i
= 0; i
< num
; ++i
) {
1188 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
))
1190 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_shaded
))
1191 flags
.shaded
= True
;
1192 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
))
1193 flags
.skip_taskbar
= True
;
1194 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_pager
))
1195 flags
.skip_pager
= True
;
1196 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_fullscreen
))
1197 flags
.fullscreen
= True
;
1198 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_hidden
))
1199 setState(IconicState
);
1200 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_vert
))
1202 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_horz
))
1206 flags
.maximized
= 1;
1208 flags
.maximized
= 2;
1210 flags
.maximized
= 3;
1218 * Gets the MWM hints for the class' contained window.
1219 * This is used while initializing the window to its first state, and not
1221 * Returns: true if the MWM hints are successfully retreived and applied;
1222 * false if they are not.
1224 void BlackboxWindow::getMWMHints(void) {
1228 num
= PropMwmHintsElements
;
1229 if (! xatom
->getValue(client
.window
, XAtom::motif_wm_hints
,
1230 XAtom::motif_wm_hints
, num
,
1231 (unsigned long **)&mwm_hint
))
1233 if (num
< PropMwmHintsElements
) {
1238 if (mwm_hint
->flags
& MwmHintsDecorations
) {
1239 if (mwm_hint
->decorations
& MwmDecorAll
) {
1240 decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
1241 Decor_Iconify
| Decor_Maximize
| Decor_Close
;
1245 if (mwm_hint
->decorations
& MwmDecorBorder
)
1246 decorations
|= Decor_Border
;
1247 if (mwm_hint
->decorations
& MwmDecorHandle
)
1248 decorations
|= Decor_Handle
;
1249 if (mwm_hint
->decorations
& MwmDecorTitle
)
1250 decorations
|= Decor_Titlebar
;
1251 if (mwm_hint
->decorations
& MwmDecorIconify
)
1252 decorations
|= Decor_Iconify
;
1253 if (mwm_hint
->decorations
& MwmDecorMaximize
)
1254 decorations
|= Decor_Maximize
;
1258 if (mwm_hint
->flags
& MwmHintsFunctions
) {
1259 if (mwm_hint
->functions
& MwmFuncAll
) {
1260 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
|
1265 if (mwm_hint
->functions
& MwmFuncResize
)
1266 functions
|= Func_Resize
;
1267 if (mwm_hint
->functions
& MwmFuncMove
)
1268 functions
|= Func_Move
;
1269 if (mwm_hint
->functions
& MwmFuncIconify
)
1270 functions
|= Func_Iconify
;
1271 if (mwm_hint
->functions
& MwmFuncMaximize
)
1272 functions
|= Func_Maximize
;
1273 if (mwm_hint
->functions
& MwmFuncClose
)
1274 functions
|= Func_Close
;
1282 * Gets the blackbox hints from the class' contained window.
1283 * This is used while initializing the window to its first state, and not
1285 * Returns: true if the hints are successfully retreived and applied; false if
1288 bool BlackboxWindow::getBlackboxHints(void) {
1290 BlackboxHints
*blackbox_hint
;
1292 num
= PropBlackboxHintsElements
;
1293 if (! xatom
->getValue(client
.window
, XAtom::blackbox_hints
,
1294 XAtom::blackbox_hints
, num
,
1295 (unsigned long **)&blackbox_hint
))
1297 if (num
< PropBlackboxHintsElements
) {
1298 delete [] blackbox_hint
;
1302 if (blackbox_hint
->flags
& AttribShaded
)
1303 flags
.shaded
= (blackbox_hint
->attrib
& AttribShaded
);
1305 if ((blackbox_hint
->flags
& AttribMaxHoriz
) &&
1306 (blackbox_hint
->flags
& AttribMaxVert
))
1307 flags
.maximized
= (blackbox_hint
->attrib
&
1308 (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1309 else if (blackbox_hint
->flags
& AttribMaxVert
)
1310 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxVert
) ? 2 : 0;
1311 else if (blackbox_hint
->flags
& AttribMaxHoriz
)
1312 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1314 if (blackbox_hint
->flags
& AttribOmnipresent
)
1315 flags
.stuck
= (blackbox_hint
->attrib
& AttribOmnipresent
);
1317 if (blackbox_hint
->flags
& AttribWorkspace
)
1318 blackbox_attrib
.workspace
= blackbox_hint
->workspace
;
1320 // if (blackbox_hint->flags & AttribStack)
1321 // don't yet have always on top/bottom for blackbox yet... working
1324 if (blackbox_hint
->flags
& AttribDecoration
) {
1325 switch (blackbox_hint
->decoration
) {
1327 // clear all decorations except close
1328 decorations
&= Decor_Close
;
1329 // clear all functions except close
1330 functions
&= Func_Close
;
1335 decorations
|= Decor_Titlebar
| Decor_Iconify
;
1336 decorations
&= ~(Decor_Border
| Decor_Handle
| Decor_Maximize
);
1337 functions
|= Func_Move
| Func_Iconify
;
1338 functions
&= ~(Func_Resize
| Func_Maximize
);
1343 decorations
|= Decor_Titlebar
;
1344 decorations
&= ~(Decor_Iconify
| Decor_Border
| Decor_Handle
);
1345 functions
|= Func_Move
;
1346 functions
&= ~(Func_Resize
| Func_Maximize
| Func_Iconify
);
1352 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Handle
|
1353 Decor_Iconify
| Decor_Maximize
;
1354 functions
|= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
1362 delete [] blackbox_hint
;
1368 void BlackboxWindow::getTransientInfo(void) {
1369 if (client
.transient_for
&&
1370 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1371 // the transient for hint was removed, so we need to tell our
1372 // previous transient_for that we are going away
1373 client
.transient_for
->client
.transientList
.remove(this);
1376 // we have no transient_for until we find a new one
1377 client
.transient_for
= 0;
1380 if (! XGetTransientForHint(blackbox
->getXDisplay(), client
.window
,
1382 // transient_for hint not set
1386 if (trans_for
== client
.window
) {
1387 // wierd client... treat this window as a normal window
1391 if (trans_for
== None
|| trans_for
== screen
->getRootWindow()) {
1392 // this is an undocumented interpretation of the ICCCM. a transient
1393 // associated with None/Root/itself is assumed to be a modal root
1394 // transient. we don't support the concept of a global transient,
1395 // so we just associate this transient with nothing, and perhaps
1396 // we will add support later for global modality.
1397 client
.transient_for
= (BlackboxWindow
*) ~0ul;
1402 client
.transient_for
= blackbox
->searchWindow(trans_for
);
1403 if (! client
.transient_for
&&
1404 client
.window_group
&& trans_for
== client
.window_group
) {
1405 // no direct transient_for, perhaps this is a group transient?
1406 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1407 if (group
) client
.transient_for
= group
->find(screen
);
1410 if (! client
.transient_for
|| client
.transient_for
== this) {
1411 // no transient_for found, or we have a wierd client that wants to be
1412 // a transient for itself, so we treat this window as a normal window
1413 client
.transient_for
= (BlackboxWindow
*) 0;
1417 // register ourselves with our new transient_for
1418 client
.transient_for
->client
.transientList
.push_back(this);
1419 flags
.stuck
= client
.transient_for
->flags
.stuck
;
1423 BlackboxWindow
*BlackboxWindow::getTransientFor(void) const {
1424 if (client
.transient_for
&&
1425 client
.transient_for
!= (BlackboxWindow
*) ~0ul)
1426 return client
.transient_for
;
1432 * This function is responsible for updating both the client and the frame
1434 * According to the ICCCM a client message is not sent for a resize, only a
1437 void BlackboxWindow::configure(int dx
, int dy
,
1438 unsigned int dw
, unsigned int dh
) {
1439 bool send_event
= ((frame
.rect
.x() != dx
|| frame
.rect
.y() != dy
) &&
1442 if (dw
!= frame
.rect
.width() || dh
!= frame
.rect
.height()) {
1443 frame
.rect
.setRect(dx
, dy
, dw
, dh
);
1444 frame
.inside_w
= frame
.rect
.width() - (frame
.border_w
* 2);
1445 frame
.inside_h
= frame
.rect
.height() - (frame
.border_w
* 2);
1447 if (frame
.rect
.right() <= 0 || frame
.rect
.bottom() <= 0)
1448 frame
.rect
.setPos(0, 0);
1450 client
.rect
.setCoords(frame
.rect
.left() + frame
.margin
.left
,
1451 frame
.rect
.top() + frame
.margin
.top
,
1452 frame
.rect
.right() - frame
.margin
.right
,
1453 frame
.rect
.bottom() - frame
.margin
.bottom
);
1456 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
1463 redrawWindowFrame();
1465 frame
.rect
.setPos(dx
, dy
);
1467 XMoveWindow(blackbox
->getXDisplay(), frame
.window
,
1468 frame
.rect
.x(), frame
.rect
.y());
1470 we may have been called just after an opaque window move, so even though
1471 the old coords match the new ones no ConfigureNotify has been sent yet.
1472 There are likely other times when this will be relevant as well.
1474 if (! flags
.moving
) send_event
= True
;
1478 // if moving, the update and event will occur when the move finishes
1479 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1480 frame
.rect
.top() + frame
.margin
.top
);
1483 event
.type
= ConfigureNotify
;
1485 event
.xconfigure
.display
= blackbox
->getXDisplay();
1486 event
.xconfigure
.event
= client
.window
;
1487 event
.xconfigure
.window
= client
.window
;
1488 event
.xconfigure
.x
= client
.rect
.x();
1489 event
.xconfigure
.y
= client
.rect
.y();
1490 event
.xconfigure
.width
= client
.rect
.width();
1491 event
.xconfigure
.height
= client
.rect
.height();
1492 event
.xconfigure
.border_width
= client
.old_bw
;
1493 event
.xconfigure
.above
= frame
.window
;
1494 event
.xconfigure
.override_redirect
= False
;
1496 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1497 StructureNotifyMask
, &event
);
1498 screen
->updateNetizenConfigNotify(&event
);
1499 XFlush(blackbox
->getXDisplay());
1505 void BlackboxWindow::configureShape(void) {
1506 XShapeCombineShape(blackbox
->getXDisplay(), frame
.window
, ShapeBounding
,
1507 frame
.margin
.left
- frame
.border_w
,
1508 frame
.margin
.top
- frame
.border_w
,
1509 client
.window
, ShapeBounding
, ShapeSet
);
1512 XRectangle xrect
[2];
1514 if (decorations
& Decor_Titlebar
) {
1515 xrect
[0].x
= xrect
[0].y
= -frame
.border_w
;
1516 xrect
[0].width
= frame
.rect
.width();
1517 xrect
[0].height
= frame
.title_h
+ (frame
.border_w
* 2);
1521 if (decorations
& Decor_Handle
) {
1522 xrect
[1].x
= -frame
.border_w
;
1523 xrect
[1].y
= frame
.rect
.height() - frame
.margin
.bottom
+
1524 frame
.mwm_border_w
- frame
.border_w
;
1525 xrect
[1].width
= frame
.rect
.width();
1526 xrect
[1].height
= frame
.handle_h
+ (frame
.border_w
* 2);
1530 XShapeCombineRectangles(blackbox
->getXDisplay(), frame
.window
,
1531 ShapeBounding
, 0, 0, xrect
, num
,
1532 ShapeUnion
, Unsorted
);
1537 bool BlackboxWindow::setInputFocus(void) {
1538 if (flags
.focused
) return True
;
1540 assert(! flags
.iconic
&&
1541 (flags
.stuck
|| // window must be on the current workspace or sticky
1542 blackbox_attrib
.workspace
== screen
->getCurrentWorkspaceID()));
1544 // if the window is not visible, mark the window as wanting focus rather
1545 // than give it focus.
1546 if (! flags
.visible
) {
1547 Workspace
*wkspc
= screen
->getWorkspace(blackbox_attrib
.workspace
);
1548 wkspc
->setLastFocusedWindow(this);
1553 We only do this check for normal windows and dialogs because other windows
1554 do this on purpose, such as kde's kicker, and we don't want to go moving
1557 if (window_type
== Type_Normal
|| window_type
== Type_Dialog
)
1558 if (! frame
.rect
.intersects(screen
->getRect())) {
1559 // client is outside the screen, move it to the center
1560 configure((screen
->getWidth() - frame
.rect
.width()) / 2,
1561 (screen
->getHeight() - frame
.rect
.height()) / 2,
1562 frame
.rect
.width(), frame
.rect
.height());
1565 if (client
.transientList
.size() > 0) {
1566 // transfer focus to any modal transients
1567 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1568 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1569 if ((*it
)->flags
.modal
) return (*it
)->setInputFocus();
1574 if (focus_mode
== F_LocallyActive
|| focus_mode
== F_Passive
) {
1575 XSetInputFocus(blackbox
->getXDisplay(), client
.window
,
1576 RevertToPointerRoot
, CurrentTime
);
1578 blackbox
->setFocusedWindow(this);
1580 /* we could set the focus to none, since the window doesn't accept focus,
1581 * but we shouldn't set focus to nothing since this would surely make
1587 if (flags
.send_focus_message
) {
1589 ce
.xclient
.type
= ClientMessage
;
1590 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1591 ce
.xclient
.display
= blackbox
->getXDisplay();
1592 ce
.xclient
.window
= client
.window
;
1593 ce
.xclient
.format
= 32;
1594 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_take_focus
);
1595 ce
.xclient
.data
.l
[1] = blackbox
->getLastTime();
1596 ce
.xclient
.data
.l
[2] = 0l;
1597 ce
.xclient
.data
.l
[3] = 0l;
1598 ce
.xclient
.data
.l
[4] = 0l;
1599 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1601 XFlush(blackbox
->getXDisplay());
1608 void BlackboxWindow::iconify(void) {
1609 if (flags
.iconic
) return;
1611 // We don't need to worry about resizing because resizing always grabs the X
1612 // server. This should only ever happen if using opaque moving.
1616 if (windowmenu
) windowmenu
->hide();
1619 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1620 * we need to clear the event mask on client.window for a split second.
1621 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1622 * split second, leaving us with a ghost window... so, we need to do this
1623 * while the X server is grabbed
1625 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1626 StructureNotifyMask
;
1627 XGrabServer(blackbox
->getXDisplay());
1628 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1629 event_mask
& ~StructureNotifyMask
);
1630 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1631 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1632 XUngrabServer(blackbox
->getXDisplay());
1634 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1635 flags
.visible
= False
;
1636 flags
.iconic
= True
;
1638 setState(IconicState
);
1640 screen
->getWorkspace(blackbox_attrib
.workspace
)->removeWindow(this);
1642 if (isTransient()) {
1643 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1644 ! client
.transient_for
->flags
.iconic
) {
1645 // iconify our transient_for
1646 client
.transient_for
->iconify();
1650 screen
->addIcon(this);
1652 if (client
.transientList
.size() > 0) {
1653 // iconify all transients
1654 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1655 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1656 if (! (*it
)->flags
.iconic
) (*it
)->iconify();
1659 screen
->updateStackingList();
1663 void BlackboxWindow::show(void) {
1664 flags
.visible
= True
;
1665 flags
.iconic
= False
;
1667 current_state
= (flags
.shaded
) ? IconicState
: NormalState
;
1668 setState(current_state
);
1670 XMapWindow(blackbox
->getXDisplay(), client
.window
);
1671 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
1672 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
1677 XTranslateCoordinates(blackbox
->getXDisplay(), client
.window
,
1678 screen
->getRootWindow(),
1679 0, 0, &real_x
, &real_y
, &child
);
1680 fprintf(stderr
, "%s -- assumed: (%d, %d), real: (%d, %d)\n", getTitle(),
1681 client
.rect
.left(), client
.rect
.top(), real_x
, real_y
);
1682 assert(client
.rect
.left() == real_x
&& client
.rect
.top() == real_y
);
1687 void BlackboxWindow::deiconify(bool reassoc
, bool raise
) {
1688 if (flags
.iconic
|| reassoc
)
1689 screen
->reassociateWindow(this, BSENTINEL
, False
);
1690 else if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID())
1695 // reassociate and deiconify all transients
1696 if (reassoc
&& client
.transientList
.size() > 0) {
1697 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1698 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1699 (*it
)->deiconify(True
, False
);
1704 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1708 void BlackboxWindow::close(void) {
1710 ce
.xclient
.type
= ClientMessage
;
1711 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1712 ce
.xclient
.display
= blackbox
->getXDisplay();
1713 ce
.xclient
.window
= client
.window
;
1714 ce
.xclient
.format
= 32;
1715 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_delete_window
);
1716 ce
.xclient
.data
.l
[1] = CurrentTime
;
1717 ce
.xclient
.data
.l
[2] = 0l;
1718 ce
.xclient
.data
.l
[3] = 0l;
1719 ce
.xclient
.data
.l
[4] = 0l;
1720 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
, NoEventMask
, &ce
);
1721 XFlush(blackbox
->getXDisplay());
1725 void BlackboxWindow::withdraw(void) {
1726 // We don't need to worry about resizing because resizing always grabs the X
1727 // server. This should only ever happen if using opaque moving.
1731 flags
.visible
= False
;
1732 flags
.iconic
= False
;
1734 setState(current_state
);
1736 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1738 XGrabServer(blackbox
->getXDisplay());
1740 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1741 StructureNotifyMask
;
1742 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1743 event_mask
& ~StructureNotifyMask
);
1744 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1745 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1747 XUngrabServer(blackbox
->getXDisplay());
1749 if (windowmenu
) windowmenu
->hide();
1753 void BlackboxWindow::maximize(unsigned int button
) {
1754 // We don't need to worry about resizing because resizing always grabs the X
1755 // server. This should only ever happen if using opaque moving.
1759 // handle case where menu is open then the max button is used instead
1760 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
1762 if (flags
.maximized
) {
1763 flags
.maximized
= 0;
1765 blackbox_attrib
.flags
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1766 blackbox_attrib
.attrib
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1769 when a resize finishes, maximize(0) is called to clear any maximization
1770 flags currently set. Otherwise it still thinks it is maximized.
1771 so we do not need to call configure() because resizing will handle it
1773 if (! flags
.resizing
)
1774 configure(blackbox_attrib
.premax_x
, blackbox_attrib
.premax_y
,
1775 blackbox_attrib
.premax_w
, blackbox_attrib
.premax_h
);
1777 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
1778 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
1780 redrawAllButtons(); // in case it is not called in configure()
1781 setState(current_state
);
1785 blackbox_attrib
.premax_x
= frame
.rect
.x();
1786 blackbox_attrib
.premax_y
= frame
.rect
.y();
1787 blackbox_attrib
.premax_w
= frame
.rect
.width();
1788 // use client.rect so that clients can be restored even if shaded
1789 blackbox_attrib
.premax_h
=
1790 client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
;
1792 const Rect
&screen_area
= screen
->availableArea();
1793 frame
.changing
= screen_area
;
1797 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1798 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1802 blackbox_attrib
.flags
|= AttribMaxVert
;
1803 blackbox_attrib
.attrib
|= AttribMaxVert
;
1805 frame
.changing
.setX(frame
.rect
.x());
1806 frame
.changing
.setWidth(frame
.rect
.width());
1810 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1811 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1813 frame
.changing
.setY(frame
.rect
.y());
1814 frame
.changing
.setHeight(frame
.rect
.height());
1821 blackbox_attrib
.flags
^= AttribShaded
;
1822 blackbox_attrib
.attrib
^= AttribShaded
;
1823 flags
.shaded
= False
;
1826 flags
.maximized
= button
;
1828 configure(frame
.changing
.x(), frame
.changing
.y(),
1829 frame
.changing
.width(), frame
.changing
.height());
1831 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1832 redrawAllButtons(); // in case it is not called in configure()
1833 setState(current_state
);
1837 // re-maximizes the window to take into account availableArea changes
1838 void BlackboxWindow::remaximize(void) {
1839 // save the original dimensions because maximize will wipe them out
1840 int premax_x
= blackbox_attrib
.premax_x
,
1841 premax_y
= blackbox_attrib
.premax_y
,
1842 premax_w
= blackbox_attrib
.premax_w
,
1843 premax_h
= blackbox_attrib
.premax_h
;
1845 unsigned int button
= flags
.maximized
;
1846 flags
.maximized
= 0; // trick maximize() into working
1849 // restore saved values
1850 blackbox_attrib
.premax_x
= premax_x
;
1851 blackbox_attrib
.premax_y
= premax_y
;
1852 blackbox_attrib
.premax_w
= premax_w
;
1853 blackbox_attrib
.premax_h
= premax_h
;
1857 void BlackboxWindow::setWorkspace(unsigned int n
) {
1858 blackbox_attrib
.flags
|= AttribWorkspace
;
1859 blackbox_attrib
.workspace
= n
;
1860 if (n
== BSENTINEL
) { // iconified window
1862 we set the workspace to 'all workspaces' so that taskbars will show the
1863 window. otherwise, it made uniconifying a window imposible without the
1864 blackbox workspace menu
1868 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
, n
);
1872 void BlackboxWindow::shade(void) {
1874 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1875 frame
.inside_w
, frame
.inside_h
);
1876 flags
.shaded
= False
;
1877 blackbox_attrib
.flags
^= AttribShaded
;
1878 blackbox_attrib
.attrib
^= AttribShaded
;
1880 setState(NormalState
);
1882 // set the frame rect to the normal size
1883 frame
.rect
.setHeight(client
.rect
.height() + frame
.margin
.top
+
1884 frame
.margin
.bottom
);
1886 if (! (decorations
& Decor_Titlebar
))
1887 return; // can't shade it without a titlebar!
1889 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1890 frame
.inside_w
, frame
.title_h
);
1891 flags
.shaded
= True
;
1892 blackbox_attrib
.flags
|= AttribShaded
;
1893 blackbox_attrib
.attrib
|= AttribShaded
;
1895 setState(IconicState
);
1897 // set the frame rect to the shaded size
1898 frame
.rect
.setHeight(frame
.title_h
+ (frame
.border_w
* 2));
1904 * (Un)Sticks a window and its relatives.
1906 void BlackboxWindow::stick(void) {
1908 blackbox_attrib
.flags
^= AttribOmnipresent
;
1909 blackbox_attrib
.attrib
^= AttribOmnipresent
;
1911 flags
.stuck
= False
;
1914 screen
->reassociateWindow(this, BSENTINEL
, True
);
1915 // temporary fix since sticky windows suck. set the hint to what we
1916 // actually hold in our data.
1917 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1918 blackbox_attrib
.workspace
);
1920 setState(current_state
);
1924 blackbox_attrib
.flags
|= AttribOmnipresent
;
1925 blackbox_attrib
.attrib
|= AttribOmnipresent
;
1927 // temporary fix since sticky windows suck. set the hint to a different
1928 // value than that contained in the class' data.
1929 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1932 setState(current_state
);
1935 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1936 client
.transient_for
->isStuck() != flags
.stuck
)
1937 client
.transient_for
->stick();
1938 // go down the chain
1939 BlackboxWindowList::iterator it
;
1940 const BlackboxWindowList::iterator end
= client
.transientList
.end();
1941 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1942 if ((*it
)->isStuck() != flags
.stuck
)
1947 void BlackboxWindow::redrawWindowFrame(void) const {
1948 if (decorations
& Decor_Titlebar
) {
1949 if (flags
.focused
) {
1951 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1952 frame
.title
, frame
.ftitle
);
1954 XSetWindowBackground(blackbox
->getXDisplay(),
1955 frame
.title
, frame
.ftitle_pixel
);
1958 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1959 frame
.title
, frame
.utitle
);
1961 XSetWindowBackground(blackbox
->getXDisplay(),
1962 frame
.title
, frame
.utitle_pixel
);
1964 XClearWindow(blackbox
->getXDisplay(), frame
.title
);
1970 if (decorations
& Decor_Handle
) {
1971 if (flags
.focused
) {
1973 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1974 frame
.handle
, frame
.fhandle
);
1976 XSetWindowBackground(blackbox
->getXDisplay(),
1977 frame
.handle
, frame
.fhandle_pixel
);
1980 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1981 frame
.left_grip
, frame
.fgrip
);
1982 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1983 frame
.right_grip
, frame
.fgrip
);
1985 XSetWindowBackground(blackbox
->getXDisplay(),
1986 frame
.left_grip
, frame
.fgrip_pixel
);
1987 XSetWindowBackground(blackbox
->getXDisplay(),
1988 frame
.right_grip
, frame
.fgrip_pixel
);
1992 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1993 frame
.handle
, frame
.uhandle
);
1995 XSetWindowBackground(blackbox
->getXDisplay(),
1996 frame
.handle
, frame
.uhandle_pixel
);
1999 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2000 frame
.left_grip
, frame
.ugrip
);
2001 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2002 frame
.right_grip
, frame
.ugrip
);
2004 XSetWindowBackground(blackbox
->getXDisplay(),
2005 frame
.left_grip
, frame
.ugrip_pixel
);
2006 XSetWindowBackground(blackbox
->getXDisplay(),
2007 frame
.right_grip
, frame
.ugrip_pixel
);
2010 XClearWindow(blackbox
->getXDisplay(), frame
.handle
);
2011 XClearWindow(blackbox
->getXDisplay(), frame
.left_grip
);
2012 XClearWindow(blackbox
->getXDisplay(), frame
.right_grip
);
2015 if (decorations
& Decor_Border
) {
2017 XSetWindowBorder(blackbox
->getXDisplay(),
2018 frame
.plate
, frame
.fborder_pixel
);
2020 XSetWindowBorder(blackbox
->getXDisplay(),
2021 frame
.plate
, frame
.uborder_pixel
);
2026 void BlackboxWindow::setFocusFlag(bool focus
) {
2027 // only focus a window if it is visible
2028 if (focus
&& !flags
.visible
)
2031 flags
.focused
= focus
;
2033 redrawWindowFrame();
2035 if (screen
->isSloppyFocus() && screen
->doAutoRaise()) {
2036 if (isFocused()) timer
->start();
2041 blackbox
->setFocusedWindow(this);
2045 void BlackboxWindow::installColormap(bool install
) {
2046 int i
= 0, ncmap
= 0;
2047 Colormap
*cmaps
= XListInstalledColormaps(blackbox
->getXDisplay(),
2048 client
.window
, &ncmap
);
2050 XWindowAttributes wattrib
;
2051 if (XGetWindowAttributes(blackbox
->getXDisplay(),
2052 client
.window
, &wattrib
)) {
2054 // install the window's colormap
2055 for (i
= 0; i
< ncmap
; i
++) {
2056 if (*(cmaps
+ i
) == wattrib
.colormap
)
2057 // this window is using an installed color map... do not install
2060 // otherwise, install the window's colormap
2062 XInstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2064 // uninstall the window's colormap
2065 for (i
= 0; i
< ncmap
; i
++) {
2066 if (*(cmaps
+ i
) == wattrib
.colormap
)
2067 // we found the colormap to uninstall
2068 XUninstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2078 void BlackboxWindow::setAllowedActions(void) {
2082 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_shade
);
2083 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_change_desktop
);
2084 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_close
);
2086 if (functions
& Func_Move
)
2087 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_move
);
2088 if (functions
& Func_Resize
)
2089 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_resize
);
2090 if (functions
& Func_Maximize
) {
2091 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_horz
);
2092 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_vert
);
2095 xatom
->setValue(client
.window
, XAtom::net_wm_allowed_actions
, XAtom::atom
,
2100 void BlackboxWindow::setState(unsigned long new_state
) {
2101 current_state
= new_state
;
2103 unsigned long state
[2];
2104 state
[0] = current_state
;
2106 xatom
->setValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
, state
, 2);
2108 xatom
->setValue(client
.window
, XAtom::blackbox_attributes
,
2109 XAtom::blackbox_attributes
, (unsigned long *)&blackbox_attrib
,
2110 PropBlackboxAttributesElements
);
2115 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_modal
);
2117 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_shaded
);
2119 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_hidden
);
2120 if (flags
.skip_taskbar
)
2121 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
);
2122 if (flags
.skip_pager
)
2123 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_pager
);
2124 if (flags
.fullscreen
)
2125 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_fullscreen
);
2126 if (flags
.maximized
== 1 || flags
.maximized
== 2)
2127 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_vert
);
2128 if (flags
.maximized
== 1 || flags
.maximized
== 3)
2129 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_horz
);
2130 xatom
->setValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
2135 bool BlackboxWindow::getState(void) {
2136 bool ret
= xatom
->getValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
,
2138 if (! ret
) current_state
= 0;
2143 void BlackboxWindow::restoreAttributes(void) {
2144 unsigned long num
= PropBlackboxAttributesElements
;
2145 BlackboxAttributes
*net
;
2146 if (! xatom
->getValue(client
.window
, XAtom::blackbox_attributes
,
2147 XAtom::blackbox_attributes
, num
,
2148 (unsigned long **)&net
))
2150 if (num
< PropBlackboxAttributesElements
) {
2155 if (net
->flags
& AttribShaded
&& net
->attrib
& AttribShaded
) {
2156 flags
.shaded
= False
;
2157 unsigned long orig_state
= current_state
;
2161 At this point in the life of a window, current_state should only be set
2162 to IconicState if the window was an *icon*, not if it was shaded.
2164 if (orig_state
!= IconicState
)
2165 current_state
= WithdrawnState
;
2168 if (net
->workspace
!= screen
->getCurrentWorkspaceID() &&
2169 net
->workspace
< screen
->getWorkspaceCount())
2170 screen
->reassociateWindow(this, net
->workspace
, True
);
2172 if ((blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID()) &&
2173 (blackbox_attrib
.workspace
< screen
->getWorkspaceCount())) {
2174 // set to WithdrawnState so it will be mapped on the new workspace
2175 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2176 } else if (current_state
== WithdrawnState
) {
2177 // the window is on this workspace and is Withdrawn, so it is waiting to
2179 current_state
= NormalState
;
2182 if (net
->flags
& AttribOmnipresent
&& net
->attrib
& AttribOmnipresent
) {
2183 flags
.stuck
= False
;
2186 // if the window was on another workspace, it was going to be hidden. this
2187 // specifies that the window should be mapped since it is sticky.
2188 if (current_state
== WithdrawnState
) current_state
= NormalState
;
2191 if (net
->flags
& AttribMaxHoriz
|| net
->flags
& AttribMaxVert
) {
2192 int x
= net
->premax_x
, y
= net
->premax_y
;
2193 unsigned int w
= net
->premax_w
, h
= net
->premax_h
;
2194 flags
.maximized
= 0;
2197 if ((net
->flags
& AttribMaxHoriz
) &&
2198 (net
->flags
& AttribMaxVert
))
2199 m
= (net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
2200 else if (net
->flags
& AttribMaxVert
)
2201 m
= (net
->attrib
& AttribMaxVert
) ? 2 : 0;
2202 else if (net
->flags
& AttribMaxHoriz
)
2203 m
= (net
->attrib
& AttribMaxHoriz
) ? 3 : 0;
2207 blackbox_attrib
.premax_x
= x
;
2208 blackbox_attrib
.premax_y
= y
;
2209 blackbox_attrib
.premax_w
= w
;
2210 blackbox_attrib
.premax_h
= h
;
2213 // with the state set it will then be the map event's job to read the
2214 // window's state and behave accordingly
2221 * Positions the Rect r according the the client window position and
2224 void BlackboxWindow::applyGravity(Rect
&r
) {
2225 // apply horizontal window gravity
2226 switch (client
.win_gravity
) {
2228 case NorthWestGravity
:
2229 case SouthWestGravity
:
2231 r
.setX(client
.rect
.x());
2237 r
.setX(client
.rect
.x() - (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2240 case NorthEastGravity
:
2241 case SouthEastGravity
:
2243 r
.setX(client
.rect
.x() - frame
.margin
.left
- frame
.margin
.right
+ 2);
2248 r
.setX(client
.rect
.x() - frame
.margin
.left
);
2252 // apply vertical window gravity
2253 switch (client
.win_gravity
) {
2255 case NorthWestGravity
:
2256 case NorthEastGravity
:
2258 r
.setY(client
.rect
.y());
2264 r
.setY(client
.rect
.y() - (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2267 case SouthWestGravity
:
2268 case SouthEastGravity
:
2270 r
.setY(client
.rect
.y() - frame
.margin
.top
- frame
.margin
.bottom
+ 2);
2275 r
.setY(client
.rect
.y() - frame
.margin
.top
);
2282 * The reverse of the applyGravity function.
2284 * Positions the Rect r according to the frame window position and
2287 void BlackboxWindow::restoreGravity(Rect
&r
) {
2288 // restore horizontal window gravity
2289 switch (client
.win_gravity
) {
2291 case NorthWestGravity
:
2292 case SouthWestGravity
:
2294 r
.setX(frame
.rect
.x());
2300 r
.setX(frame
.rect
.x() + (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2303 case NorthEastGravity
:
2304 case SouthEastGravity
:
2306 r
.setX(frame
.rect
.x() + frame
.margin
.left
+ frame
.margin
.right
- 2);
2311 r
.setX(frame
.rect
.x() + frame
.margin
.left
);
2315 // restore vertical window gravity
2316 switch (client
.win_gravity
) {
2318 case NorthWestGravity
:
2319 case NorthEastGravity
:
2321 r
.setY(frame
.rect
.y());
2327 r
.setY(frame
.rect
.y() + (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2330 case SouthWestGravity
:
2331 case SouthEastGravity
:
2333 r
.setY(frame
.rect
.y() + frame
.margin
.top
+ frame
.margin
.bottom
- 2);
2338 r
.setY(frame
.rect
.y() + frame
.margin
.top
);
2344 void BlackboxWindow::redrawLabel(void) const {
2345 if (flags
.focused
) {
2347 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2348 frame
.label
, frame
.flabel
);
2350 XSetWindowBackground(blackbox
->getXDisplay(),
2351 frame
.label
, frame
.flabel_pixel
);
2354 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2355 frame
.label
, frame
.ulabel
);
2357 XSetWindowBackground(blackbox
->getXDisplay(),
2358 frame
.label
, frame
.ulabel_pixel
);
2360 XClearWindow(blackbox
->getXDisplay(), frame
.label
);
2362 WindowStyle
*style
= screen
->getWindowStyle();
2364 int pos
= frame
.bevel_w
* 2;
2365 style
->doJustify(client
.title
.c_str(), pos
, frame
.label_w
, frame
.bevel_w
* 4);
2366 style
->font
->drawString(frame
.label
, pos
, 1,
2367 (flags
.focused
? style
->l_text_focus
:
2368 style
->l_text_unfocus
),
2373 void BlackboxWindow::redrawAllButtons(void) const {
2374 if (frame
.iconify_button
) redrawIconifyButton(False
);
2375 if (frame
.maximize_button
) redrawMaximizeButton(flags
.maximized
);
2376 if (frame
.close_button
) redrawCloseButton(False
);
2380 void BlackboxWindow::redrawIconifyButton(bool pressed
) const {
2382 if (flags
.focused
) {
2384 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2385 frame
.iconify_button
, frame
.fbutton
);
2387 XSetWindowBackground(blackbox
->getXDisplay(),
2388 frame
.iconify_button
, frame
.fbutton_pixel
);
2391 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2392 frame
.iconify_button
, frame
.ubutton
);
2394 XSetWindowBackground(blackbox
->getXDisplay(), frame
.iconify_button
,
2395 frame
.ubutton_pixel
);
2399 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2400 frame
.iconify_button
, frame
.pbutton
);
2402 XSetWindowBackground(blackbox
->getXDisplay(),
2403 frame
.iconify_button
, frame
.pbutton_pixel
);
2405 XClearWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
2407 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2408 screen
->getWindowStyle()->b_pic_unfocus
);
2409 XDrawRectangle(blackbox
->getXDisplay(), frame
.iconify_button
, pen
.gc(),
2410 2, (frame
.button_w
- 5), (frame
.button_w
- 5), 2);
2414 void BlackboxWindow::redrawMaximizeButton(bool pressed
) const {
2416 if (flags
.focused
) {
2418 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2419 frame
.maximize_button
, frame
.fbutton
);
2421 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2422 frame
.fbutton_pixel
);
2425 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2426 frame
.maximize_button
, frame
.ubutton
);
2428 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2429 frame
.ubutton_pixel
);
2433 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2434 frame
.maximize_button
, frame
.pbutton
);
2436 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2437 frame
.pbutton_pixel
);
2439 XClearWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
2441 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2442 screen
->getWindowStyle()->b_pic_unfocus
);
2443 XDrawRectangle(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2444 2, 2, (frame
.button_w
- 5), (frame
.button_w
- 5));
2445 XDrawLine(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2446 2, 3, (frame
.button_w
- 3), 3);
2450 void BlackboxWindow::redrawCloseButton(bool pressed
) const {
2452 if (flags
.focused
) {
2454 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2457 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2458 frame
.fbutton_pixel
);
2461 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2464 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2465 frame
.ubutton_pixel
);
2469 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2470 frame
.close_button
, frame
.pbutton
);
2472 XSetWindowBackground(blackbox
->getXDisplay(),
2473 frame
.close_button
, frame
.pbutton_pixel
);
2475 XClearWindow(blackbox
->getXDisplay(), frame
.close_button
);
2477 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2478 screen
->getWindowStyle()->b_pic_unfocus
);
2479 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2480 2, 2, (frame
.button_w
- 3), (frame
.button_w
- 3));
2481 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2482 2, (frame
.button_w
- 3), (frame
.button_w
- 3), 2);
2486 void BlackboxWindow::mapRequestEvent(const XMapRequestEvent
*re
) {
2487 if (re
->window
!= client
.window
)
2491 fprintf(stderr
, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2495 switch (current_state
) {
2500 case WithdrawnState
:
2509 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2511 if (! blackbox
->isStartup()) {
2512 XSync(blackbox
->getXDisplay(), False
); // make sure the frame is mapped
2513 if (isTransient() || screen
->doFocusNew()) {
2516 if (screen
->getPlacementPolicy() == BScreen::ClickMousePlacement
) {
2520 XQueryPointer(blackbox
->getXDisplay(), screen
->getRootWindow(),
2521 &r
, &c
, &rx
, &ry
, &x
, &y
, &m
);
2531 void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent
*ue
) {
2532 if (ue
->window
!= client
.window
)
2536 fprintf(stderr
, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2540 screen
->unmanageWindow(this, False
);
2544 void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent
*de
) {
2545 if (de
->window
!= client
.window
)
2549 fprintf(stderr
, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2553 screen
->unmanageWindow(this, False
);
2557 void BlackboxWindow::reparentNotifyEvent(const XReparentEvent
*re
) {
2558 if (re
->window
!= client
.window
|| re
->parent
== frame
.plate
)
2562 fprintf(stderr
, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2563 "0x%lx.\n", client
.window
, re
->parent
);
2568 XPutBackEvent(blackbox
->getXDisplay(), &ev
);
2569 screen
->unmanageWindow(this, True
);
2573 void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent
*pe
) {
2574 if (pe
->state
== PropertyDelete
)
2578 fprintf(stderr
, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n",
2584 case XA_WM_CLIENT_MACHINE
:
2588 case XA_WM_TRANSIENT_FOR
: {
2589 // determine if this is a transient window
2592 // adjust the window decorations based on transience
2593 if (isTransient()) {
2594 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2595 functions
&= ~Func_Maximize
;
2596 setAllowedActions();
2607 case XA_WM_ICON_NAME
:
2609 if (flags
.iconic
) screen
->propagateWindowName(this);
2612 case XAtom::net_wm_name
:
2616 if (decorations
& Decor_Titlebar
)
2619 screen
->propagateWindowName(this);
2622 case XA_WM_NORMAL_HINTS
: {
2625 if ((client
.normal_hint_flags
& PMinSize
) &&
2626 (client
.normal_hint_flags
& PMaxSize
)) {
2627 // the window now can/can't resize itself, so the buttons need to be
2630 if (client
.max_width
<= client
.min_width
&&
2631 client
.max_height
<= client
.min_height
) {
2632 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2633 functions
&= ~(Func_Resize
| Func_Maximize
);
2635 if (! isTransient()) {
2636 decorations
|= Decor_Maximize
| Decor_Handle
;
2637 functions
|= Func_Maximize
;
2639 functions
|= Func_Resize
;
2642 setAllowedActions();
2645 Rect old_rect
= frame
.rect
;
2649 if (old_rect
!= frame
.rect
)
2656 if (pe
->atom
== xatom
->getAtom(XAtom::wm_protocols
)) {
2659 if ((decorations
& Decor_Close
) && (! frame
.close_button
)) {
2660 createCloseButton();
2661 if (decorations
& Decor_Titlebar
) {
2662 positionButtons(True
);
2663 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
2665 if (windowmenu
) windowmenu
->reconfigure();
2667 } else if (pe
->atom
== xatom
->getAtom(XAtom::net_wm_strut
)) {
2676 void BlackboxWindow::exposeEvent(const XExposeEvent
*ee
) {
2678 fprintf(stderr
, "BlackboxWindow::exposeEvent() for 0x%lx\n", client
.window
);
2681 if (frame
.label
== ee
->window
&& (decorations
& Decor_Titlebar
))
2683 else if (frame
.close_button
== ee
->window
)
2684 redrawCloseButton(False
);
2685 else if (frame
.maximize_button
== ee
->window
)
2686 redrawMaximizeButton(flags
.maximized
);
2687 else if (frame
.iconify_button
== ee
->window
)
2688 redrawIconifyButton(False
);
2692 void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent
*cr
) {
2693 if (cr
->window
!= client
.window
|| flags
.iconic
)
2696 if (cr
->value_mask
& CWBorderWidth
)
2697 client
.old_bw
= cr
->border_width
;
2699 if (cr
->value_mask
& (CWX
| CWY
| CWWidth
| CWHeight
)) {
2700 Rect req
= frame
.rect
;
2702 if (cr
->value_mask
& (CWX
| CWY
)) {
2703 if (cr
->value_mask
& CWX
)
2704 client
.rect
.setX(cr
->x
);
2705 if (cr
->value_mask
& CWY
)
2706 client
.rect
.setY(cr
->y
);
2711 if (cr
->value_mask
& CWWidth
)
2712 req
.setWidth(cr
->width
+ frame
.margin
.left
+ frame
.margin
.right
);
2714 if (cr
->value_mask
& CWHeight
)
2715 req
.setHeight(cr
->height
+ frame
.margin
.top
+ frame
.margin
.bottom
);
2717 configure(req
.x(), req
.y(), req
.width(), req
.height());
2720 if (cr
->value_mask
& CWStackMode
&& !isDesktop()) {
2721 switch (cr
->detail
) {
2724 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2730 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2737 void BlackboxWindow::buttonPressEvent(const XButtonEvent
*be
) {
2739 fprintf(stderr
, "BlackboxWindow::buttonPressEvent() for 0x%lx\n",
2743 if (frame
.maximize_button
== be
->window
&& be
->button
<= 3) {
2744 redrawMaximizeButton(True
);
2745 } else if (be
->button
== 1 || (be
->button
== 3 && be
->state
== Mod1Mask
)) {
2746 if (! flags
.focused
)
2749 if (frame
.iconify_button
== be
->window
) {
2750 redrawIconifyButton(True
);
2751 } else if (frame
.close_button
== be
->window
) {
2752 redrawCloseButton(True
);
2753 } else if (frame
.plate
== be
->window
) {
2754 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2756 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2758 XAllowEvents(blackbox
->getXDisplay(), ReplayPointer
, be
->time
);
2760 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
2761 if (((be
->time
- lastButtonPressTime
) <=
2762 blackbox
->getDoubleClickInterval()) ||
2763 (be
->state
== ControlMask
)) {
2764 lastButtonPressTime
= 0;
2767 lastButtonPressTime
= be
->time
;
2771 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2773 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2775 } else if (be
->button
== 2 && (be
->window
!= frame
.iconify_button
) &&
2776 (be
->window
!= frame
.close_button
)) {
2777 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2778 } else if (windowmenu
&& be
->button
== 3 &&
2779 (frame
.title
== be
->window
|| frame
.label
== be
->window
||
2780 frame
.handle
== be
->window
|| frame
.window
== be
->window
)) {
2781 if (windowmenu
->isVisible()) {
2784 int mx
= be
->x_root
- windowmenu
->getWidth() / 2,
2785 my
= be
->y_root
- windowmenu
->getHeight() / 2;
2787 // snap the window menu into a corner/side if necessary
2788 int left_edge
, right_edge
, top_edge
, bottom_edge
;
2791 the " + (frame.border_w * 2) - 1" bits are to get the proper width
2792 and height of the menu, as the sizes returned by it do not include
2795 left_edge
= frame
.rect
.x();
2796 right_edge
= frame
.rect
.right() -
2797 (windowmenu
->getWidth() + (frame
.border_w
* 2) - 1);
2798 top_edge
= client
.rect
.top() - (frame
.border_w
+ frame
.mwm_border_w
);
2799 bottom_edge
= client
.rect
.bottom() -
2800 (windowmenu
->getHeight() + (frame
.border_w
* 2) - 1) +
2801 (frame
.border_w
+ frame
.mwm_border_w
);
2805 if (mx
> right_edge
)
2809 if (my
> bottom_edge
)
2812 windowmenu
->move(mx
, my
);
2814 XRaiseWindow(blackbox
->getXDisplay(), windowmenu
->getWindowID());
2815 XRaiseWindow(blackbox
->getXDisplay(),
2816 windowmenu
->getSendToMenu()->getWindowID());
2819 } else if (be
->button
== 4) {
2820 if ((be
->window
== frame
.label
||
2821 be
->window
== frame
.title
||
2822 be
->window
== frame
.maximize_button
||
2823 be
->window
== frame
.iconify_button
||
2824 be
->window
== frame
.close_button
) &&
2828 } else if (be
->button
== 5) {
2829 if ((be
->window
== frame
.label
||
2830 be
->window
== frame
.title
||
2831 be
->window
== frame
.maximize_button
||
2832 be
->window
== frame
.iconify_button
||
2833 be
->window
== frame
.close_button
) &&
2840 void BlackboxWindow::buttonReleaseEvent(const XButtonEvent
*re
) {
2842 fprintf(stderr
, "BlackboxWindow::buttonReleaseEvent() for 0x%lx\n",
2846 if (re
->window
== frame
.maximize_button
&&
2847 re
->button
>= 1 && re
->button
<= 3) {
2848 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2849 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2850 maximize(re
->button
);
2852 redrawMaximizeButton(flags
.maximized
);
2854 } else if (re
->window
== frame
.iconify_button
&& re
->button
== 1) {
2855 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2856 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2859 redrawIconifyButton(False
);
2861 } else if (re
->window
== frame
.close_button
& re
->button
== 1) {
2862 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2863 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
)))
2865 redrawCloseButton(False
);
2866 } else if (flags
.moving
) {
2868 } else if (flags
.resizing
) {
2870 } else if (re
->window
== frame
.window
) {
2871 if (re
->button
== 2 && re
->state
== Mod1Mask
)
2872 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
2878 void BlackboxWindow::beginMove(int x_root
, int y_root
) {
2879 assert(! (flags
.resizing
|| flags
.moving
));
2882 Only one window can be moved/resized at a time. If another window is already
2883 being moved or resized, then stop it before whating to work with this one.
2885 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
2886 if (changing
&& changing
!= this) {
2887 if (changing
->flags
.moving
)
2888 changing
->endMove();
2889 else // if (changing->flags.resizing)
2890 changing
->endResize();
2893 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
2894 PointerMotionMask
| ButtonReleaseMask
,
2895 GrabModeAsync
, GrabModeAsync
,
2896 None
, blackbox
->getMoveCursor(), CurrentTime
);
2898 if (windowmenu
&& windowmenu
->isVisible())
2901 flags
.moving
= True
;
2902 blackbox
->setChangingWindow(this);
2904 if (! screen
->doOpaqueMove()) {
2905 XGrabServer(blackbox
->getXDisplay());
2907 frame
.changing
= frame
.rect
;
2908 screen
->showPosition(frame
.changing
.x(), frame
.changing
.y());
2910 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2914 frame
.changing
.width() - 1,
2915 frame
.changing
.height() - 1);
2918 frame
.grab_x
= x_root
- frame
.rect
.x() - frame
.border_w
;
2919 frame
.grab_y
= y_root
- frame
.rect
.y() - frame
.border_w
;
2923 void BlackboxWindow::doMove(int x_root
, int y_root
) {
2924 assert(flags
.moving
);
2925 assert(blackbox
->getChangingWindow() == this);
2927 int dx
= x_root
- frame
.grab_x
, dy
= y_root
- frame
.grab_y
;
2928 dx
-= frame
.border_w
;
2929 dy
-= frame
.border_w
;
2931 const int snap_distance
= screen
->getEdgeSnapThreshold();
2933 if (snap_distance
) {
2935 const int wleft
= dx
,
2936 wright
= dx
+ frame
.rect
.width() - 1,
2938 wbottom
= dy
+ frame
.rect
.height() - 1;
2940 if (screen
->getWindowToWindowSnap()) {
2941 Workspace
*w
= screen
->getWorkspace(getWorkspaceNumber());
2944 // try snap to another window
2945 for (unsigned int i
= 0, c
= w
->getCount(); i
< c
; ++i
) {
2946 BlackboxWindow
*snapwin
= w
->getWindow(i
);
2947 if (snapwin
== this)
2948 continue; // don't snap to self
2950 bool snapped
= False
;
2952 const Rect
&winrect
= snapwin
->frameRect();
2953 int dleft
= std::abs(wright
- winrect
.left()),
2954 dright
= std::abs(wleft
- winrect
.right()),
2955 dtop
= std::abs(wbottom
- winrect
.top()),
2956 dbottom
= std::abs(wtop
- winrect
.bottom());
2958 if (wtop
>= (signed)(winrect
.y() - frame
.rect
.height() + 1) &&
2959 wtop
< (signed)(winrect
.y() + winrect
.height() - 1)) {
2961 // snap left of other window?
2962 if (dleft
< snap_distance
&& dleft
<= dright
) {
2963 dx
= winrect
.left() - frame
.rect
.width();
2966 // snap right of other window?
2967 else if (dright
< snap_distance
) {
2968 dx
= winrect
.right() + 1;
2973 if (screen
->getWindowCornerSnap()) {
2974 // try corner-snap to its other sides
2975 dtop
= std::abs(wtop
- winrect
.top());
2976 dbottom
= std::abs(wbottom
- winrect
.bottom());
2977 if (dtop
< snap_distance
&& dtop
<= dbottom
)
2979 else if (dbottom
< snap_distance
)
2980 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
2987 if (wleft
>= (signed)(winrect
.x() - frame
.rect
.width() + 1) &&
2988 wleft
< (signed)(winrect
.x() + winrect
.width() - 1)) {
2990 // snap top of other window?
2991 if (dtop
< snap_distance
&& dtop
<= dbottom
) {
2992 dy
= winrect
.top() - frame
.rect
.height();
2995 // snap bottom of other window?
2996 else if (dbottom
< snap_distance
) {
2997 dy
= winrect
.bottom() + 1;
3002 if (screen
->getWindowCornerSnap()) {
3003 // try corner-snap to its other sides
3004 dleft
= std::abs(wleft
- winrect
.left());
3005 dright
= std::abs(wright
- winrect
.right());
3006 if (dleft
< snap_distance
&& dleft
<= dright
)
3007 dx
= winrect
.left();
3008 else if (dright
< snap_distance
)
3009 dx
= winrect
.right() - frame
.rect
.width() + 1;
3018 // try snap to the screen's available area
3019 Rect srect
= screen
->availableArea();
3021 int dleft
= std::abs(wleft
- srect
.left()),
3022 dright
= std::abs(wright
- srect
.right()),
3023 dtop
= std::abs(wtop
- srect
.top()),
3024 dbottom
= std::abs(wbottom
- srect
.bottom());
3027 if (dleft
< snap_distance
&& dleft
<= dright
)
3030 else if (dright
< snap_distance
)
3031 dx
= srect
.right() - frame
.rect
.width() + 1;
3034 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3037 else if (dbottom
< snap_distance
)
3038 dy
= srect
.bottom() - frame
.rect
.height() + 1;
3040 srect
= screen
->getRect(); // now get the full screen
3042 dleft
= std::abs(wleft
- srect
.left()),
3043 dright
= std::abs(wright
- srect
.right()),
3044 dtop
= std::abs(wtop
- srect
.top()),
3045 dbottom
= std::abs(wbottom
- srect
.bottom());
3048 if (dleft
< snap_distance
&& dleft
<= dright
)
3051 else if (dright
< snap_distance
)
3052 dx
= srect
.right() - frame
.rect
.width() + 1;
3055 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3058 else if (dbottom
< snap_distance
)
3059 dy
= srect
.bottom() - frame
.rect
.height() + 1;
3062 if (screen
->doOpaqueMove()) {
3063 configure(dx
, dy
, frame
.rect
.width(), frame
.rect
.height());
3065 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3069 frame
.changing
.width() - 1,
3070 frame
.changing
.height() - 1);
3072 frame
.changing
.setPos(dx
, dy
);
3074 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3078 frame
.changing
.width() - 1,
3079 frame
.changing
.height() - 1);
3082 screen
->showPosition(dx
, dy
);
3086 void BlackboxWindow::endMove(void) {
3087 assert(flags
.moving
);
3088 assert(blackbox
->getChangingWindow() == this);
3090 flags
.moving
= False
;
3091 blackbox
->setChangingWindow(0);
3093 if (! screen
->doOpaqueMove()) {
3094 /* when drawing the rubber band, we need to make sure we only draw inside
3095 * the frame... frame.changing_* contain the new coords for the window,
3096 * so we need to subtract 1 from changing_w/changing_h every where we
3097 * draw the rubber band (for both moving and resizing)
3099 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3100 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3101 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3102 XUngrabServer(blackbox
->getXDisplay());
3104 configure(frame
.changing
.x(), frame
.changing
.y(),
3105 frame
.changing
.width(), frame
.changing
.height());
3107 configure(frame
.rect
.x(), frame
.rect
.y(),
3108 frame
.rect
.width(), frame
.rect
.height());
3110 screen
->hideGeometry();
3112 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3114 // if there are any left over motions from the move, drop them now
3115 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3117 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3122 void BlackboxWindow::beginResize(int x_root
, int y_root
, Corner dir
) {
3123 assert(! (flags
.resizing
|| flags
.moving
));
3126 Only one window can be moved/resized at a time. If another window is already
3127 being moved or resized, then stop it before whating to work with this one.
3129 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3130 if (changing
&& changing
!= this) {
3131 if (changing
->flags
.moving
)
3132 changing
->endMove();
3133 else // if (changing->flags.resizing)
3134 changing
->endResize();
3142 switch (resize_dir
) {
3145 cursor
= blackbox
->getLowerLeftAngleCursor();
3150 cursor
= blackbox
->getLowerRightAngleCursor();
3154 anchor
= BottomRight
;
3155 cursor
= blackbox
->getUpperLeftAngleCursor();
3159 anchor
= BottomLeft
;
3160 cursor
= blackbox
->getUpperRightAngleCursor();
3164 assert(false); // unhandled Corner
3165 return; // unreachable, for the compiler
3168 XGrabServer(blackbox
->getXDisplay());
3169 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3170 PointerMotionMask
| ButtonReleaseMask
,
3171 GrabModeAsync
, GrabModeAsync
, None
, cursor
, CurrentTime
);
3173 flags
.resizing
= True
;
3174 blackbox
->setChangingWindow(this);
3177 frame
.changing
= frame
.rect
;
3179 constrain(anchor
, &gw
, &gh
);
3181 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3182 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3183 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3185 screen
->showGeometry(gw
, gh
);
3187 frame
.grab_x
= x_root
;
3188 frame
.grab_y
= y_root
;
3192 void BlackboxWindow::doResize(int x_root
, int y_root
) {
3193 assert(flags
.resizing
);
3194 assert(blackbox
->getChangingWindow() == this);
3196 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3197 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3198 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3203 switch (resize_dir
) {
3206 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3207 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3211 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3212 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3215 anchor
= BottomRight
;
3216 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3217 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3220 anchor
= BottomLeft
;
3221 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3222 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3226 assert(false); // unhandled Corner
3227 return; // unreachable, for the compiler
3230 constrain(anchor
, &gw
, &gh
);
3232 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3233 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3234 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3236 screen
->showGeometry(gw
, gh
);
3240 void BlackboxWindow::endResize(void) {
3241 assert(flags
.resizing
);
3242 assert(blackbox
->getChangingWindow() == this);
3244 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3245 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3246 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3247 XUngrabServer(blackbox
->getXDisplay());
3249 // unset maximized state after resized when fully maximized
3250 if (flags
.maximized
== 1)
3253 flags
.resizing
= False
;
3254 blackbox
->setChangingWindow(0);
3256 configure(frame
.changing
.x(), frame
.changing
.y(),
3257 frame
.changing
.width(), frame
.changing
.height());
3258 screen
->hideGeometry();
3260 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3262 // if there are any left over motions from the resize, drop them now
3263 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3265 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3270 void BlackboxWindow::motionNotifyEvent(const XMotionEvent
*me
) {
3272 fprintf(stderr
, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n",
3277 doMove(me
->x_root
, me
->y_root
);
3278 } else if (flags
.resizing
) {
3279 doResize(me
->x_root
, me
->y_root
);
3281 if (!flags
.resizing
&& me
->state
& Button1Mask
&& (functions
& Func_Move
) &&
3282 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3283 frame
.handle
== me
->window
|| frame
.window
== me
->window
)) {
3284 beginMove(me
->x_root
, me
->y_root
);
3285 } else if ((functions
& Func_Resize
) &&
3286 (me
->state
& Button1Mask
&& (me
->window
== frame
.right_grip
||
3287 me
->window
== frame
.left_grip
)) ||
3288 (me
->state
& Button3Mask
&& me
->state
& Mod1Mask
&&
3289 me
->window
== frame
.window
)) {
3290 unsigned int zones
= screen
->getResizeZones();
3293 if (me
->window
== frame
.left_grip
) {
3294 corner
= BottomLeft
;
3295 } else if (me
->window
== frame
.right_grip
|| zones
== 1) {
3296 corner
= BottomRight
;
3299 bool left
= (me
->x_root
- frame
.rect
.x() <=
3300 static_cast<signed>(frame
.rect
.width() / 2));
3303 else // (zones == 4)
3304 top
= (me
->y_root
- frame
.rect
.y() <=
3305 static_cast<signed>(frame
.rect
.height() / 2));
3306 corner
= (top
? (left
? TopLeft
: TopRight
) :
3307 (left
? BottomLeft
: BottomRight
));
3310 beginResize(me
->x_root
, me
->y_root
, corner
);
3317 void BlackboxWindow::shapeEvent(XShapeEvent
*) {
3318 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
3325 bool BlackboxWindow::validateClient(void) const {
3326 XSync(blackbox
->getXDisplay(), False
);
3329 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3330 DestroyNotify
, &e
) ||
3331 XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3333 XPutBackEvent(blackbox
->getXDisplay(), &e
);
3342 void BlackboxWindow::restore(bool remap
) {
3343 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeDelete
);
3344 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
3345 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, NoEventMask
);
3347 // do not leave a shaded window as an icon unless it was an icon
3348 if (flags
.shaded
&& ! flags
.iconic
) setState(NormalState
);
3350 restoreGravity(client
.rect
);
3352 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
3353 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
3355 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, client
.old_bw
);
3358 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3359 ReparentNotify
, &ev
)) {
3362 // according to the ICCCM - if the client doesn't reparent to
3363 // root, then we have to do it for them
3364 XReparentWindow(blackbox
->getXDisplay(), client
.window
,
3365 screen
->getRootWindow(),
3366 client
.rect
.x(), client
.rect
.y());
3369 if (remap
) XMapWindow(blackbox
->getXDisplay(), client
.window
);
3373 // timer for autoraise
3374 void BlackboxWindow::timeout(void) {
3375 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3379 void BlackboxWindow::changeBlackboxHints(BlackboxHints
*net
) {
3380 if ((net
->flags
& AttribShaded
) &&
3381 ((blackbox_attrib
.attrib
& AttribShaded
) !=
3382 (net
->attrib
& AttribShaded
)))
3385 if (flags
.visible
&& // watch out for requests when we can not be seen
3386 (net
->flags
& (AttribMaxVert
| AttribMaxHoriz
)) &&
3387 ((blackbox_attrib
.attrib
& (AttribMaxVert
| AttribMaxHoriz
)) !=
3388 (net
->attrib
& (AttribMaxVert
| AttribMaxHoriz
)))) {
3389 if (flags
.maximized
) {
3394 if ((net
->flags
& AttribMaxHoriz
) && (net
->flags
& AttribMaxVert
))
3395 button
= ((net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0);
3396 else if (net
->flags
& AttribMaxVert
)
3397 button
= ((net
->attrib
& AttribMaxVert
) ? 2 : 0);
3398 else if (net
->flags
& AttribMaxHoriz
)
3399 button
= ((net
->attrib
& AttribMaxHoriz
) ? 3 : 0);
3405 if ((net
->flags
& AttribOmnipresent
) &&
3406 ((blackbox_attrib
.attrib
& AttribOmnipresent
) !=
3407 (net
->attrib
& AttribOmnipresent
)))
3410 if ((net
->flags
& AttribWorkspace
) &&
3411 (blackbox_attrib
.workspace
!= net
->workspace
)) {
3412 screen
->reassociateWindow(this, net
->workspace
, True
);
3414 if (screen
->getCurrentWorkspaceID() != net
->workspace
) {
3418 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3422 if (net
->flags
& AttribDecoration
) {
3423 switch (net
->decoration
) {
3425 // clear all decorations except close
3426 decorations
&= Decor_Close
;
3432 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Iconify
;
3434 decorations
= ((functions
& Func_Resize
) && !isTransient() ?
3435 decorations
| Decor_Handle
:
3436 decorations
&= ~Decor_Handle
);
3437 decorations
= (functions
& Func_Maximize
?
3438 decorations
| Decor_Maximize
:
3439 decorations
&= ~Decor_Maximize
);
3444 decorations
|= Decor_Titlebar
| Decor_Iconify
;
3445 decorations
&= ~(Decor_Border
| Decor_Handle
);
3447 decorations
= (functions
& Func_Maximize
?
3448 decorations
| Decor_Maximize
:
3449 decorations
&= ~Decor_Maximize
);
3454 decorations
|= Decor_Titlebar
;
3455 decorations
&= ~(Decor_Iconify
| Decor_Border
);
3457 decorations
= ((functions
& Func_Resize
) && !isTransient() ?
3458 decorations
| Decor_Handle
:
3459 decorations
&= ~Decor_Handle
);
3460 decorations
= (functions
& Func_Maximize
?
3461 decorations
| Decor_Maximize
:
3462 decorations
&= ~Decor_Maximize
);
3467 // we can not be shaded if we lack a titlebar
3468 if (flags
.shaded
&& ! (decorations
& Decor_Titlebar
))
3471 if (flags
.visible
&& frame
.window
) {
3472 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
3473 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
3477 setState(current_state
);
3483 * Set the sizes of all components of the window frame
3484 * (the window decorations).
3485 * These values are based upon the current style settings and the client
3486 * window's dimensions.
3488 void BlackboxWindow::upsize(void) {
3489 frame
.bevel_w
= screen
->getBevelWidth();
3491 if (decorations
& Decor_Border
) {
3492 frame
.border_w
= screen
->getBorderWidth();
3493 if (! isTransient())
3494 frame
.mwm_border_w
= screen
->getFrameWidth();
3496 frame
.mwm_border_w
= 0;
3498 frame
.mwm_border_w
= frame
.border_w
= 0;
3501 if (decorations
& Decor_Titlebar
) {
3502 // the height of the titlebar is based upon the height of the font being
3503 // used to display the window's title
3504 WindowStyle
*style
= screen
->getWindowStyle();
3505 frame
.title_h
= style
->font
->height() + (frame
.bevel_w
* 2) + 2;
3507 frame
.label_h
= frame
.title_h
- (frame
.bevel_w
* 2);
3508 frame
.button_w
= (frame
.label_h
- 2);
3510 // set the top frame margin
3511 frame
.margin
.top
= frame
.border_w
+ frame
.title_h
+
3512 frame
.border_w
+ frame
.mwm_border_w
;
3518 // set the top frame margin
3519 frame
.margin
.top
= frame
.border_w
+ frame
.mwm_border_w
;
3522 // set the left/right frame margin
3523 frame
.margin
.left
= frame
.margin
.right
= frame
.border_w
+ frame
.mwm_border_w
;
3525 if (decorations
& Decor_Handle
) {
3526 frame
.grip_w
= frame
.button_w
* 2;
3527 frame
.handle_h
= screen
->getHandleWidth();
3529 // set the bottom frame margin
3530 frame
.margin
.bottom
= frame
.border_w
+ frame
.handle_h
+
3531 frame
.border_w
+ frame
.mwm_border_w
;
3536 // set the bottom frame margin
3537 frame
.margin
.bottom
= frame
.border_w
+ frame
.mwm_border_w
;
3541 We first get the normal dimensions and use this to define the inside_w/h
3542 then we modify the height if shading is in effect.
3543 If the shade state is not considered then frame.rect gets reset to the
3544 normal window size on a reconfigure() call resulting in improper
3545 dimensions appearing in move/resize and other events.
3548 height
= client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
,
3549 width
= client
.rect
.width() + frame
.margin
.left
+ frame
.margin
.right
;
3551 frame
.inside_w
= width
- (frame
.border_w
* 2);
3552 frame
.inside_h
= height
- (frame
.border_w
* 2);
3555 height
= frame
.title_h
+ (frame
.border_w
* 2);
3556 frame
.rect
.setSize(width
, height
);
3561 * Calculate the size of the client window and constrain it to the
3562 * size specified by the size hints of the client window.
3564 * The logical width and height are placed into pw and ph, if they
3565 * are non-zero. Logical size refers to the users perception of
3566 * the window size (for example an xterm resizes in cells, not in pixels).
3568 * The physical geometry is placed into frame.changing_{x,y,width,height}.
3569 * Physical geometry refers to the geometry of the window in pixels.
3571 void BlackboxWindow::constrain(Corner anchor
, int *pw
, int *ph
) {
3572 // frame.changing represents the requested frame size, we need to
3573 // strip the frame margin off and constrain the client size
3574 frame
.changing
.setCoords(frame
.changing
.left() + frame
.margin
.left
,
3575 frame
.changing
.top() + frame
.margin
.top
,
3576 frame
.changing
.right() - frame
.margin
.right
,
3577 frame
.changing
.bottom() - frame
.margin
.bottom
);
3579 int dw
= frame
.changing
.width(), dh
= frame
.changing
.height(),
3580 base_width
= (client
.base_width
) ? client
.base_width
: client
.min_width
,
3581 base_height
= (client
.base_height
) ? client
.base_height
:
3585 if (dw
< static_cast<signed>(client
.min_width
)) dw
= client
.min_width
;
3586 if (dh
< static_cast<signed>(client
.min_height
)) dh
= client
.min_height
;
3587 if (dw
> static_cast<signed>(client
.max_width
)) dw
= client
.max_width
;
3588 if (dh
> static_cast<signed>(client
.max_height
)) dh
= client
.max_height
;
3591 dw
/= client
.width_inc
;
3593 dh
/= client
.height_inc
;
3596 if (client
.width_inc
== 1)
3597 *pw
= dw
+ base_width
;
3602 if (client
.height_inc
== 1)
3603 *ph
= dh
+ base_height
;
3608 dw
*= client
.width_inc
;
3610 dh
*= client
.height_inc
;
3613 frame
.changing
.setSize(dw
, dh
);
3615 // add the frame margin back onto frame.changing
3616 frame
.changing
.setCoords(frame
.changing
.left() - frame
.margin
.left
,
3617 frame
.changing
.top() - frame
.margin
.top
,
3618 frame
.changing
.right() + frame
.margin
.right
,
3619 frame
.changing
.bottom() + frame
.margin
.bottom
);
3621 // move frame.changing to the specified anchor
3629 dx
= frame
.rect
.right() - frame
.changing
.right();
3633 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3637 dx
= frame
.rect
.right() - frame
.changing
.right();
3638 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3642 assert(false); // unhandled corner
3644 frame
.changing
.setPos(frame
.changing
.x() + dx
, frame
.changing
.y() + dy
);
3648 void WindowStyle::doJustify(const std::string
&text
, int &start_pos
,
3649 unsigned int max_length
,
3650 unsigned int modifier
) const {
3651 size_t text_len
= text
.size();
3652 unsigned int length
;
3655 length
= font
->measureString(string(text
, 0, text_len
)) + modifier
;
3656 } while (length
> max_length
&& text_len
-- > 0);
3660 start_pos
+= max_length
- length
;
3664 start_pos
+= (max_length
- length
) / 2;
3674 BWindowGroup::BWindowGroup(Blackbox
*b
, Window _group
)
3675 : blackbox(b
), group(_group
) {
3676 XWindowAttributes wattrib
;
3677 if (! XGetWindowAttributes(blackbox
->getXDisplay(), group
, &wattrib
)) {
3678 // group window doesn't seem to exist anymore
3683 XSelectInput(blackbox
->getXDisplay(), group
,
3684 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
3686 blackbox
->saveGroupSearch(group
, this);
3690 BWindowGroup::~BWindowGroup(void) {
3691 blackbox
->removeGroupSearch(group
);
3696 BWindowGroup::find(BScreen
*screen
, bool allow_transients
) const {
3697 BlackboxWindow
*ret
= blackbox
->getFocusedWindow();
3699 // does the focus window match (or any transient_fors)?
3701 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3702 if (ret
->isTransient() && allow_transients
) break;
3703 else if (! ret
->isTransient()) break;
3706 ret
= ret
->getTransientFor();
3709 if (ret
) return ret
;
3711 // the focus window didn't match, look in the group's window list
3712 BlackboxWindowList::const_iterator it
, end
= windowList
.end();
3713 for (it
= windowList
.begin(); it
!= end
; ++it
) {
3715 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3716 if (ret
->isTransient() && allow_transients
) break;
3717 else if (! ret
->isTransient()) break;