1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2 // Window.cc for Blackbox - an X11 Window manager
3 // Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry <shaleh at debian.org>
4 // Copyright (c) 1997 - 2000, 2002 Brad Hughes <bhughes at trolltech.com>
6 // Permission is hereby granted, free of charge, to any person obtaining a
7 // copy of this software and associated documentation files (the "Software"),
8 // to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 // and/or sell copies of the Software, and to permit persons to whom the
11 // Software is furnished to do so, subject to the following conditions:
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 // DEALINGS IN THE SOFTWARE.
25 # include "../config.h"
26 #endif // HAVE_CONFIG_H
29 #include <X11/Xatom.h>
30 #include <X11/keysym.h>
34 #endif // HAVE_STRING_H
39 # endif // HAVE_STDIO_H
46 #include "blackbox.hh"
47 #include "Clientmenu.hh"
50 #include "Iconmenu.hh"
56 #include "Windowmenu.hh"
57 #include "Workspace.hh"
62 // change this to change what modifier keys openbox uses for mouse bindings
63 // for example: Mod1Mask | ControlMask
64 // or: ControlMask| ShiftMask
65 const unsigned int ModMask
= Mod1Mask
;
68 * Initializes the class with default values/the window's set initial values.
70 BlackboxWindow::BlackboxWindow(Blackbox
*b
, Window w
, BScreen
*s
) {
71 // fprintf(stderr, "BlackboxWindow size: %d bytes\n",
72 // sizeof(BlackboxWindow));
75 fprintf(stderr
, "BlackboxWindow::BlackboxWindow(): creating 0x%lx\n", w
);
79 set timer to zero... it is initialized properly later, so we check
80 if timer is zero in the destructor, and assume that the window is not
81 fully constructed if timer is zero...
87 xatom
= blackbox
->getXAtom();
89 if (! validateClient()) {
94 // set the eventmask early in the game so that we make sure we get
95 // all the events we are interested in
96 XSetWindowAttributes attrib_set
;
97 attrib_set
.event_mask
= PropertyChangeMask
| FocusChangeMask
|
99 attrib_set
.do_not_propagate_mask
= ButtonPressMask
| ButtonReleaseMask
|
101 XChangeWindowAttributes(blackbox
->getXDisplay(), client
.window
,
102 CWEventMask
|CWDontPropagate
, &attrib_set
);
104 // fetch client size and placement
105 XWindowAttributes wattrib
;
106 if ((! XGetWindowAttributes(blackbox
->getXDisplay(),
107 client
.window
, &wattrib
)) ||
108 (! wattrib
.screen
) || wattrib
.override_redirect
) {
111 "BlackboxWindow::BlackboxWindow(): XGetWindowAttributes failed\n");
118 flags
.moving
= flags
.resizing
= flags
.shaded
= flags
.visible
=
119 flags
.iconic
= flags
.focused
= flags
.stuck
= flags
.modal
=
120 flags
.send_focus_message
= flags
.shaped
= flags
.skip_taskbar
=
121 flags
.skip_pager
= flags
.fullscreen
= False
;
124 blackbox_attrib
.workspace
= window_number
= BSENTINEL
;
126 blackbox_attrib
.flags
= blackbox_attrib
.attrib
= blackbox_attrib
.stack
127 = blackbox_attrib
.decoration
= 0l;
128 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
129 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
132 frame
.window
= frame
.plate
= frame
.title
= frame
.handle
= None
;
133 frame
.close_button
= frame
.iconify_button
= frame
.maximize_button
= None
;
134 frame
.right_grip
= frame
.left_grip
= None
;
136 frame
.ulabel_pixel
= frame
.flabel_pixel
= frame
.utitle_pixel
=
137 frame
.ftitle_pixel
= frame
.uhandle_pixel
= frame
.fhandle_pixel
=
138 frame
.ubutton_pixel
= frame
.fbutton_pixel
= frame
.pbutton_pixel
=
139 frame
.uborder_pixel
= frame
.fborder_pixel
= frame
.ugrip_pixel
=
140 frame
.fgrip_pixel
= 0;
141 frame
.utitle
= frame
.ftitle
= frame
.uhandle
= frame
.fhandle
= None
;
142 frame
.ulabel
= frame
.flabel
= frame
.ubutton
= frame
.fbutton
= None
;
143 frame
.pbutton
= frame
.ugrip
= frame
.fgrip
= None
;
145 decorations
= Decor_Titlebar
| Decor_Border
| Decor_Handle
|
146 Decor_Iconify
| Decor_Maximize
;
147 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
149 client
.wm_hint_flags
= client
.normal_hint_flags
= 0;
150 client
.window_group
= None
;
151 client
.transient_for
= 0;
154 get the initial size and location of client window (relative to the
155 _root window_). This position is the reference point used with the
156 window's gravity to find the window's initial position.
158 client
.rect
.setRect(wattrib
.x
, wattrib
.y
, wattrib
.width
, wattrib
.height
);
159 client
.old_bw
= wattrib
.border_width
;
162 lastButtonPressTime
= 0;
164 timer
= new BTimer(blackbox
, this);
165 timer
->setTimeout(blackbox
->getAutoRaiseDelay());
167 if (! getBlackboxHints()) {
172 // get size, aspect, minimum/maximum size and other hints set by the
178 if (client
.initial_state
== WithdrawnState
) {
179 screen
->getSlit()->addClient(client
.window
);
184 frame
.window
= createToplevelWindow();
185 frame
.plate
= createChildWindow(frame
.window
);
186 associateClientWindow();
188 blackbox
->saveWindowSearch(frame
.window
, this);
189 blackbox
->saveWindowSearch(frame
.plate
, this);
190 blackbox
->saveWindowSearch(client
.window
, this);
192 // determine if this is a transient window
195 // determine the window's type, so we can decide its decorations and
196 // functionality, or if we should not manage it at all
199 // adjust the window decorations/behavior based on the window type
200 switch (window_type
) {
207 // none of these windows are decorated or manipulated by the window manager
210 blackbox_attrib
.workspace
= 0; // we do need to belong to a workspace
211 flags
.stuck
= True
; // we show up on all workspaces
215 // dialogs cannot be maximized, and don't display a handle
216 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
217 functions
&= ~Func_Maximize
;
221 // normal windows retain all of the possible decorations and functionality
225 // further adjeust the window's decorations/behavior based on window sizes
226 if ((client
.normal_hint_flags
& PMinSize
) &&
227 (client
.normal_hint_flags
& PMaxSize
) &&
228 client
.max_width
<= client
.min_width
&&
229 client
.max_height
<= client
.min_height
) {
230 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
231 functions
&= ~(Func_Resize
| Func_Maximize
);
237 bool place_window
= True
;
238 if (blackbox
->isStartup() || isTransient() ||
239 client
.normal_hint_flags
& (PPosition
|USPosition
)) {
240 applyGravity(frame
.rect
);
242 if (blackbox
->isStartup() || client
.rect
.intersects(screen
->getRect()))
243 place_window
= False
;
246 // add the window's strut. note this is done *after* placing the window.
247 screen
->addStrut(&client
.strut
);
250 if (decorations
& Decor_Titlebar
)
253 if (decorations
& Decor_Handle
)
257 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
262 windowmenu
= new Windowmenu(this);
264 if (blackbox_attrib
.workspace
>= screen
->getWorkspaceCount())
265 screen
->getCurrentWorkspace()->addWindow(this, place_window
);
267 screen
->getWorkspace(blackbox_attrib
.workspace
)->
268 addWindow(this, place_window
);
270 if (! place_window
) {
271 // don't need to call configure if we are letting the workspace
273 configure(frame
.rect
.x(), frame
.rect
.y(),
274 frame
.rect
.width(), frame
.rect
.height());
277 // preserve the window's initial state on first map, and its current state
280 if (client
.wm_hint_flags
& StateHint
)
281 current_state
= client
.initial_state
;
283 current_state
= NormalState
;
286 // get sticky state from our parent window if we've got one
287 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
288 client
.transient_for
->isStuck() != flags
.stuck
)
292 flags
.shaded
= False
;
293 unsigned long orig_state
= current_state
;
297 At this point in the life of a window, current_state should only be set
298 to IconicState if the window was an *icon*, not if it was shaded.
300 if (orig_state
!= IconicState
)
301 current_state
= NormalState
;
309 if (flags
.maximized
&& (functions
& Func_Maximize
)) {
314 When the window is mapped (and also when its attributes are restored), the
315 current_state that was set here will be used.
316 It is set to Normal if the window is to be mapped or it is set to Iconic
317 if the window is to be iconified.
318 *Note* that for sticky windows, the same rules apply here, they are in
319 fact never set to Iconic since there is no way for us to tell if a sticky
320 window was iconified previously.
327 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
333 BlackboxWindow::~BlackboxWindow(void) {
335 fprintf(stderr
, "BlackboxWindow::~BlackboxWindow: destroying 0x%lx\n",
339 if (! timer
) // window not managed...
342 screen
->removeStrut(&client
.strut
);
343 screen
->updateAvailableArea();
345 // We don't need to worry about resizing because resizing always grabs the X
346 // server. This should only ever happen if using opaque moving.
354 if (client
.window_group
) {
355 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
356 if (group
) group
->removeWindow(this);
359 // remove ourselves from our transient_for
361 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
362 client
.transient_for
->client
.transientList
.remove(this);
364 client
.transient_for
= (BlackboxWindow
*) 0;
367 if (client
.transientList
.size() > 0) {
368 // reset transient_for for all transients
369 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
370 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
371 (*it
)->client
.transient_for
= (BlackboxWindow
*) 0;
382 blackbox
->removeWindowSearch(frame
.plate
);
383 XDestroyWindow(blackbox
->getXDisplay(), frame
.plate
);
387 blackbox
->removeWindowSearch(frame
.window
);
388 XDestroyWindow(blackbox
->getXDisplay(), frame
.window
);
391 blackbox
->removeWindowSearch(client
.window
);
396 * Creates a new top level window, with a given location, size, and border
398 * Returns: the newly created window
400 Window
BlackboxWindow::createToplevelWindow(void) {
401 XSetWindowAttributes attrib_create
;
402 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
| CWColormap
|
403 CWOverrideRedirect
| CWEventMask
;
405 attrib_create
.background_pixmap
= None
;
406 attrib_create
.colormap
= screen
->getColormap();
407 attrib_create
.override_redirect
= True
;
408 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
409 ButtonMotionMask
| EnterWindowMask
;
411 return XCreateWindow(blackbox
->getXDisplay(), screen
->getRootWindow(),
412 0, 0, 1, 1, frame
.border_w
, screen
->getDepth(),
413 InputOutput
, screen
->getVisual(), create_mask
,
419 * Creates a child window, and optionally associates a given cursor with
422 Window
BlackboxWindow::createChildWindow(Window parent
, Cursor cursor
) {
423 XSetWindowAttributes attrib_create
;
424 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
|
427 attrib_create
.background_pixmap
= None
;
428 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
429 ButtonMotionMask
| ExposureMask
;
432 create_mask
|= CWCursor
;
433 attrib_create
.cursor
= cursor
;
436 return XCreateWindow(blackbox
->getXDisplay(), parent
, 0, 0, 1, 1, 0,
437 screen
->getDepth(), InputOutput
, screen
->getVisual(),
438 create_mask
, &attrib_create
);
442 void BlackboxWindow::associateClientWindow(void) {
443 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, 0);
447 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeInsert
);
449 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, SubstructureRedirectMask
);
451 XGrabServer(blackbox
->getXDisplay());
453 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
455 XSelectInput(blackbox
->getXDisplay(), client
.window
,
456 event_mask
& ~StructureNotifyMask
);
457 XReparentWindow(blackbox
->getXDisplay(), client
.window
, frame
.plate
, 0, 0);
458 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
460 XUngrabServer(blackbox
->getXDisplay());
462 XRaiseWindow(blackbox
->getXDisplay(), frame
.plate
);
463 XMapSubwindows(blackbox
->getXDisplay(), frame
.plate
);
467 if (blackbox
->hasShapeExtensions()) {
468 XShapeSelectInput(blackbox
->getXDisplay(), client
.window
,
475 XShapeQueryExtents(blackbox
->getXDisplay(), client
.window
, &shaped
,
476 &foo
, &foo
, &ufoo
, &ufoo
, &foo
, &foo
, &foo
,
478 flags
.shaped
= shaped
;
484 void BlackboxWindow::decorate(void) {
487 texture
= &(screen
->getWindowStyle()->b_focus
);
488 frame
.fbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
491 frame
.fbutton_pixel
= texture
->color().pixel();
493 texture
= &(screen
->getWindowStyle()->b_unfocus
);
494 frame
.ubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
497 frame
.ubutton_pixel
= texture
->color().pixel();
499 texture
= &(screen
->getWindowStyle()->b_pressed
);
500 frame
.pbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
503 frame
.pbutton_pixel
= texture
->color().pixel();
505 if (decorations
& Decor_Titlebar
) {
506 texture
= &(screen
->getWindowStyle()->t_focus
);
507 frame
.ftitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
510 frame
.ftitle_pixel
= texture
->color().pixel();
512 texture
= &(screen
->getWindowStyle()->t_unfocus
);
513 frame
.utitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
516 frame
.utitle_pixel
= texture
->color().pixel();
518 XSetWindowBorder(blackbox
->getXDisplay(), frame
.title
,
519 screen
->getBorderColor()->pixel());
524 if (decorations
& Decor_Border
) {
525 frame
.fborder_pixel
= screen
->getWindowStyle()->f_focus
.pixel();
526 frame
.uborder_pixel
= screen
->getWindowStyle()->f_unfocus
.pixel();
527 blackbox_attrib
.flags
|= AttribDecoration
;
528 blackbox_attrib
.decoration
= DecorNormal
;
530 blackbox_attrib
.flags
|= AttribDecoration
;
531 blackbox_attrib
.decoration
= DecorNone
;
534 if (decorations
& Decor_Handle
) {
535 texture
= &(screen
->getWindowStyle()->h_focus
);
536 frame
.fhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
539 frame
.fhandle_pixel
= texture
->color().pixel();
541 texture
= &(screen
->getWindowStyle()->h_unfocus
);
542 frame
.uhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
545 frame
.uhandle_pixel
= texture
->color().pixel();
547 texture
= &(screen
->getWindowStyle()->g_focus
);
548 frame
.fgrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.fgrip
);
550 frame
.fgrip_pixel
= texture
->color().pixel();
552 texture
= &(screen
->getWindowStyle()->g_unfocus
);
553 frame
.ugrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.ugrip
);
555 frame
.ugrip_pixel
= texture
->color().pixel();
557 XSetWindowBorder(blackbox
->getXDisplay(), frame
.handle
,
558 screen
->getBorderColor()->pixel());
559 XSetWindowBorder(blackbox
->getXDisplay(), frame
.left_grip
,
560 screen
->getBorderColor()->pixel());
561 XSetWindowBorder(blackbox
->getXDisplay(), frame
.right_grip
,
562 screen
->getBorderColor()->pixel());
565 XSetWindowBorder(blackbox
->getXDisplay(), frame
.window
,
566 screen
->getBorderColor()->pixel());
570 void BlackboxWindow::decorateLabel(void) {
573 texture
= &(screen
->getWindowStyle()->l_focus
);
574 frame
.flabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.flabel
);
576 frame
.flabel_pixel
= texture
->color().pixel();
578 texture
= &(screen
->getWindowStyle()->l_unfocus
);
579 frame
.ulabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.ulabel
);
581 frame
.ulabel_pixel
= texture
->color().pixel();
585 void BlackboxWindow::createHandle(void) {
586 frame
.handle
= createChildWindow(frame
.window
);
587 blackbox
->saveWindowSearch(frame
.handle
, this);
590 createChildWindow(frame
.handle
, blackbox
->getLowerLeftAngleCursor());
591 blackbox
->saveWindowSearch(frame
.left_grip
, this);
594 createChildWindow(frame
.handle
, blackbox
->getLowerRightAngleCursor());
595 blackbox
->saveWindowSearch(frame
.right_grip
, this);
599 void BlackboxWindow::destroyHandle(void) {
601 screen
->getImageControl()->removeImage(frame
.fhandle
);
604 screen
->getImageControl()->removeImage(frame
.uhandle
);
607 screen
->getImageControl()->removeImage(frame
.fgrip
);
610 screen
->getImageControl()->removeImage(frame
.ugrip
);
612 blackbox
->removeWindowSearch(frame
.left_grip
);
613 blackbox
->removeWindowSearch(frame
.right_grip
);
615 XDestroyWindow(blackbox
->getXDisplay(), frame
.left_grip
);
616 XDestroyWindow(blackbox
->getXDisplay(), frame
.right_grip
);
617 frame
.left_grip
= frame
.right_grip
= None
;
619 blackbox
->removeWindowSearch(frame
.handle
);
620 XDestroyWindow(blackbox
->getXDisplay(), frame
.handle
);
625 void BlackboxWindow::createTitlebar(void) {
626 frame
.title
= createChildWindow(frame
.window
);
627 frame
.label
= createChildWindow(frame
.title
);
628 blackbox
->saveWindowSearch(frame
.title
, this);
629 blackbox
->saveWindowSearch(frame
.label
, this);
631 if (decorations
& Decor_Iconify
) createIconifyButton();
632 if (decorations
& Decor_Maximize
) createMaximizeButton();
633 if (decorations
& Decor_Close
) createCloseButton();
637 void BlackboxWindow::destroyTitlebar(void) {
638 if (frame
.close_button
)
639 destroyCloseButton();
641 if (frame
.iconify_button
)
642 destroyIconifyButton();
644 if (frame
.maximize_button
)
645 destroyMaximizeButton();
648 screen
->getImageControl()->removeImage(frame
.ftitle
);
651 screen
->getImageControl()->removeImage(frame
.utitle
);
654 screen
->getImageControl()->removeImage(frame
.flabel
);
657 screen
->getImageControl()->removeImage(frame
.ulabel
);
660 screen
->getImageControl()->removeImage(frame
.fbutton
);
663 screen
->getImageControl()->removeImage(frame
.ubutton
);
666 screen
->getImageControl()->removeImage(frame
.pbutton
);
668 blackbox
->removeWindowSearch(frame
.title
);
669 blackbox
->removeWindowSearch(frame
.label
);
671 XDestroyWindow(blackbox
->getXDisplay(), frame
.label
);
672 XDestroyWindow(blackbox
->getXDisplay(), frame
.title
);
673 frame
.title
= frame
.label
= None
;
677 void BlackboxWindow::createCloseButton(void) {
678 if (frame
.title
!= None
) {
679 frame
.close_button
= createChildWindow(frame
.title
);
680 blackbox
->saveWindowSearch(frame
.close_button
, this);
685 void BlackboxWindow::destroyCloseButton(void) {
686 blackbox
->removeWindowSearch(frame
.close_button
);
687 XDestroyWindow(blackbox
->getXDisplay(), frame
.close_button
);
688 frame
.close_button
= None
;
692 void BlackboxWindow::createIconifyButton(void) {
693 if (frame
.title
!= None
) {
694 frame
.iconify_button
= createChildWindow(frame
.title
);
695 blackbox
->saveWindowSearch(frame
.iconify_button
, this);
700 void BlackboxWindow::destroyIconifyButton(void) {
701 blackbox
->removeWindowSearch(frame
.iconify_button
);
702 XDestroyWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
703 frame
.iconify_button
= None
;
707 void BlackboxWindow::createMaximizeButton(void) {
708 if (frame
.title
!= None
) {
709 frame
.maximize_button
= createChildWindow(frame
.title
);
710 blackbox
->saveWindowSearch(frame
.maximize_button
, this);
715 void BlackboxWindow::destroyMaximizeButton(void) {
716 blackbox
->removeWindowSearch(frame
.maximize_button
);
717 XDestroyWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
718 frame
.maximize_button
= None
;
722 void BlackboxWindow::positionButtons(bool redecorate_label
) {
723 string layout
= blackbox
->getTitlebarLayout();
726 bool hasclose
, hasiconify
, hasmaximize
, haslabel
;
727 hasclose
= hasiconify
= hasmaximize
= haslabel
= false;
729 string::const_iterator it
, end
;
730 for (it
= layout
.begin(), end
= layout
.end(); it
!= end
; ++it
) {
733 if (! hasclose
&& (decorations
& Decor_Close
)) {
739 if (! hasiconify
&& (decorations
& Decor_Iconify
)) {
745 if (! hasmaximize
&& (decorations
& Decor_Maximize
)) {
757 if (! hasclose
&& frame
.close_button
)
758 destroyCloseButton();
759 if (! hasiconify
&& frame
.iconify_button
)
760 destroyIconifyButton();
761 if (! hasmaximize
&& frame
.maximize_button
)
762 destroyMaximizeButton();
764 parsed
+= 'L'; // require that the label be in the layout
766 const unsigned int bsep
= frame
.bevel_w
+ 1; // separation between elements
767 const unsigned int by
= frame
.bevel_w
+ 1;
768 const unsigned int ty
= frame
.bevel_w
;
770 frame
.label_w
= frame
.inside_w
- bsep
* 2 -
771 (frame
.button_w
+ bsep
) * (parsed
.size() - 1);
773 unsigned int x
= bsep
;
774 for (it
= parsed
.begin(), end
= parsed
.end(); it
!= end
; ++it
) {
777 if (! frame
.close_button
) createCloseButton();
778 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.close_button
, x
, by
,
779 frame
.button_w
, frame
.button_w
);
780 x
+= frame
.button_w
+ bsep
;
783 if (! frame
.iconify_button
) createIconifyButton();
784 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.iconify_button
, x
, by
,
785 frame
.button_w
, frame
.button_w
);
786 x
+= frame
.button_w
+ bsep
;
789 if (! frame
.maximize_button
) createMaximizeButton();
790 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.maximize_button
, x
, by
,
791 frame
.button_w
, frame
.button_w
);
792 x
+= frame
.button_w
+ bsep
;
795 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.label
, x
, ty
,
796 frame
.label_w
, frame
.label_h
);
797 x
+= frame
.label_w
+ bsep
;
802 if (redecorate_label
) decorateLabel();
808 void BlackboxWindow::reconfigure(void) {
809 restoreGravity(client
.rect
);
811 applyGravity(frame
.rect
);
820 windowmenu
->move(windowmenu
->getX(), frame
.rect
.y() + frame
.title_h
);
821 windowmenu
->reconfigure();
826 void BlackboxWindow::grabButtons(void) {
827 if (! screen
->isSloppyFocus() || screen
->doClickRaise())
828 // grab button 1 for changing focus/raising
829 blackbox
->grabButton(Button1
, 0, frame
.plate
, True
, ButtonPressMask
,
830 GrabModeSync
, GrabModeSync
, frame
.plate
, None
,
831 screen
->allowScrollLock());
833 if (functions
& Func_Move
)
834 blackbox
->grabButton(Button1
, ModMask
, frame
.window
, True
,
835 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
836 GrabModeAsync
, frame
.window
, None
,
837 screen
->allowScrollLock());
838 if (functions
& Func_Resize
)
839 blackbox
->grabButton(Button3
, ModMask
, frame
.window
, True
,
840 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
841 GrabModeAsync
, frame
.window
, None
,
842 screen
->allowScrollLock());
843 // alt+middle lowers the window
844 blackbox
->grabButton(Button2
, ModMask
, frame
.window
, True
,
845 ButtonReleaseMask
, GrabModeAsync
, GrabModeAsync
,
847 screen
->allowScrollLock());
851 void BlackboxWindow::ungrabButtons(void) {
852 if ((! screen
->isSloppyFocus()) || screen
->doClickRaise())
853 blackbox
->ungrabButton(Button1
, 0, frame
.plate
);
855 blackbox
->ungrabButton(Button1
, ModMask
, frame
.window
);
856 blackbox
->ungrabButton(Button2
, ModMask
, frame
.window
);
857 blackbox
->ungrabButton(Button3
, ModMask
, frame
.window
);
861 void BlackboxWindow::positionWindows(void) {
862 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.window
,
863 frame
.rect
.x(), frame
.rect
.y(), frame
.inside_w
,
864 (flags
.shaded
) ? frame
.title_h
: frame
.inside_h
);
865 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.window
,
867 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.plate
,
869 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.plate
,
870 frame
.margin
.left
- frame
.mwm_border_w
- frame
.border_w
,
871 frame
.margin
.top
- frame
.mwm_border_w
- frame
.border_w
,
872 client
.rect
.width(), client
.rect
.height());
873 XMoveResizeWindow(blackbox
->getXDisplay(), client
.window
,
874 0, 0, client
.rect
.width(), client
.rect
.height());
875 // ensure client.rect contains the real location
876 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
877 frame
.rect
.top() + frame
.margin
.top
);
879 if (decorations
& Decor_Titlebar
) {
880 if (frame
.title
== None
) createTitlebar();
882 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.title
,
884 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.title
, -frame
.border_w
,
885 -frame
.border_w
, frame
.inside_w
, frame
.title_h
);
888 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
889 XMapWindow(blackbox
->getXDisplay(), frame
.title
);
890 } else if (frame
.title
) {
893 if (decorations
& Decor_Handle
) {
894 if (frame
.handle
== None
) createHandle();
895 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.handle
,
897 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.left_grip
,
899 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.right_grip
,
902 // use client.rect here so the value is correct even if shaded
903 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.handle
,
905 client
.rect
.height() + frame
.margin
.top
+
906 frame
.mwm_border_w
- frame
.border_w
,
907 frame
.inside_w
, frame
.handle_h
);
908 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.left_grip
,
909 -frame
.border_w
, -frame
.border_w
,
910 frame
.grip_w
, frame
.handle_h
);
911 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.right_grip
,
912 frame
.inside_w
- frame
.grip_w
- frame
.border_w
,
913 -frame
.border_w
, frame
.grip_w
, frame
.handle_h
);
915 XMapSubwindows(blackbox
->getXDisplay(), frame
.handle
);
916 XMapWindow(blackbox
->getXDisplay(), frame
.handle
);
917 } else if (frame
.handle
) {
920 XSync(blackbox
->getXDisplay(), False
);
924 void BlackboxWindow::updateStrut(void) {
925 unsigned long num
= 4;
927 if (! xatom
->getValue(client
.window
, XAtom::net_wm_strut
, XAtom::cardinal
,
932 client
.strut
.left
= data
[0];
933 client
.strut
.right
= data
[1];
934 client
.strut
.top
= data
[2];
935 client
.strut
.bottom
= data
[3];
937 screen
->updateAvailableArea();
944 void BlackboxWindow::getWindowType(void) {
946 if (xatom
->getValue(client
.window
, XAtom::net_wm_window_type
, XAtom::atom
,
948 if (val
== xatom
->getAtom(XAtom::net_wm_window_type_desktop
))
949 window_type
= Type_Desktop
;
950 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_dock
))
951 window_type
= Type_Dock
;
952 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_toolbar
))
953 window_type
= Type_Toolbar
;
954 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_menu
))
955 window_type
= Type_Menu
;
956 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_utility
))
957 window_type
= Type_Utility
;
958 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_splash
))
959 window_type
= Type_Splash
;
960 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_dialog
))
961 window_type
= Type_Dialog
;
962 else //if (val[0] == xatom->getAtom(XAtom::net_wm_window_type_normal))
963 window_type
= Type_Normal
;
968 * the window type hint was not set, which means we either classify ourself
969 * as a normal window or a dialog, depending on if we are a transient.
972 window_type
= Type_Dialog
;
974 window_type
= Type_Normal
;
978 void BlackboxWindow::getWMName(void) {
979 if (xatom
->getValue(client
.window
, XAtom::net_wm_name
,
980 XAtom::utf8
, client
.title
) &&
981 !client
.title
.empty()) {
982 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
985 //fall through to using WM_NAME
986 if (xatom
->getValue(client
.window
, XAtom::wm_name
, XAtom::ansi
, client
.title
)
987 && !client
.title
.empty()) {
988 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
991 // fall back to an internal default
992 client
.title
= i18n(WindowSet
, WindowUnnamed
, "Unnamed");
993 xatom
->setValue(client
.window
, XAtom::net_wm_visible_name
, XAtom::utf8
,
998 void BlackboxWindow::getWMIconName(void) {
999 if (xatom
->getValue(client
.window
, XAtom::net_wm_icon_name
,
1000 XAtom::utf8
, client
.icon_title
) &&
1001 !client
.icon_title
.empty()) {
1002 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1005 //fall through to using WM_ICON_NAME
1006 if (xatom
->getValue(client
.window
, XAtom::wm_icon_name
, XAtom::ansi
,
1007 client
.icon_title
) &&
1008 !client
.icon_title
.empty()) {
1009 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1012 // fall back to using the main name
1013 client
.icon_title
= client
.title
;
1014 xatom
->setValue(client
.window
, XAtom::net_wm_visible_icon_name
, XAtom::utf8
,
1020 * Retrieve which WM Protocols are supported by the client window.
1021 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
1022 * window's decorations and allow the close behavior.
1023 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
1026 void BlackboxWindow::getWMProtocols(void) {
1030 if (XGetWMProtocols(blackbox
->getXDisplay(), client
.window
,
1031 &proto
, &num_return
)) {
1032 for (int i
= 0; i
< num_return
; ++i
) {
1033 if (proto
[i
] == xatom
->getAtom(XAtom::wm_delete_window
)) {
1034 decorations
|= Decor_Close
;
1035 functions
|= Func_Close
;
1036 } else if (proto
[i
] == xatom
->getAtom(XAtom::wm_take_focus
))
1037 flags
.send_focus_message
= True
;
1038 else if (proto
[i
] == xatom
->getAtom(XAtom::blackbox_structure_messages
))
1039 screen
->addNetizen(new Netizen(screen
, client
.window
));
1048 * Gets the value of the WM_HINTS property.
1049 * If the property is not set, then use a set of default values.
1051 void BlackboxWindow::getWMHints(void) {
1052 focus_mode
= F_Passive
;
1053 client
.initial_state
= NormalState
;
1055 // remove from current window group
1056 if (client
.window_group
) {
1057 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1058 if (group
) group
->removeWindow(this);
1060 client
.window_group
= None
;
1062 XWMHints
*wmhint
= XGetWMHints(blackbox
->getXDisplay(), client
.window
);
1067 if (wmhint
->flags
& InputHint
) {
1068 if (wmhint
->input
== True
) {
1069 if (flags
.send_focus_message
)
1070 focus_mode
= F_LocallyActive
;
1072 if (flags
.send_focus_message
)
1073 focus_mode
= F_GloballyActive
;
1075 focus_mode
= F_NoInput
;
1079 if (wmhint
->flags
& StateHint
)
1080 client
.initial_state
= wmhint
->initial_state
;
1082 if (wmhint
->flags
& WindowGroupHint
) {
1083 client
.window_group
= wmhint
->window_group
;
1085 // add window to the appropriate group
1086 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1087 if (! group
) { // no group found, create it!
1088 new BWindowGroup(blackbox
, client
.window_group
);
1089 group
= blackbox
->searchGroup(client
.window_group
);
1092 group
->addWindow(this);
1095 client
.wm_hint_flags
= wmhint
->flags
;
1101 * Gets the value of the WM_NORMAL_HINTS property.
1102 * If the property is not set, then use a set of default values.
1104 void BlackboxWindow::getWMNormalHints(void) {
1106 XSizeHints sizehint
;
1108 client
.min_width
= client
.min_height
=
1109 client
.width_inc
= client
.height_inc
= 1;
1110 client
.base_width
= client
.base_height
= 0;
1111 client
.win_gravity
= NorthWestGravity
;
1113 client
.min_aspect_x
= client
.min_aspect_y
=
1114 client
.max_aspect_x
= client
.max_aspect_y
= 1;
1118 use the full screen, not the strut modified size. otherwise when the
1119 availableArea changes max_width/height will be incorrect and lead to odd
1122 const Rect
& screen_area
= screen
->getRect();
1123 client
.max_width
= screen_area
.width();
1124 client
.max_height
= screen_area
.height();
1126 if (! XGetWMNormalHints(blackbox
->getXDisplay(), client
.window
,
1127 &sizehint
, &icccm_mask
))
1130 client
.normal_hint_flags
= sizehint
.flags
;
1132 if (sizehint
.flags
& PMinSize
) {
1133 if (sizehint
.min_width
>= 0)
1134 client
.min_width
= sizehint
.min_width
;
1135 if (sizehint
.min_height
>= 0)
1136 client
.min_height
= sizehint
.min_height
;
1139 if (sizehint
.flags
& PMaxSize
) {
1140 if (sizehint
.max_width
> static_cast<signed>(client
.min_width
))
1141 client
.max_width
= sizehint
.max_width
;
1143 client
.max_width
= client
.min_width
;
1145 if (sizehint
.max_height
> static_cast<signed>(client
.min_height
))
1146 client
.max_height
= sizehint
.max_height
;
1148 client
.max_height
= client
.min_height
;
1151 if (sizehint
.flags
& PResizeInc
) {
1152 client
.width_inc
= sizehint
.width_inc
;
1153 client
.height_inc
= sizehint
.height_inc
;
1156 #if 0 // we do not support this at the moment
1157 if (sizehint
.flags
& PAspect
) {
1158 client
.min_aspect_x
= sizehint
.min_aspect
.x
;
1159 client
.min_aspect_y
= sizehint
.min_aspect
.y
;
1160 client
.max_aspect_x
= sizehint
.max_aspect
.x
;
1161 client
.max_aspect_y
= sizehint
.max_aspect
.y
;
1165 if (sizehint
.flags
& PBaseSize
) {
1166 client
.base_width
= sizehint
.base_width
;
1167 client
.base_height
= sizehint
.base_height
;
1170 if (sizehint
.flags
& PWinGravity
)
1171 client
.win_gravity
= sizehint
.win_gravity
;
1176 * Gets the NETWM hints for the class' contained window.
1178 void BlackboxWindow::getNetWMHints(void) {
1179 unsigned long workspace
;
1181 if (xatom
->getValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1183 if (workspace
== 0xffffffff)
1186 blackbox_attrib
.workspace
= workspace
;
1189 unsigned long *state
;
1190 unsigned long num
= (unsigned) -1;
1191 if (xatom
->getValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
1195 for (unsigned long i
= 0; i
< num
; ++i
) {
1196 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
))
1198 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_shaded
))
1199 flags
.shaded
= True
;
1200 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
))
1201 flags
.skip_taskbar
= True
;
1202 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_pager
))
1203 flags
.skip_pager
= True
;
1204 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_fullscreen
))
1205 flags
.fullscreen
= True
;
1206 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_hidden
))
1207 setState(IconicState
);
1208 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_vert
))
1210 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_horz
))
1214 flags
.maximized
= 1;
1216 flags
.maximized
= 2;
1218 flags
.maximized
= 3;
1226 * Gets the MWM hints for the class' contained window.
1227 * This is used while initializing the window to its first state, and not
1229 * Returns: true if the MWM hints are successfully retreived and applied;
1230 * false if they are not.
1232 void BlackboxWindow::getMWMHints(void) {
1236 num
= PropMwmHintsElements
;
1237 if (! xatom
->getValue(client
.window
, XAtom::motif_wm_hints
,
1238 XAtom::motif_wm_hints
, num
,
1239 (unsigned long **)&mwm_hint
))
1241 if (num
< PropMwmHintsElements
) {
1246 if (mwm_hint
->flags
& MwmHintsDecorations
) {
1247 if (mwm_hint
->decorations
& MwmDecorAll
) {
1248 decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
1249 Decor_Iconify
| Decor_Maximize
| Decor_Close
;
1253 if (mwm_hint
->decorations
& MwmDecorBorder
)
1254 decorations
|= Decor_Border
;
1255 if (mwm_hint
->decorations
& MwmDecorHandle
)
1256 decorations
|= Decor_Handle
;
1257 if (mwm_hint
->decorations
& MwmDecorTitle
)
1258 decorations
|= Decor_Titlebar
;
1259 if (mwm_hint
->decorations
& MwmDecorIconify
)
1260 decorations
|= Decor_Iconify
;
1261 if (mwm_hint
->decorations
& MwmDecorMaximize
)
1262 decorations
|= Decor_Maximize
;
1266 if (mwm_hint
->flags
& MwmHintsFunctions
) {
1267 if (mwm_hint
->functions
& MwmFuncAll
) {
1268 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
|
1273 if (mwm_hint
->functions
& MwmFuncResize
)
1274 functions
|= Func_Resize
;
1275 if (mwm_hint
->functions
& MwmFuncMove
)
1276 functions
|= Func_Move
;
1277 if (mwm_hint
->functions
& MwmFuncIconify
)
1278 functions
|= Func_Iconify
;
1279 if (mwm_hint
->functions
& MwmFuncMaximize
)
1280 functions
|= Func_Maximize
;
1281 if (mwm_hint
->functions
& MwmFuncClose
)
1282 functions
|= Func_Close
;
1290 * Gets the blackbox hints from the class' contained window.
1291 * This is used while initializing the window to its first state, and not
1293 * Returns: true if the hints are successfully retreived and applied; false if
1296 bool BlackboxWindow::getBlackboxHints(void) {
1298 BlackboxHints
*blackbox_hint
;
1300 num
= PropBlackboxHintsElements
;
1301 if (! xatom
->getValue(client
.window
, XAtom::blackbox_hints
,
1302 XAtom::blackbox_hints
, num
,
1303 (unsigned long **)&blackbox_hint
))
1305 if (num
< PropBlackboxHintsElements
) {
1306 delete [] blackbox_hint
;
1310 if (blackbox_hint
->flags
& AttribShaded
)
1311 flags
.shaded
= (blackbox_hint
->attrib
& AttribShaded
);
1313 if ((blackbox_hint
->flags
& AttribMaxHoriz
) &&
1314 (blackbox_hint
->flags
& AttribMaxVert
))
1315 flags
.maximized
= (blackbox_hint
->attrib
&
1316 (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1317 else if (blackbox_hint
->flags
& AttribMaxVert
)
1318 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxVert
) ? 2 : 0;
1319 else if (blackbox_hint
->flags
& AttribMaxHoriz
)
1320 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1322 if (blackbox_hint
->flags
& AttribOmnipresent
)
1323 flags
.stuck
= (blackbox_hint
->attrib
& AttribOmnipresent
);
1325 if (blackbox_hint
->flags
& AttribWorkspace
)
1326 blackbox_attrib
.workspace
= blackbox_hint
->workspace
;
1328 // if (blackbox_hint->flags & AttribStack)
1329 // don't yet have always on top/bottom for blackbox yet... working
1332 if (blackbox_hint
->flags
& AttribDecoration
) {
1333 switch (blackbox_hint
->decoration
) {
1335 // clear all decorations except close
1336 decorations
&= Decor_Close
;
1337 // clear all functions except close
1338 functions
&= Func_Close
;
1343 decorations
|= Decor_Titlebar
| Decor_Iconify
;
1344 decorations
&= ~(Decor_Border
| Decor_Handle
| Decor_Maximize
);
1345 functions
|= Func_Move
| Func_Iconify
;
1346 functions
&= ~(Func_Resize
| Func_Maximize
);
1351 decorations
|= Decor_Titlebar
;
1352 decorations
&= ~(Decor_Iconify
| Decor_Border
| Decor_Handle
);
1353 functions
|= Func_Move
;
1354 functions
&= ~(Func_Resize
| Func_Maximize
| Func_Iconify
);
1360 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Handle
|
1361 Decor_Iconify
| Decor_Maximize
;
1362 functions
|= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
1370 delete [] blackbox_hint
;
1376 void BlackboxWindow::getTransientInfo(void) {
1377 if (client
.transient_for
&&
1378 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1379 // the transient for hint was removed, so we need to tell our
1380 // previous transient_for that we are going away
1381 client
.transient_for
->client
.transientList
.remove(this);
1384 // we have no transient_for until we find a new one
1385 client
.transient_for
= 0;
1388 if (! XGetTransientForHint(blackbox
->getXDisplay(), client
.window
,
1390 // transient_for hint not set
1394 if (trans_for
== client
.window
) {
1395 // wierd client... treat this window as a normal window
1399 if (trans_for
== None
|| trans_for
== screen
->getRootWindow()) {
1400 // this is an undocumented interpretation of the ICCCM. a transient
1401 // associated with None/Root/itself is assumed to be a modal root
1402 // transient. we don't support the concept of a global transient,
1403 // so we just associate this transient with nothing, and perhaps
1404 // we will add support later for global modality.
1405 client
.transient_for
= (BlackboxWindow
*) ~0ul;
1410 client
.transient_for
= blackbox
->searchWindow(trans_for
);
1411 if (! client
.transient_for
&&
1412 client
.window_group
&& trans_for
== client
.window_group
) {
1413 // no direct transient_for, perhaps this is a group transient?
1414 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1415 if (group
) client
.transient_for
= group
->find(screen
);
1418 if (! client
.transient_for
|| client
.transient_for
== this) {
1419 // no transient_for found, or we have a wierd client that wants to be
1420 // a transient for itself, so we treat this window as a normal window
1421 client
.transient_for
= (BlackboxWindow
*) 0;
1425 // register ourselves with our new transient_for
1426 client
.transient_for
->client
.transientList
.push_back(this);
1427 flags
.stuck
= client
.transient_for
->flags
.stuck
;
1431 BlackboxWindow
*BlackboxWindow::getTransientFor(void) const {
1432 if (client
.transient_for
&&
1433 client
.transient_for
!= (BlackboxWindow
*) ~0ul)
1434 return client
.transient_for
;
1440 * This function is responsible for updating both the client and the frame
1442 * According to the ICCCM a client message is not sent for a resize, only a
1445 void BlackboxWindow::configure(int dx
, int dy
,
1446 unsigned int dw
, unsigned int dh
) {
1447 bool send_event
= ((frame
.rect
.x() != dx
|| frame
.rect
.y() != dy
) &&
1450 if (dw
!= frame
.rect
.width() || dh
!= frame
.rect
.height()) {
1451 frame
.rect
.setRect(dx
, dy
, dw
, dh
);
1452 frame
.inside_w
= frame
.rect
.width() - (frame
.border_w
* 2);
1453 frame
.inside_h
= frame
.rect
.height() - (frame
.border_w
* 2);
1455 if (frame
.rect
.right() <= 0 || frame
.rect
.bottom() <= 0)
1456 frame
.rect
.setPos(0, 0);
1458 client
.rect
.setCoords(frame
.rect
.left() + frame
.margin
.left
,
1459 frame
.rect
.top() + frame
.margin
.top
,
1460 frame
.rect
.right() - frame
.margin
.right
,
1461 frame
.rect
.bottom() - frame
.margin
.bottom
);
1464 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
1471 redrawWindowFrame();
1473 frame
.rect
.setPos(dx
, dy
);
1475 XMoveWindow(blackbox
->getXDisplay(), frame
.window
,
1476 frame
.rect
.x(), frame
.rect
.y());
1478 we may have been called just after an opaque window move, so even though
1479 the old coords match the new ones no ConfigureNotify has been sent yet.
1480 There are likely other times when this will be relevant as well.
1482 if (! flags
.moving
) send_event
= True
;
1486 // if moving, the update and event will occur when the move finishes
1487 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1488 frame
.rect
.top() + frame
.margin
.top
);
1491 event
.type
= ConfigureNotify
;
1493 event
.xconfigure
.display
= blackbox
->getXDisplay();
1494 event
.xconfigure
.event
= client
.window
;
1495 event
.xconfigure
.window
= client
.window
;
1496 event
.xconfigure
.x
= client
.rect
.x();
1497 event
.xconfigure
.y
= client
.rect
.y();
1498 event
.xconfigure
.width
= client
.rect
.width();
1499 event
.xconfigure
.height
= client
.rect
.height();
1500 event
.xconfigure
.border_width
= client
.old_bw
;
1501 event
.xconfigure
.above
= frame
.window
;
1502 event
.xconfigure
.override_redirect
= False
;
1504 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1505 StructureNotifyMask
, &event
);
1506 screen
->updateNetizenConfigNotify(&event
);
1507 XFlush(blackbox
->getXDisplay());
1513 void BlackboxWindow::configureShape(void) {
1514 XShapeCombineShape(blackbox
->getXDisplay(), frame
.window
, ShapeBounding
,
1515 frame
.margin
.left
- frame
.border_w
,
1516 frame
.margin
.top
- frame
.border_w
,
1517 client
.window
, ShapeBounding
, ShapeSet
);
1520 XRectangle xrect
[2];
1522 if (decorations
& Decor_Titlebar
) {
1523 xrect
[0].x
= xrect
[0].y
= -frame
.border_w
;
1524 xrect
[0].width
= frame
.rect
.width();
1525 xrect
[0].height
= frame
.title_h
+ (frame
.border_w
* 2);
1529 if (decorations
& Decor_Handle
) {
1530 xrect
[1].x
= -frame
.border_w
;
1531 xrect
[1].y
= frame
.rect
.height() - frame
.margin
.bottom
+
1532 frame
.mwm_border_w
- frame
.border_w
;
1533 xrect
[1].width
= frame
.rect
.width();
1534 xrect
[1].height
= frame
.handle_h
+ (frame
.border_w
* 2);
1538 XShapeCombineRectangles(blackbox
->getXDisplay(), frame
.window
,
1539 ShapeBounding
, 0, 0, xrect
, num
,
1540 ShapeUnion
, Unsorted
);
1545 bool BlackboxWindow::setInputFocus(void) {
1546 if (flags
.focused
) return True
;
1548 assert(! flags
.iconic
&&
1549 (flags
.stuck
|| // window must be on the current workspace or sticky
1550 blackbox_attrib
.workspace
== screen
->getCurrentWorkspaceID()));
1552 // if the window is not visible, mark the window as wanting focus rather
1553 // than give it focus.
1554 if (! flags
.visible
) {
1555 Workspace
*wkspc
= screen
->getWorkspace(blackbox_attrib
.workspace
);
1556 wkspc
->setLastFocusedWindow(this);
1561 We only do this check for normal windows and dialogs because other windows
1562 do this on purpose, such as kde's kicker, and we don't want to go moving
1565 if (window_type
== Type_Normal
|| window_type
== Type_Dialog
)
1566 if (! frame
.rect
.intersects(screen
->getRect())) {
1567 // client is outside the screen, move it to the center
1568 configure((screen
->getWidth() - frame
.rect
.width()) / 2,
1569 (screen
->getHeight() - frame
.rect
.height()) / 2,
1570 frame
.rect
.width(), frame
.rect
.height());
1573 if (client
.transientList
.size() > 0) {
1574 // transfer focus to any modal transients
1575 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1576 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1577 if ((*it
)->flags
.modal
) return (*it
)->setInputFocus();
1582 if (focus_mode
== F_LocallyActive
|| focus_mode
== F_Passive
) {
1583 XSetInputFocus(blackbox
->getXDisplay(), client
.window
,
1584 RevertToPointerRoot
, CurrentTime
);
1586 blackbox
->setFocusedWindow(this);
1588 /* we could set the focus to none, since the window doesn't accept focus,
1589 * but we shouldn't set focus to nothing since this would surely make
1595 if (flags
.send_focus_message
) {
1597 ce
.xclient
.type
= ClientMessage
;
1598 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1599 ce
.xclient
.display
= blackbox
->getXDisplay();
1600 ce
.xclient
.window
= client
.window
;
1601 ce
.xclient
.format
= 32;
1602 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_take_focus
);
1603 ce
.xclient
.data
.l
[1] = blackbox
->getLastTime();
1604 ce
.xclient
.data
.l
[2] = 0l;
1605 ce
.xclient
.data
.l
[3] = 0l;
1606 ce
.xclient
.data
.l
[4] = 0l;
1607 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1609 XFlush(blackbox
->getXDisplay());
1616 void BlackboxWindow::iconify(void) {
1617 if (flags
.iconic
) return;
1619 // We don't need to worry about resizing because resizing always grabs the X
1620 // server. This should only ever happen if using opaque moving.
1624 if (windowmenu
) windowmenu
->hide();
1627 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1628 * we need to clear the event mask on client.window for a split second.
1629 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1630 * split second, leaving us with a ghost window... so, we need to do this
1631 * while the X server is grabbed
1633 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1634 StructureNotifyMask
;
1635 XGrabServer(blackbox
->getXDisplay());
1636 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1637 event_mask
& ~StructureNotifyMask
);
1638 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1639 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1640 XUngrabServer(blackbox
->getXDisplay());
1642 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1643 flags
.visible
= False
;
1644 flags
.iconic
= True
;
1646 setState(IconicState
);
1648 screen
->getWorkspace(blackbox_attrib
.workspace
)->removeWindow(this);
1650 if (isTransient()) {
1651 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1652 ! client
.transient_for
->flags
.iconic
) {
1653 // iconify our transient_for
1654 client
.transient_for
->iconify();
1658 screen
->addIcon(this);
1660 if (client
.transientList
.size() > 0) {
1661 // iconify all transients
1662 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1663 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1664 if (! (*it
)->flags
.iconic
) (*it
)->iconify();
1667 screen
->updateStackingList();
1671 void BlackboxWindow::show(void) {
1672 flags
.visible
= True
;
1673 flags
.iconic
= False
;
1675 current_state
= (flags
.shaded
) ? IconicState
: NormalState
;
1676 setState(current_state
);
1678 XMapWindow(blackbox
->getXDisplay(), client
.window
);
1679 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
1680 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
1685 XTranslateCoordinates(blackbox
->getXDisplay(), client
.window
,
1686 screen
->getRootWindow(),
1687 0, 0, &real_x
, &real_y
, &child
);
1688 fprintf(stderr
, "%s -- assumed: (%d, %d), real: (%d, %d)\n", getTitle(),
1689 client
.rect
.left(), client
.rect
.top(), real_x
, real_y
);
1690 assert(client
.rect
.left() == real_x
&& client
.rect
.top() == real_y
);
1695 void BlackboxWindow::deiconify(bool reassoc
, bool raise
) {
1696 if (flags
.iconic
|| reassoc
)
1697 screen
->reassociateWindow(this, BSENTINEL
, False
);
1698 else if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID())
1703 // reassociate and deiconify all transients
1704 if (reassoc
&& client
.transientList
.size() > 0) {
1705 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1706 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1707 (*it
)->deiconify(True
, False
);
1712 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1716 void BlackboxWindow::close(void) {
1718 ce
.xclient
.type
= ClientMessage
;
1719 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1720 ce
.xclient
.display
= blackbox
->getXDisplay();
1721 ce
.xclient
.window
= client
.window
;
1722 ce
.xclient
.format
= 32;
1723 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_delete_window
);
1724 ce
.xclient
.data
.l
[1] = CurrentTime
;
1725 ce
.xclient
.data
.l
[2] = 0l;
1726 ce
.xclient
.data
.l
[3] = 0l;
1727 ce
.xclient
.data
.l
[4] = 0l;
1728 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
, NoEventMask
, &ce
);
1729 XFlush(blackbox
->getXDisplay());
1733 void BlackboxWindow::withdraw(void) {
1734 // We don't need to worry about resizing because resizing always grabs the X
1735 // server. This should only ever happen if using opaque moving.
1739 flags
.visible
= False
;
1740 flags
.iconic
= False
;
1742 setState(current_state
);
1744 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1746 XGrabServer(blackbox
->getXDisplay());
1748 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1749 StructureNotifyMask
;
1750 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1751 event_mask
& ~StructureNotifyMask
);
1752 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1753 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1755 XUngrabServer(blackbox
->getXDisplay());
1757 if (windowmenu
) windowmenu
->hide();
1761 void BlackboxWindow::maximize(unsigned int button
) {
1762 // We don't need to worry about resizing because resizing always grabs the X
1763 // server. This should only ever happen if using opaque moving.
1767 // handle case where menu is open then the max button is used instead
1768 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
1770 if (flags
.maximized
) {
1771 flags
.maximized
= 0;
1773 blackbox_attrib
.flags
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1774 blackbox_attrib
.attrib
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1777 when a resize finishes, maximize(0) is called to clear any maximization
1778 flags currently set. Otherwise it still thinks it is maximized.
1779 so we do not need to call configure() because resizing will handle it
1781 if (! flags
.resizing
)
1782 configure(blackbox_attrib
.premax_x
, blackbox_attrib
.premax_y
,
1783 blackbox_attrib
.premax_w
, blackbox_attrib
.premax_h
);
1785 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
1786 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
1788 redrawAllButtons(); // in case it is not called in configure()
1789 setState(current_state
);
1793 blackbox_attrib
.premax_x
= frame
.rect
.x();
1794 blackbox_attrib
.premax_y
= frame
.rect
.y();
1795 blackbox_attrib
.premax_w
= frame
.rect
.width();
1796 // use client.rect so that clients can be restored even if shaded
1797 blackbox_attrib
.premax_h
=
1798 client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
;
1801 if (screen
->isXineramaActive() && blackbox
->doXineramaMaximizing()) {
1802 // find the area to use
1803 RectList availableAreas
= screen
->allAvailableAreas();
1804 RectList::iterator it
, end
= availableAreas
.end();
1806 for (it
= availableAreas
.begin(); it
!= end
; ++it
)
1807 if (it
->intersects(frame
.rect
)) break;
1808 if (it
== end
) // the window isn't inside an area
1809 it
= availableAreas
.begin(); // so just default to the first one
1811 frame
.changing
= *it
;
1814 frame
.changing
= screen
->availableArea();
1818 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1819 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1823 blackbox_attrib
.flags
|= AttribMaxVert
;
1824 blackbox_attrib
.attrib
|= AttribMaxVert
;
1826 frame
.changing
.setX(frame
.rect
.x());
1827 frame
.changing
.setWidth(frame
.rect
.width());
1831 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1832 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1834 frame
.changing
.setY(frame
.rect
.y());
1835 frame
.changing
.setHeight(frame
.rect
.height());
1842 blackbox_attrib
.flags
^= AttribShaded
;
1843 blackbox_attrib
.attrib
^= AttribShaded
;
1844 flags
.shaded
= False
;
1847 flags
.maximized
= button
;
1849 configure(frame
.changing
.x(), frame
.changing
.y(),
1850 frame
.changing
.width(), frame
.changing
.height());
1852 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1853 redrawAllButtons(); // in case it is not called in configure()
1854 setState(current_state
);
1858 // re-maximizes the window to take into account availableArea changes
1859 void BlackboxWindow::remaximize(void) {
1860 // save the original dimensions because maximize will wipe them out
1861 int premax_x
= blackbox_attrib
.premax_x
,
1862 premax_y
= blackbox_attrib
.premax_y
,
1863 premax_w
= blackbox_attrib
.premax_w
,
1864 premax_h
= blackbox_attrib
.premax_h
;
1866 unsigned int button
= flags
.maximized
;
1867 flags
.maximized
= 0; // trick maximize() into working
1870 // restore saved values
1871 blackbox_attrib
.premax_x
= premax_x
;
1872 blackbox_attrib
.premax_y
= premax_y
;
1873 blackbox_attrib
.premax_w
= premax_w
;
1874 blackbox_attrib
.premax_h
= premax_h
;
1878 void BlackboxWindow::setWorkspace(unsigned int n
) {
1879 blackbox_attrib
.flags
|= AttribWorkspace
;
1880 blackbox_attrib
.workspace
= n
;
1881 if (n
== BSENTINEL
) { // iconified window
1883 we set the workspace to 'all workspaces' so that taskbars will show the
1884 window. otherwise, it made uniconifying a window imposible without the
1885 blackbox workspace menu
1889 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
, n
);
1893 void BlackboxWindow::shade(void) {
1895 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1896 frame
.inside_w
, frame
.inside_h
);
1897 flags
.shaded
= False
;
1898 blackbox_attrib
.flags
^= AttribShaded
;
1899 blackbox_attrib
.attrib
^= AttribShaded
;
1901 setState(NormalState
);
1903 // set the frame rect to the normal size
1904 frame
.rect
.setHeight(client
.rect
.height() + frame
.margin
.top
+
1905 frame
.margin
.bottom
);
1907 if (! (decorations
& Decor_Titlebar
))
1908 return; // can't shade it without a titlebar!
1910 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1911 frame
.inside_w
, frame
.title_h
);
1912 flags
.shaded
= True
;
1913 blackbox_attrib
.flags
|= AttribShaded
;
1914 blackbox_attrib
.attrib
|= AttribShaded
;
1916 setState(IconicState
);
1918 // set the frame rect to the shaded size
1919 frame
.rect
.setHeight(frame
.title_h
+ (frame
.border_w
* 2));
1925 * (Un)Sticks a window and its relatives.
1927 void BlackboxWindow::stick(void) {
1929 blackbox_attrib
.flags
^= AttribOmnipresent
;
1930 blackbox_attrib
.attrib
^= AttribOmnipresent
;
1932 flags
.stuck
= False
;
1935 screen
->reassociateWindow(this, BSENTINEL
, True
);
1936 // temporary fix since sticky windows suck. set the hint to what we
1937 // actually hold in our data.
1938 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1939 blackbox_attrib
.workspace
);
1941 setState(current_state
);
1945 blackbox_attrib
.flags
|= AttribOmnipresent
;
1946 blackbox_attrib
.attrib
|= AttribOmnipresent
;
1948 // temporary fix since sticky windows suck. set the hint to a different
1949 // value than that contained in the class' data.
1950 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1953 setState(current_state
);
1956 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1957 client
.transient_for
->isStuck() != flags
.stuck
)
1958 client
.transient_for
->stick();
1959 // go down the chain
1960 BlackboxWindowList::iterator it
;
1961 const BlackboxWindowList::iterator end
= client
.transientList
.end();
1962 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1963 if ((*it
)->isStuck() != flags
.stuck
)
1968 void BlackboxWindow::redrawWindowFrame(void) const {
1969 if (decorations
& Decor_Titlebar
) {
1970 if (flags
.focused
) {
1972 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1973 frame
.title
, frame
.ftitle
);
1975 XSetWindowBackground(blackbox
->getXDisplay(),
1976 frame
.title
, frame
.ftitle_pixel
);
1979 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1980 frame
.title
, frame
.utitle
);
1982 XSetWindowBackground(blackbox
->getXDisplay(),
1983 frame
.title
, frame
.utitle_pixel
);
1985 XClearWindow(blackbox
->getXDisplay(), frame
.title
);
1991 if (decorations
& Decor_Handle
) {
1992 if (flags
.focused
) {
1994 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1995 frame
.handle
, frame
.fhandle
);
1997 XSetWindowBackground(blackbox
->getXDisplay(),
1998 frame
.handle
, frame
.fhandle_pixel
);
2001 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2002 frame
.left_grip
, frame
.fgrip
);
2003 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2004 frame
.right_grip
, frame
.fgrip
);
2006 XSetWindowBackground(blackbox
->getXDisplay(),
2007 frame
.left_grip
, frame
.fgrip_pixel
);
2008 XSetWindowBackground(blackbox
->getXDisplay(),
2009 frame
.right_grip
, frame
.fgrip_pixel
);
2013 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2014 frame
.handle
, frame
.uhandle
);
2016 XSetWindowBackground(blackbox
->getXDisplay(),
2017 frame
.handle
, frame
.uhandle_pixel
);
2020 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2021 frame
.left_grip
, frame
.ugrip
);
2022 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2023 frame
.right_grip
, frame
.ugrip
);
2025 XSetWindowBackground(blackbox
->getXDisplay(),
2026 frame
.left_grip
, frame
.ugrip_pixel
);
2027 XSetWindowBackground(blackbox
->getXDisplay(),
2028 frame
.right_grip
, frame
.ugrip_pixel
);
2031 XClearWindow(blackbox
->getXDisplay(), frame
.handle
);
2032 XClearWindow(blackbox
->getXDisplay(), frame
.left_grip
);
2033 XClearWindow(blackbox
->getXDisplay(), frame
.right_grip
);
2036 if (decorations
& Decor_Border
) {
2038 XSetWindowBorder(blackbox
->getXDisplay(),
2039 frame
.plate
, frame
.fborder_pixel
);
2041 XSetWindowBorder(blackbox
->getXDisplay(),
2042 frame
.plate
, frame
.uborder_pixel
);
2047 void BlackboxWindow::setFocusFlag(bool focus
) {
2048 // only focus a window if it is visible
2049 if (focus
&& !flags
.visible
)
2052 flags
.focused
= focus
;
2054 redrawWindowFrame();
2056 if (screen
->isSloppyFocus() && screen
->doAutoRaise()) {
2057 if (isFocused()) timer
->start();
2062 blackbox
->setFocusedWindow(this);
2064 Clientmenu
*menu
= screen
->getWorkspace(blackbox_attrib
.workspace
)->getMenu();
2065 menu
->setItemSelected(window_number
, isFocused());
2069 void BlackboxWindow::installColormap(bool install
) {
2070 int i
= 0, ncmap
= 0;
2071 Colormap
*cmaps
= XListInstalledColormaps(blackbox
->getXDisplay(),
2072 client
.window
, &ncmap
);
2074 XWindowAttributes wattrib
;
2075 if (XGetWindowAttributes(blackbox
->getXDisplay(),
2076 client
.window
, &wattrib
)) {
2078 // install the window's colormap
2079 for (i
= 0; i
< ncmap
; i
++) {
2080 if (*(cmaps
+ i
) == wattrib
.colormap
)
2081 // this window is using an installed color map... do not install
2084 // otherwise, install the window's colormap
2086 XInstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2088 // uninstall the window's colormap
2089 for (i
= 0; i
< ncmap
; i
++) {
2090 if (*(cmaps
+ i
) == wattrib
.colormap
)
2091 // we found the colormap to uninstall
2092 XUninstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2102 void BlackboxWindow::setAllowedActions(void) {
2106 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_shade
);
2107 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_change_desktop
);
2108 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_close
);
2110 if (functions
& Func_Move
)
2111 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_move
);
2112 if (functions
& Func_Resize
)
2113 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_resize
);
2114 if (functions
& Func_Maximize
) {
2115 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_horz
);
2116 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_vert
);
2119 xatom
->setValue(client
.window
, XAtom::net_wm_allowed_actions
, XAtom::atom
,
2124 void BlackboxWindow::setState(unsigned long new_state
) {
2125 current_state
= new_state
;
2127 unsigned long state
[2];
2128 state
[0] = current_state
;
2130 xatom
->setValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
, state
, 2);
2132 xatom
->setValue(client
.window
, XAtom::blackbox_attributes
,
2133 XAtom::blackbox_attributes
, (unsigned long *)&blackbox_attrib
,
2134 PropBlackboxAttributesElements
);
2139 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_modal
);
2141 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_shaded
);
2143 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_hidden
);
2144 if (flags
.skip_taskbar
)
2145 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
);
2146 if (flags
.skip_pager
)
2147 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_pager
);
2148 if (flags
.fullscreen
)
2149 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_fullscreen
);
2150 if (flags
.maximized
== 1 || flags
.maximized
== 2)
2151 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_vert
);
2152 if (flags
.maximized
== 1 || flags
.maximized
== 3)
2153 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_horz
);
2154 xatom
->setValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
2159 bool BlackboxWindow::getState(void) {
2160 bool ret
= xatom
->getValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
,
2162 if (! ret
) current_state
= 0;
2167 void BlackboxWindow::restoreAttributes(void) {
2168 unsigned long num
= PropBlackboxAttributesElements
;
2169 BlackboxAttributes
*net
;
2170 if (! xatom
->getValue(client
.window
, XAtom::blackbox_attributes
,
2171 XAtom::blackbox_attributes
, num
,
2172 (unsigned long **)&net
))
2174 if (num
< PropBlackboxAttributesElements
) {
2179 if (net
->flags
& AttribShaded
&& net
->attrib
& AttribShaded
) {
2180 flags
.shaded
= False
;
2181 unsigned long orig_state
= current_state
;
2185 At this point in the life of a window, current_state should only be set
2186 to IconicState if the window was an *icon*, not if it was shaded.
2188 if (orig_state
!= IconicState
)
2189 current_state
= WithdrawnState
;
2192 if (net
->workspace
!= screen
->getCurrentWorkspaceID() &&
2193 net
->workspace
< screen
->getWorkspaceCount())
2194 screen
->reassociateWindow(this, net
->workspace
, True
);
2196 if ((blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID()) &&
2197 (blackbox_attrib
.workspace
< screen
->getWorkspaceCount())) {
2198 // set to WithdrawnState so it will be mapped on the new workspace
2199 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2200 } else if (current_state
== WithdrawnState
) {
2201 // the window is on this workspace and is Withdrawn, so it is waiting to
2203 current_state
= NormalState
;
2206 if (net
->flags
& AttribOmnipresent
&& net
->attrib
& AttribOmnipresent
) {
2207 flags
.stuck
= False
;
2210 // if the window was on another workspace, it was going to be hidden. this
2211 // specifies that the window should be mapped since it is sticky.
2212 if (current_state
== WithdrawnState
) current_state
= NormalState
;
2215 if (net
->flags
& AttribMaxHoriz
|| net
->flags
& AttribMaxVert
) {
2216 int x
= net
->premax_x
, y
= net
->premax_y
;
2217 unsigned int w
= net
->premax_w
, h
= net
->premax_h
;
2218 flags
.maximized
= 0;
2221 if ((net
->flags
& AttribMaxHoriz
) &&
2222 (net
->flags
& AttribMaxVert
))
2223 m
= (net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
2224 else if (net
->flags
& AttribMaxVert
)
2225 m
= (net
->attrib
& AttribMaxVert
) ? 2 : 0;
2226 else if (net
->flags
& AttribMaxHoriz
)
2227 m
= (net
->attrib
& AttribMaxHoriz
) ? 3 : 0;
2231 blackbox_attrib
.premax_x
= x
;
2232 blackbox_attrib
.premax_y
= y
;
2233 blackbox_attrib
.premax_w
= w
;
2234 blackbox_attrib
.premax_h
= h
;
2237 // with the state set it will then be the map event's job to read the
2238 // window's state and behave accordingly
2245 * Positions the Rect r according the the client window position and
2248 void BlackboxWindow::applyGravity(Rect
&r
) {
2249 // apply horizontal window gravity
2250 switch (client
.win_gravity
) {
2252 case NorthWestGravity
:
2253 case SouthWestGravity
:
2255 r
.setX(client
.rect
.x());
2261 r
.setX(client
.rect
.x() - (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2264 case NorthEastGravity
:
2265 case SouthEastGravity
:
2267 r
.setX(client
.rect
.x() - frame
.margin
.left
- frame
.margin
.right
+ 2);
2272 r
.setX(client
.rect
.x() - frame
.margin
.left
);
2276 // apply vertical window gravity
2277 switch (client
.win_gravity
) {
2279 case NorthWestGravity
:
2280 case NorthEastGravity
:
2282 r
.setY(client
.rect
.y());
2288 r
.setY(client
.rect
.y() - (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2291 case SouthWestGravity
:
2292 case SouthEastGravity
:
2294 r
.setY(client
.rect
.y() - frame
.margin
.top
- frame
.margin
.bottom
+ 2);
2299 r
.setY(client
.rect
.y() - frame
.margin
.top
);
2306 * The reverse of the applyGravity function.
2308 * Positions the Rect r according to the frame window position and
2311 void BlackboxWindow::restoreGravity(Rect
&r
) {
2312 // restore horizontal window gravity
2313 switch (client
.win_gravity
) {
2315 case NorthWestGravity
:
2316 case SouthWestGravity
:
2318 r
.setX(frame
.rect
.x());
2324 r
.setX(frame
.rect
.x() + (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2327 case NorthEastGravity
:
2328 case SouthEastGravity
:
2330 r
.setX(frame
.rect
.x() + frame
.margin
.left
+ frame
.margin
.right
- 2);
2335 r
.setX(frame
.rect
.x() + frame
.margin
.left
);
2339 // restore vertical window gravity
2340 switch (client
.win_gravity
) {
2342 case NorthWestGravity
:
2343 case NorthEastGravity
:
2345 r
.setY(frame
.rect
.y());
2351 r
.setY(frame
.rect
.y() + (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2354 case SouthWestGravity
:
2355 case SouthEastGravity
:
2357 r
.setY(frame
.rect
.y() + frame
.margin
.top
+ frame
.margin
.bottom
- 2);
2362 r
.setY(frame
.rect
.y() + frame
.margin
.top
);
2368 void BlackboxWindow::redrawLabel(void) const {
2369 if (flags
.focused
) {
2371 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2372 frame
.label
, frame
.flabel
);
2374 XSetWindowBackground(blackbox
->getXDisplay(),
2375 frame
.label
, frame
.flabel_pixel
);
2378 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2379 frame
.label
, frame
.ulabel
);
2381 XSetWindowBackground(blackbox
->getXDisplay(),
2382 frame
.label
, frame
.ulabel_pixel
);
2384 XClearWindow(blackbox
->getXDisplay(), frame
.label
);
2386 WindowStyle
*style
= screen
->getWindowStyle();
2388 int pos
= frame
.bevel_w
* 2;
2389 style
->doJustify(client
.title
.c_str(), pos
, frame
.label_w
, frame
.bevel_w
* 4);
2390 style
->font
->drawString(frame
.label
, pos
, 1,
2391 (flags
.focused
? style
->l_text_focus
:
2392 style
->l_text_unfocus
),
2397 void BlackboxWindow::redrawAllButtons(void) const {
2398 if (frame
.iconify_button
) redrawIconifyButton(False
);
2399 if (frame
.maximize_button
) redrawMaximizeButton(flags
.maximized
);
2400 if (frame
.close_button
) redrawCloseButton(False
);
2404 void BlackboxWindow::redrawIconifyButton(bool pressed
) const {
2406 if (flags
.focused
) {
2408 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2409 frame
.iconify_button
, frame
.fbutton
);
2411 XSetWindowBackground(blackbox
->getXDisplay(),
2412 frame
.iconify_button
, frame
.fbutton_pixel
);
2415 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2416 frame
.iconify_button
, frame
.ubutton
);
2418 XSetWindowBackground(blackbox
->getXDisplay(), frame
.iconify_button
,
2419 frame
.ubutton_pixel
);
2423 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2424 frame
.iconify_button
, frame
.pbutton
);
2426 XSetWindowBackground(blackbox
->getXDisplay(),
2427 frame
.iconify_button
, frame
.pbutton_pixel
);
2429 XClearWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
2431 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2432 screen
->getWindowStyle()->b_pic_unfocus
);
2433 XDrawRectangle(blackbox
->getXDisplay(), frame
.iconify_button
, pen
.gc(),
2434 2, (frame
.button_w
- 5), (frame
.button_w
- 5), 2);
2438 void BlackboxWindow::redrawMaximizeButton(bool pressed
) const {
2440 if (flags
.focused
) {
2442 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2443 frame
.maximize_button
, frame
.fbutton
);
2445 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2446 frame
.fbutton_pixel
);
2449 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2450 frame
.maximize_button
, frame
.ubutton
);
2452 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2453 frame
.ubutton_pixel
);
2457 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2458 frame
.maximize_button
, frame
.pbutton
);
2460 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2461 frame
.pbutton_pixel
);
2463 XClearWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
2465 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2466 screen
->getWindowStyle()->b_pic_unfocus
);
2467 XDrawRectangle(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2468 2, 2, (frame
.button_w
- 5), (frame
.button_w
- 5));
2469 XDrawLine(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2470 2, 3, (frame
.button_w
- 3), 3);
2474 void BlackboxWindow::redrawCloseButton(bool pressed
) const {
2476 if (flags
.focused
) {
2478 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2481 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2482 frame
.fbutton_pixel
);
2485 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2488 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2489 frame
.ubutton_pixel
);
2493 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2494 frame
.close_button
, frame
.pbutton
);
2496 XSetWindowBackground(blackbox
->getXDisplay(),
2497 frame
.close_button
, frame
.pbutton_pixel
);
2499 XClearWindow(blackbox
->getXDisplay(), frame
.close_button
);
2501 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2502 screen
->getWindowStyle()->b_pic_unfocus
);
2503 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2504 2, 2, (frame
.button_w
- 3), (frame
.button_w
- 3));
2505 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2506 2, (frame
.button_w
- 3), (frame
.button_w
- 3), 2);
2510 void BlackboxWindow::mapRequestEvent(const XMapRequestEvent
*re
) {
2511 if (re
->window
!= client
.window
)
2515 fprintf(stderr
, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2519 switch (current_state
) {
2524 case WithdrawnState
:
2533 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2535 if (! blackbox
->isStartup()) {
2536 XSync(blackbox
->getXDisplay(), False
); // make sure the frame is mapped
2537 if (screen
->doFocusNew()|| (isTransient() && getTransientFor() &&
2538 getTransientFor()->isFocused())) {
2541 if (screen
->getPlacementPolicy() == BScreen::ClickMousePlacement
) {
2545 XQueryPointer(blackbox
->getXDisplay(), screen
->getRootWindow(),
2546 &r
, &c
, &rx
, &ry
, &x
, &y
, &m
);
2556 void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent
*ue
) {
2557 if (ue
->window
!= client
.window
)
2561 fprintf(stderr
, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2565 screen
->unmanageWindow(this, False
);
2569 void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent
*de
) {
2570 if (de
->window
!= client
.window
)
2574 fprintf(stderr
, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2578 screen
->unmanageWindow(this, False
);
2582 void BlackboxWindow::reparentNotifyEvent(const XReparentEvent
*re
) {
2583 if (re
->window
!= client
.window
|| re
->parent
== frame
.plate
)
2587 fprintf(stderr
, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2588 "0x%lx.\n", client
.window
, re
->parent
);
2593 XPutBackEvent(blackbox
->getXDisplay(), &ev
);
2594 screen
->unmanageWindow(this, True
);
2598 void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent
*pe
) {
2599 if (pe
->state
== PropertyDelete
)
2603 fprintf(stderr
, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n",
2609 case XA_WM_CLIENT_MACHINE
:
2613 case XA_WM_TRANSIENT_FOR
: {
2614 // determine if this is a transient window
2617 // adjust the window decorations based on transience
2618 if (isTransient()) {
2619 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2620 functions
&= ~Func_Maximize
;
2621 setAllowedActions();
2632 case XA_WM_ICON_NAME
:
2634 if (flags
.iconic
) screen
->propagateWindowName(this);
2637 case XAtom::net_wm_name
:
2641 if (decorations
& Decor_Titlebar
)
2644 screen
->propagateWindowName(this);
2647 case XA_WM_NORMAL_HINTS
: {
2650 if ((client
.normal_hint_flags
& PMinSize
) &&
2651 (client
.normal_hint_flags
& PMaxSize
)) {
2652 // the window now can/can't resize itself, so the buttons need to be
2655 if (client
.max_width
<= client
.min_width
&&
2656 client
.max_height
<= client
.min_height
) {
2657 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2658 functions
&= ~(Func_Resize
| Func_Maximize
);
2660 if (! isTransient()) {
2661 decorations
|= Decor_Maximize
| Decor_Handle
;
2662 functions
|= Func_Maximize
;
2664 functions
|= Func_Resize
;
2667 setAllowedActions();
2670 Rect old_rect
= frame
.rect
;
2674 if (old_rect
!= frame
.rect
)
2681 if (pe
->atom
== xatom
->getAtom(XAtom::wm_protocols
)) {
2684 if ((decorations
& Decor_Close
) && (! frame
.close_button
)) {
2685 createCloseButton();
2686 if (decorations
& Decor_Titlebar
) {
2687 positionButtons(True
);
2688 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
2690 if (windowmenu
) windowmenu
->reconfigure();
2692 } else if (pe
->atom
== xatom
->getAtom(XAtom::net_wm_strut
)) {
2701 void BlackboxWindow::exposeEvent(const XExposeEvent
*ee
) {
2703 fprintf(stderr
, "BlackboxWindow::exposeEvent() for 0x%lx\n", client
.window
);
2706 if (frame
.label
== ee
->window
&& (decorations
& Decor_Titlebar
))
2708 else if (frame
.close_button
== ee
->window
)
2709 redrawCloseButton(False
);
2710 else if (frame
.maximize_button
== ee
->window
)
2711 redrawMaximizeButton(flags
.maximized
);
2712 else if (frame
.iconify_button
== ee
->window
)
2713 redrawIconifyButton(False
);
2717 void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent
*cr
) {
2718 if (cr
->window
!= client
.window
|| flags
.iconic
)
2721 if (cr
->value_mask
& CWBorderWidth
)
2722 client
.old_bw
= cr
->border_width
;
2724 if (cr
->value_mask
& (CWX
| CWY
| CWWidth
| CWHeight
)) {
2725 Rect req
= frame
.rect
;
2727 if (cr
->value_mask
& (CWX
| CWY
)) {
2728 if (cr
->value_mask
& CWX
)
2729 client
.rect
.setX(cr
->x
);
2730 if (cr
->value_mask
& CWY
)
2731 client
.rect
.setY(cr
->y
);
2736 if (cr
->value_mask
& CWWidth
)
2737 req
.setWidth(cr
->width
+ frame
.margin
.left
+ frame
.margin
.right
);
2739 if (cr
->value_mask
& CWHeight
)
2740 req
.setHeight(cr
->height
+ frame
.margin
.top
+ frame
.margin
.bottom
);
2742 configure(req
.x(), req
.y(), req
.width(), req
.height());
2745 if (cr
->value_mask
& CWStackMode
&& !isDesktop()) {
2746 switch (cr
->detail
) {
2749 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2755 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2762 void BlackboxWindow::buttonPressEvent(const XButtonEvent
*be
) {
2764 fprintf(stderr
, "BlackboxWindow::buttonPressEvent() for 0x%lx\n",
2768 if (frame
.maximize_button
== be
->window
&& be
->button
<= 3) {
2769 redrawMaximizeButton(True
);
2770 } else if (be
->button
== 1 || (be
->button
== 3 && be
->state
== ModMask
)) {
2771 if (! flags
.focused
)
2774 if (frame
.iconify_button
== be
->window
) {
2775 redrawIconifyButton(True
);
2776 } else if (frame
.close_button
== be
->window
) {
2777 redrawCloseButton(True
);
2778 } else if (frame
.plate
== be
->window
) {
2779 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2781 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2783 XAllowEvents(blackbox
->getXDisplay(), ReplayPointer
, be
->time
);
2785 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
2786 if (((be
->time
- lastButtonPressTime
) <=
2787 blackbox
->getDoubleClickInterval()) ||
2788 (be
->state
== ControlMask
)) {
2789 lastButtonPressTime
= 0;
2792 lastButtonPressTime
= be
->time
;
2796 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2798 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2800 } else if (be
->button
== 2 && (be
->window
!= frame
.iconify_button
) &&
2801 (be
->window
!= frame
.close_button
)) {
2802 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2803 } else if (windowmenu
&& be
->button
== 3 &&
2804 (frame
.title
== be
->window
|| frame
.label
== be
->window
||
2805 frame
.handle
== be
->window
|| frame
.window
== be
->window
)) {
2806 if (windowmenu
->isVisible()) {
2809 int mx
= be
->x_root
- windowmenu
->getWidth() / 2,
2810 my
= be
->y_root
- windowmenu
->getHeight() / 2;
2812 // snap the window menu into a corner/side if necessary
2813 int left_edge
, right_edge
, top_edge
, bottom_edge
;
2816 the " + (frame.border_w * 2) - 1" bits are to get the proper width
2817 and height of the menu, as the sizes returned by it do not include
2820 left_edge
= frame
.rect
.x();
2821 right_edge
= frame
.rect
.right() -
2822 (windowmenu
->getWidth() + (frame
.border_w
* 2) - 1);
2823 top_edge
= client
.rect
.top() - (frame
.border_w
+ frame
.mwm_border_w
);
2824 bottom_edge
= client
.rect
.bottom() -
2825 (windowmenu
->getHeight() + (frame
.border_w
* 2) - 1) +
2826 (frame
.border_w
+ frame
.mwm_border_w
);
2830 if (mx
> right_edge
)
2834 if (my
> bottom_edge
)
2837 windowmenu
->move(mx
, my
);
2839 XRaiseWindow(blackbox
->getXDisplay(), windowmenu
->getWindowID());
2840 XRaiseWindow(blackbox
->getXDisplay(),
2841 windowmenu
->getSendToMenu()->getWindowID());
2844 } else if (be
->button
== 4) {
2845 if ((be
->window
== frame
.label
||
2846 be
->window
== frame
.title
||
2847 be
->window
== frame
.maximize_button
||
2848 be
->window
== frame
.iconify_button
||
2849 be
->window
== frame
.close_button
) &&
2853 } else if (be
->button
== 5) {
2854 if ((be
->window
== frame
.label
||
2855 be
->window
== frame
.title
||
2856 be
->window
== frame
.maximize_button
||
2857 be
->window
== frame
.iconify_button
||
2858 be
->window
== frame
.close_button
) &&
2865 void BlackboxWindow::buttonReleaseEvent(const XButtonEvent
*re
) {
2867 fprintf(stderr
, "BlackboxWindow::buttonReleaseEvent() for 0x%lx\n",
2871 if (re
->window
== frame
.maximize_button
&&
2872 re
->button
>= 1 && re
->button
<= 3) {
2873 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2874 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2875 maximize(re
->button
);
2877 redrawMaximizeButton(flags
.maximized
);
2879 } else if (re
->window
== frame
.iconify_button
&& re
->button
== 1) {
2880 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2881 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2884 redrawIconifyButton(False
);
2886 } else if (re
->window
== frame
.close_button
& re
->button
== 1) {
2887 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2888 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
)))
2890 redrawCloseButton(False
);
2891 } else if (flags
.moving
) {
2893 } else if (flags
.resizing
) {
2895 } else if (re
->window
== frame
.window
) {
2896 if (re
->button
== 2 && re
->state
== ModMask
)
2897 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
2903 void BlackboxWindow::beginMove(int x_root
, int y_root
) {
2904 assert(! (flags
.resizing
|| flags
.moving
));
2907 Only one window can be moved/resized at a time. If another window is already
2908 being moved or resized, then stop it before whating to work with this one.
2910 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
2911 if (changing
&& changing
!= this) {
2912 if (changing
->flags
.moving
)
2913 changing
->endMove();
2914 else // if (changing->flags.resizing)
2915 changing
->endResize();
2918 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
2919 PointerMotionMask
| ButtonReleaseMask
,
2920 GrabModeAsync
, GrabModeAsync
,
2921 None
, blackbox
->getMoveCursor(), CurrentTime
);
2923 if (windowmenu
&& windowmenu
->isVisible())
2926 flags
.moving
= True
;
2927 blackbox
->setChangingWindow(this);
2929 if (! screen
->doOpaqueMove()) {
2930 XGrabServer(blackbox
->getXDisplay());
2932 frame
.changing
= frame
.rect
;
2933 screen
->showPosition(frame
.changing
.x(), frame
.changing
.y());
2935 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2939 frame
.changing
.width() - 1,
2940 frame
.changing
.height() - 1);
2943 frame
.grab_x
= x_root
- frame
.rect
.x() - frame
.border_w
;
2944 frame
.grab_y
= y_root
- frame
.rect
.y() - frame
.border_w
;
2948 void BlackboxWindow::doMove(int x_root
, int y_root
) {
2949 assert(flags
.moving
);
2950 assert(blackbox
->getChangingWindow() == this);
2952 int dx
= x_root
- frame
.grab_x
, dy
= y_root
- frame
.grab_y
;
2953 dx
-= frame
.border_w
;
2954 dy
-= frame
.border_w
;
2956 if (screen
->doWorkspaceWarping()) {
2957 // workspace warping
2959 unsigned int dest
= screen
->getCurrentWorkspaceID();
2963 if (dest
> 0) dest
--;
2964 else dest
= screen
->getNumberOfWorkspaces() - 1;
2966 } else if (x_root
>= screen
->getRect().right()) {
2969 if (dest
< screen
->getNumberOfWorkspaces() - 1) dest
++;
2974 bool focus
= flags
.focused
; // had focus while moving?
2976 screen
->reassociateWindow(this, dest
, False
);
2977 screen
->changeWorkspaceID(dest
);
2982 If the XWarpPointer is done after the configure, we can end up
2983 grabbing another window, so made sure you do it first.
2987 dest_x
= screen
->getRect().right() - 1;
2988 XWarpPointer(blackbox
->getXDisplay(), None
,
2989 screen
->getRootWindow(), 0, 0, 0, 0,
2992 configure(dx
+ (screen
->getRect().width() - 1), dy
,
2993 frame
.rect
.width(), frame
.rect
.height());
2996 XWarpPointer(blackbox
->getXDisplay(), None
,
2997 screen
->getRootWindow(), 0, 0, 0, 0,
3000 configure(dx
- (screen
->getRect().width() - 1), dy
,
3001 frame
.rect
.width(), frame
.rect
.height());
3004 beginMove(dest_x
, y_root
);
3009 const int snap_distance
= screen
->getEdgeSnapThreshold();
3011 if (snap_distance
) {
3013 const int wleft
= dx
,
3014 wright
= dx
+ frame
.rect
.width() - 1,
3016 wbottom
= dy
+ frame
.rect
.height() - 1;
3018 if (screen
->getWindowToWindowSnap()) {
3019 Workspace
*w
= screen
->getWorkspace(getWorkspaceNumber());
3022 // try snap to another window
3023 for (unsigned int i
= 0, c
= w
->getCount(); i
< c
; ++i
) {
3024 BlackboxWindow
*snapwin
= w
->getWindow(i
);
3025 if (snapwin
== this)
3026 continue; // don't snap to self
3028 bool snapped
= False
;
3030 const Rect
&winrect
= snapwin
->frameRect();
3031 int dleft
= std::abs(wright
- winrect
.left()),
3032 dright
= std::abs(wleft
- winrect
.right()),
3033 dtop
= std::abs(wbottom
- winrect
.top()),
3034 dbottom
= std::abs(wtop
- winrect
.bottom());
3036 if (wtop
>= (signed)(winrect
.y() - frame
.rect
.height() + 1) &&
3037 wtop
< (signed)(winrect
.y() + winrect
.height() - 1)) {
3039 // snap left of other window?
3040 if (dleft
< snap_distance
&& dleft
<= dright
) {
3041 dx
= winrect
.left() - frame
.rect
.width();
3044 // snap right of other window?
3045 else if (dright
< snap_distance
) {
3046 dx
= winrect
.right() + 1;
3051 if (screen
->getWindowCornerSnap()) {
3052 // try corner-snap to its other sides
3053 dtop
= std::abs(wtop
- winrect
.top());
3054 dbottom
= std::abs(wbottom
- winrect
.bottom());
3055 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3057 else if (dbottom
< snap_distance
)
3058 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
3065 if (wleft
>= (signed)(winrect
.x() - frame
.rect
.width() + 1) &&
3066 wleft
< (signed)(winrect
.x() + winrect
.width() - 1)) {
3068 // snap top of other window?
3069 if (dtop
< snap_distance
&& dtop
<= dbottom
) {
3070 dy
= winrect
.top() - frame
.rect
.height();
3073 // snap bottom of other window?
3074 else if (dbottom
< snap_distance
) {
3075 dy
= winrect
.bottom() + 1;
3080 if (screen
->getWindowCornerSnap()) {
3081 // try corner-snap to its other sides
3082 dleft
= std::abs(wleft
- winrect
.left());
3083 dright
= std::abs(wright
- winrect
.right());
3084 if (dleft
< snap_distance
&& dleft
<= dright
)
3085 dx
= winrect
.left();
3086 else if (dright
< snap_distance
)
3087 dx
= winrect
.right() - frame
.rect
.width() + 1;
3096 RectList snaplist
; // the list of rects we will try to snap to
3098 // snap to the strut (and screen boundaries for xinerama)
3100 if (screen
->isXineramaActive() && blackbox
->doXineramaSnapping()) {
3101 if (! screen
->doFullMax())
3102 snaplist
.insert(snaplist
.begin(),
3103 screen
->allAvailableAreas().begin(),
3104 screen
->allAvailableAreas().end());
3106 // always snap to the screen edges
3107 snaplist
.insert(snaplist
.begin(),
3108 screen
->getXineramaAreas().begin(),
3109 screen
->getXineramaAreas().end());
3113 if (! screen
->doFullMax())
3114 snaplist
.push_back(screen
->availableArea());
3116 // always snap to the screen edges
3117 snaplist
.push_back(screen
->getRect());
3120 RectList::const_iterator it
, end
= snaplist
.end();
3121 for (it
= snaplist
.begin(); it
!= end
; ++it
) {
3122 const Rect
&srect
= *it
;
3124 // if we're not in the rectangle then don't snap to it.
3125 if (! srect
.intersects(Rect(wleft
, wtop
, frame
.rect
.width(),
3126 frame
.rect
.height())))
3129 int dleft
= std::abs(wleft
- srect
.left()),
3130 dright
= std::abs(wright
- srect
.right()),
3131 dtop
= std::abs(wtop
- srect
.top()),
3132 dbottom
= std::abs(wbottom
- srect
.bottom());
3135 if (dleft
< snap_distance
&& dleft
<= dright
)
3138 else if (dright
< snap_distance
)
3139 dx
= srect
.right() - frame
.rect
.width() + 1;
3142 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3145 else if (dbottom
< snap_distance
)
3146 dy
= srect
.bottom() - frame
.rect
.height() + 1;
3150 if (screen
->doOpaqueMove()) {
3151 configure(dx
, dy
, frame
.rect
.width(), frame
.rect
.height());
3153 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3157 frame
.changing
.width() - 1,
3158 frame
.changing
.height() - 1);
3160 frame
.changing
.setPos(dx
, dy
);
3162 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3166 frame
.changing
.width() - 1,
3167 frame
.changing
.height() - 1);
3170 screen
->showPosition(dx
, dy
);
3174 void BlackboxWindow::endMove(void) {
3175 assert(flags
.moving
);
3176 assert(blackbox
->getChangingWindow() == this);
3178 flags
.moving
= False
;
3179 blackbox
->setChangingWindow(0);
3181 if (! screen
->doOpaqueMove()) {
3182 /* when drawing the rubber band, we need to make sure we only draw inside
3183 * the frame... frame.changing_* contain the new coords for the window,
3184 * so we need to subtract 1 from changing_w/changing_h every where we
3185 * draw the rubber band (for both moving and resizing)
3187 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3188 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3189 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3190 XUngrabServer(blackbox
->getXDisplay());
3192 configure(frame
.changing
.x(), frame
.changing
.y(),
3193 frame
.changing
.width(), frame
.changing
.height());
3195 configure(frame
.rect
.x(), frame
.rect
.y(),
3196 frame
.rect
.width(), frame
.rect
.height());
3198 screen
->hideGeometry();
3200 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3202 // if there are any left over motions from the move, drop them now
3203 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3205 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3210 void BlackboxWindow::beginResize(int x_root
, int y_root
, Corner dir
) {
3211 assert(! (flags
.resizing
|| flags
.moving
));
3214 Only one window can be moved/resized at a time. If another window is already
3215 being moved or resized, then stop it before whating to work with this one.
3217 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3218 if (changing
&& changing
!= this) {
3219 if (changing
->flags
.moving
)
3220 changing
->endMove();
3221 else // if (changing->flags.resizing)
3222 changing
->endResize();
3230 switch (resize_dir
) {
3233 cursor
= blackbox
->getLowerLeftAngleCursor();
3238 cursor
= blackbox
->getLowerRightAngleCursor();
3242 anchor
= BottomRight
;
3243 cursor
= blackbox
->getUpperLeftAngleCursor();
3247 anchor
= BottomLeft
;
3248 cursor
= blackbox
->getUpperRightAngleCursor();
3252 assert(false); // unhandled Corner
3253 return; // unreachable, for the compiler
3256 XGrabServer(blackbox
->getXDisplay());
3257 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3258 PointerMotionMask
| ButtonReleaseMask
,
3259 GrabModeAsync
, GrabModeAsync
, None
, cursor
, CurrentTime
);
3261 flags
.resizing
= True
;
3262 blackbox
->setChangingWindow(this);
3265 frame
.changing
= frame
.rect
;
3267 constrain(anchor
, &gw
, &gh
);
3269 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3270 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3271 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3273 screen
->showGeometry(gw
, gh
);
3275 frame
.grab_x
= x_root
;
3276 frame
.grab_y
= y_root
;
3280 void BlackboxWindow::doResize(int x_root
, int y_root
) {
3281 assert(flags
.resizing
);
3282 assert(blackbox
->getChangingWindow() == this);
3284 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3285 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3286 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3291 switch (resize_dir
) {
3294 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3295 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3299 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3300 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3303 anchor
= BottomRight
;
3304 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3305 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3308 anchor
= BottomLeft
;
3309 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3310 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3314 assert(false); // unhandled Corner
3315 return; // unreachable, for the compiler
3318 constrain(anchor
, &gw
, &gh
);
3320 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3321 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3322 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3324 screen
->showGeometry(gw
, gh
);
3328 void BlackboxWindow::endResize(void) {
3329 assert(flags
.resizing
);
3330 assert(blackbox
->getChangingWindow() == this);
3332 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3333 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3334 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3335 XUngrabServer(blackbox
->getXDisplay());
3337 // unset maximized state after resized when fully maximized
3338 if (flags
.maximized
== 1)
3341 flags
.resizing
= False
;
3342 blackbox
->setChangingWindow(0);
3344 configure(frame
.changing
.x(), frame
.changing
.y(),
3345 frame
.changing
.width(), frame
.changing
.height());
3346 screen
->hideGeometry();
3348 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3350 // if there are any left over motions from the resize, drop them now
3351 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3353 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3358 void BlackboxWindow::motionNotifyEvent(const XMotionEvent
*me
) {
3360 fprintf(stderr
, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n",
3365 doMove(me
->x_root
, me
->y_root
);
3366 } else if (flags
.resizing
) {
3367 doResize(me
->x_root
, me
->y_root
);
3369 if (!flags
.resizing
&& me
->state
& Button1Mask
&& (functions
& Func_Move
) &&
3370 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3371 frame
.handle
== me
->window
|| frame
.window
== me
->window
)) {
3372 beginMove(me
->x_root
, me
->y_root
);
3373 } else if ((functions
& Func_Resize
) &&
3374 (me
->state
& Button1Mask
&& (me
->window
== frame
.right_grip
||
3375 me
->window
== frame
.left_grip
)) ||
3376 (me
->state
& Button3Mask
&& me
->state
& ModMask
&&
3377 me
->window
== frame
.window
)) {
3378 unsigned int zones
= screen
->getResizeZones();
3381 if (me
->window
== frame
.left_grip
) {
3382 corner
= BottomLeft
;
3383 } else if (me
->window
== frame
.right_grip
|| zones
== 1) {
3384 corner
= BottomRight
;
3387 bool left
= (me
->x_root
- frame
.rect
.x() <=
3388 static_cast<signed>(frame
.rect
.width() / 2));
3391 else // (zones == 4)
3392 top
= (me
->y_root
- frame
.rect
.y() <=
3393 static_cast<signed>(frame
.rect
.height() / 2));
3394 corner
= (top
? (left
? TopLeft
: TopRight
) :
3395 (left
? BottomLeft
: BottomRight
));
3398 beginResize(me
->x_root
, me
->y_root
, corner
);
3405 void BlackboxWindow::shapeEvent(XShapeEvent
*) {
3406 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
3413 bool BlackboxWindow::validateClient(void) const {
3414 XSync(blackbox
->getXDisplay(), False
);
3417 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3418 DestroyNotify
, &e
) ||
3419 XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3421 XPutBackEvent(blackbox
->getXDisplay(), &e
);
3430 void BlackboxWindow::restore(bool remap
) {
3431 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeDelete
);
3432 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
3433 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, NoEventMask
);
3435 // do not leave a shaded window as an icon unless it was an icon
3436 if (flags
.shaded
&& ! flags
.iconic
) setState(NormalState
);
3438 restoreGravity(client
.rect
);
3440 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
3441 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
3443 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, client
.old_bw
);
3446 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3447 ReparentNotify
, &ev
)) {
3450 // according to the ICCCM - if the client doesn't reparent to
3451 // root, then we have to do it for them
3452 XReparentWindow(blackbox
->getXDisplay(), client
.window
,
3453 screen
->getRootWindow(),
3454 client
.rect
.x(), client
.rect
.y());
3457 if (remap
) XMapWindow(blackbox
->getXDisplay(), client
.window
);
3461 // timer for autoraise
3462 void BlackboxWindow::timeout(void) {
3463 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3467 void BlackboxWindow::changeBlackboxHints(BlackboxHints
*net
) {
3468 if ((net
->flags
& AttribShaded
) &&
3469 ((blackbox_attrib
.attrib
& AttribShaded
) !=
3470 (net
->attrib
& AttribShaded
)))
3473 if (flags
.visible
&& // watch out for requests when we can not be seen
3474 (net
->flags
& (AttribMaxVert
| AttribMaxHoriz
)) &&
3475 ((blackbox_attrib
.attrib
& (AttribMaxVert
| AttribMaxHoriz
)) !=
3476 (net
->attrib
& (AttribMaxVert
| AttribMaxHoriz
)))) {
3477 if (flags
.maximized
) {
3482 if ((net
->flags
& AttribMaxHoriz
) && (net
->flags
& AttribMaxVert
))
3483 button
= ((net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0);
3484 else if (net
->flags
& AttribMaxVert
)
3485 button
= ((net
->attrib
& AttribMaxVert
) ? 2 : 0);
3486 else if (net
->flags
& AttribMaxHoriz
)
3487 button
= ((net
->attrib
& AttribMaxHoriz
) ? 3 : 0);
3493 if ((net
->flags
& AttribOmnipresent
) &&
3494 ((blackbox_attrib
.attrib
& AttribOmnipresent
) !=
3495 (net
->attrib
& AttribOmnipresent
)))
3498 if ((net
->flags
& AttribWorkspace
) &&
3499 (blackbox_attrib
.workspace
!= net
->workspace
)) {
3500 screen
->reassociateWindow(this, net
->workspace
, True
);
3502 if (screen
->getCurrentWorkspaceID() != net
->workspace
) {
3506 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3510 if (net
->flags
& AttribDecoration
) {
3511 switch (net
->decoration
) {
3513 // clear all decorations except close
3514 decorations
&= Decor_Close
;
3520 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Iconify
;
3522 decorations
= ((functions
& Func_Resize
) && !isTransient() ?
3523 decorations
| Decor_Handle
:
3524 decorations
&= ~Decor_Handle
);
3525 decorations
= (functions
& Func_Maximize
?
3526 decorations
| Decor_Maximize
:
3527 decorations
&= ~Decor_Maximize
);
3532 decorations
|= Decor_Titlebar
| Decor_Iconify
;
3533 decorations
&= ~(Decor_Border
| Decor_Handle
);
3535 decorations
= (functions
& Func_Maximize
?
3536 decorations
| Decor_Maximize
:
3537 decorations
&= ~Decor_Maximize
);
3542 decorations
|= Decor_Titlebar
;
3543 decorations
&= ~(Decor_Iconify
| Decor_Border
);
3545 decorations
= ((functions
& Func_Resize
) && !isTransient() ?
3546 decorations
| Decor_Handle
:
3547 decorations
&= ~Decor_Handle
);
3548 decorations
= (functions
& Func_Maximize
?
3549 decorations
| Decor_Maximize
:
3550 decorations
&= ~Decor_Maximize
);
3555 // we can not be shaded if we lack a titlebar
3556 if (flags
.shaded
&& ! (decorations
& Decor_Titlebar
))
3559 if (flags
.visible
&& frame
.window
) {
3560 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
3561 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
3565 setState(current_state
);
3571 * Set the sizes of all components of the window frame
3572 * (the window decorations).
3573 * These values are based upon the current style settings and the client
3574 * window's dimensions.
3576 void BlackboxWindow::upsize(void) {
3577 frame
.bevel_w
= screen
->getBevelWidth();
3579 if (decorations
& Decor_Border
) {
3580 frame
.border_w
= screen
->getBorderWidth();
3581 if (! isTransient())
3582 frame
.mwm_border_w
= screen
->getFrameWidth();
3584 frame
.mwm_border_w
= 0;
3586 frame
.mwm_border_w
= frame
.border_w
= 0;
3589 if (decorations
& Decor_Titlebar
) {
3590 // the height of the titlebar is based upon the height of the font being
3591 // used to display the window's title
3592 WindowStyle
*style
= screen
->getWindowStyle();
3593 frame
.title_h
= style
->font
->height() + (frame
.bevel_w
* 2) + 2;
3595 frame
.label_h
= frame
.title_h
- (frame
.bevel_w
* 2);
3596 frame
.button_w
= (frame
.label_h
- 2);
3598 // set the top frame margin
3599 frame
.margin
.top
= frame
.border_w
+ frame
.title_h
+
3600 frame
.border_w
+ frame
.mwm_border_w
;
3606 // set the top frame margin
3607 frame
.margin
.top
= frame
.border_w
+ frame
.mwm_border_w
;
3610 // set the left/right frame margin
3611 frame
.margin
.left
= frame
.margin
.right
= frame
.border_w
+ frame
.mwm_border_w
;
3613 if (decorations
& Decor_Handle
) {
3614 frame
.grip_w
= frame
.button_w
* 2;
3615 frame
.handle_h
= screen
->getHandleWidth();
3617 // set the bottom frame margin
3618 frame
.margin
.bottom
= frame
.border_w
+ frame
.handle_h
+
3619 frame
.border_w
+ frame
.mwm_border_w
;
3624 // set the bottom frame margin
3625 frame
.margin
.bottom
= frame
.border_w
+ frame
.mwm_border_w
;
3629 We first get the normal dimensions and use this to define the inside_w/h
3630 then we modify the height if shading is in effect.
3631 If the shade state is not considered then frame.rect gets reset to the
3632 normal window size on a reconfigure() call resulting in improper
3633 dimensions appearing in move/resize and other events.
3636 height
= client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
,
3637 width
= client
.rect
.width() + frame
.margin
.left
+ frame
.margin
.right
;
3639 frame
.inside_w
= width
- (frame
.border_w
* 2);
3640 frame
.inside_h
= height
- (frame
.border_w
* 2);
3643 height
= frame
.title_h
+ (frame
.border_w
* 2);
3644 frame
.rect
.setSize(width
, height
);
3649 * Calculate the size of the client window and constrain it to the
3650 * size specified by the size hints of the client window.
3652 * The logical width and height are placed into pw and ph, if they
3653 * are non-zero. Logical size refers to the users perception of
3654 * the window size (for example an xterm resizes in cells, not in pixels).
3656 * The physical geometry is placed into frame.changing_{x,y,width,height}.
3657 * Physical geometry refers to the geometry of the window in pixels.
3659 void BlackboxWindow::constrain(Corner anchor
, int *pw
, int *ph
) {
3660 // frame.changing represents the requested frame size, we need to
3661 // strip the frame margin off and constrain the client size
3662 frame
.changing
.setCoords(frame
.changing
.left() + frame
.margin
.left
,
3663 frame
.changing
.top() + frame
.margin
.top
,
3664 frame
.changing
.right() - frame
.margin
.right
,
3665 frame
.changing
.bottom() - frame
.margin
.bottom
);
3667 int dw
= frame
.changing
.width(), dh
= frame
.changing
.height(),
3668 base_width
= (client
.base_width
) ? client
.base_width
: client
.min_width
,
3669 base_height
= (client
.base_height
) ? client
.base_height
:
3673 if (dw
< static_cast<signed>(client
.min_width
)) dw
= client
.min_width
;
3674 if (dh
< static_cast<signed>(client
.min_height
)) dh
= client
.min_height
;
3675 if (dw
> static_cast<signed>(client
.max_width
)) dw
= client
.max_width
;
3676 if (dh
> static_cast<signed>(client
.max_height
)) dh
= client
.max_height
;
3679 dw
/= client
.width_inc
;
3681 dh
/= client
.height_inc
;
3684 if (client
.width_inc
== 1)
3685 *pw
= dw
+ base_width
;
3690 if (client
.height_inc
== 1)
3691 *ph
= dh
+ base_height
;
3696 dw
*= client
.width_inc
;
3698 dh
*= client
.height_inc
;
3701 frame
.changing
.setSize(dw
, dh
);
3703 // add the frame margin back onto frame.changing
3704 frame
.changing
.setCoords(frame
.changing
.left() - frame
.margin
.left
,
3705 frame
.changing
.top() - frame
.margin
.top
,
3706 frame
.changing
.right() + frame
.margin
.right
,
3707 frame
.changing
.bottom() + frame
.margin
.bottom
);
3709 // move frame.changing to the specified anchor
3717 dx
= frame
.rect
.right() - frame
.changing
.right();
3721 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3725 dx
= frame
.rect
.right() - frame
.changing
.right();
3726 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3730 assert(false); // unhandled corner
3732 frame
.changing
.setPos(frame
.changing
.x() + dx
, frame
.changing
.y() + dy
);
3736 void WindowStyle::doJustify(const std::string
&text
, int &start_pos
,
3737 unsigned int max_length
,
3738 unsigned int modifier
) const {
3739 size_t text_len
= text
.size();
3740 unsigned int length
;
3743 length
= font
->measureString(string(text
, 0, text_len
)) + modifier
;
3744 } while (length
> max_length
&& text_len
-- > 0);
3748 start_pos
+= max_length
- length
;
3752 start_pos
+= (max_length
- length
) / 2;
3762 BWindowGroup::BWindowGroup(Blackbox
*b
, Window _group
)
3763 : blackbox(b
), group(_group
) {
3764 XWindowAttributes wattrib
;
3765 if (! XGetWindowAttributes(blackbox
->getXDisplay(), group
, &wattrib
)) {
3766 // group window doesn't seem to exist anymore
3771 XSelectInput(blackbox
->getXDisplay(), group
,
3772 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
3774 blackbox
->saveGroupSearch(group
, this);
3778 BWindowGroup::~BWindowGroup(void) {
3779 blackbox
->removeGroupSearch(group
);
3784 BWindowGroup::find(BScreen
*screen
, bool allow_transients
) const {
3785 BlackboxWindow
*ret
= blackbox
->getFocusedWindow();
3787 // does the focus window match (or any transient_fors)?
3789 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3790 if (ret
->isTransient() && allow_transients
) break;
3791 else if (! ret
->isTransient()) break;
3794 ret
= ret
->getTransientFor();
3797 if (ret
) return ret
;
3799 // the focus window didn't match, look in the group's window list
3800 BlackboxWindowList::const_iterator it
, end
= windowList
.end();
3801 for (it
= windowList
.begin(); it
!= end
; ++it
) {
3803 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3804 if (ret
->isTransient() && allow_transients
) break;
3805 else if (! ret
->isTransient()) break;