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 /* we could set the focus to none, since the window doesn't accept focus,
1587 * but we shouldn't set focus to nothing since this would surely make
1593 if (flags
.send_focus_message
) {
1595 ce
.xclient
.type
= ClientMessage
;
1596 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1597 ce
.xclient
.display
= blackbox
->getXDisplay();
1598 ce
.xclient
.window
= client
.window
;
1599 ce
.xclient
.format
= 32;
1600 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_take_focus
);
1601 ce
.xclient
.data
.l
[1] = blackbox
->getLastTime();
1602 ce
.xclient
.data
.l
[2] = 0l;
1603 ce
.xclient
.data
.l
[3] = 0l;
1604 ce
.xclient
.data
.l
[4] = 0l;
1605 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1607 XFlush(blackbox
->getXDisplay());
1614 void BlackboxWindow::iconify(void) {
1615 if (flags
.iconic
) return;
1617 // We don't need to worry about resizing because resizing always grabs the X
1618 // server. This should only ever happen if using opaque moving.
1622 if (windowmenu
) windowmenu
->hide();
1625 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1626 * we need to clear the event mask on client.window for a split second.
1627 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1628 * split second, leaving us with a ghost window... so, we need to do this
1629 * while the X server is grabbed
1631 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1632 StructureNotifyMask
;
1633 XGrabServer(blackbox
->getXDisplay());
1634 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1635 event_mask
& ~StructureNotifyMask
);
1636 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1637 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1638 XUngrabServer(blackbox
->getXDisplay());
1640 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1641 flags
.visible
= False
;
1642 flags
.iconic
= True
;
1644 setState(IconicState
);
1646 screen
->getWorkspace(blackbox_attrib
.workspace
)->removeWindow(this);
1648 if (isTransient()) {
1649 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1650 ! client
.transient_for
->flags
.iconic
) {
1651 // iconify our transient_for
1652 client
.transient_for
->iconify();
1656 screen
->addIcon(this);
1658 if (client
.transientList
.size() > 0) {
1659 // iconify all transients
1660 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1661 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1662 if (! (*it
)->flags
.iconic
) (*it
)->iconify();
1665 screen
->updateStackingList();
1669 void BlackboxWindow::show(void) {
1670 flags
.visible
= True
;
1671 flags
.iconic
= False
;
1673 current_state
= (flags
.shaded
) ? IconicState
: NormalState
;
1674 setState(current_state
);
1676 XMapWindow(blackbox
->getXDisplay(), client
.window
);
1677 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
1678 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
1683 XTranslateCoordinates(blackbox
->getXDisplay(), client
.window
,
1684 screen
->getRootWindow(),
1685 0, 0, &real_x
, &real_y
, &child
);
1686 fprintf(stderr
, "%s -- assumed: (%d, %d), real: (%d, %d)\n", getTitle(),
1687 client
.rect
.left(), client
.rect
.top(), real_x
, real_y
);
1688 assert(client
.rect
.left() == real_x
&& client
.rect
.top() == real_y
);
1693 void BlackboxWindow::deiconify(bool reassoc
, bool raise
) {
1694 if (flags
.iconic
|| reassoc
)
1695 screen
->reassociateWindow(this, BSENTINEL
, False
);
1696 else if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID())
1701 // reassociate and deiconify all transients
1702 if (reassoc
&& client
.transientList
.size() > 0) {
1703 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1704 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1705 (*it
)->deiconify(True
, False
);
1710 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1714 void BlackboxWindow::close(void) {
1716 ce
.xclient
.type
= ClientMessage
;
1717 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1718 ce
.xclient
.display
= blackbox
->getXDisplay();
1719 ce
.xclient
.window
= client
.window
;
1720 ce
.xclient
.format
= 32;
1721 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_delete_window
);
1722 ce
.xclient
.data
.l
[1] = CurrentTime
;
1723 ce
.xclient
.data
.l
[2] = 0l;
1724 ce
.xclient
.data
.l
[3] = 0l;
1725 ce
.xclient
.data
.l
[4] = 0l;
1726 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
, NoEventMask
, &ce
);
1727 XFlush(blackbox
->getXDisplay());
1731 void BlackboxWindow::withdraw(void) {
1732 // We don't need to worry about resizing because resizing always grabs the X
1733 // server. This should only ever happen if using opaque moving.
1737 flags
.visible
= False
;
1738 flags
.iconic
= False
;
1740 setState(current_state
);
1742 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1744 XGrabServer(blackbox
->getXDisplay());
1746 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1747 StructureNotifyMask
;
1748 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1749 event_mask
& ~StructureNotifyMask
);
1750 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1751 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1753 XUngrabServer(blackbox
->getXDisplay());
1755 if (windowmenu
) windowmenu
->hide();
1759 void BlackboxWindow::maximize(unsigned int button
) {
1760 // We don't need to worry about resizing because resizing always grabs the X
1761 // server. This should only ever happen if using opaque moving.
1765 // handle case where menu is open then the max button is used instead
1766 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
1768 if (flags
.maximized
) {
1769 flags
.maximized
= 0;
1771 blackbox_attrib
.flags
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1772 blackbox_attrib
.attrib
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1775 when a resize finishes, maximize(0) is called to clear any maximization
1776 flags currently set. Otherwise it still thinks it is maximized.
1777 so we do not need to call configure() because resizing will handle it
1779 if (! flags
.resizing
)
1780 configure(blackbox_attrib
.premax_x
, blackbox_attrib
.premax_y
,
1781 blackbox_attrib
.premax_w
, blackbox_attrib
.premax_h
);
1783 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
1784 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
1786 redrawAllButtons(); // in case it is not called in configure()
1787 setState(current_state
);
1791 blackbox_attrib
.premax_x
= frame
.rect
.x();
1792 blackbox_attrib
.premax_y
= frame
.rect
.y();
1793 blackbox_attrib
.premax_w
= frame
.rect
.width();
1794 // use client.rect so that clients can be restored even if shaded
1795 blackbox_attrib
.premax_h
=
1796 client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
;
1799 if (screen
->isXineramaActive() && blackbox
->doXineramaMaximizing()) {
1800 // find the area to use
1801 RectList availableAreas
= screen
->allAvailableAreas();
1802 RectList::iterator it
, end
= availableAreas
.end();
1804 for (it
= availableAreas
.begin(); it
!= end
; ++it
)
1805 if (it
->intersects(frame
.rect
)) break;
1806 if (it
== end
) // the window isn't inside an area
1807 it
= availableAreas
.begin(); // so just default to the first one
1809 frame
.changing
= *it
;
1812 frame
.changing
= screen
->availableArea();
1816 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1817 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1821 blackbox_attrib
.flags
|= AttribMaxVert
;
1822 blackbox_attrib
.attrib
|= AttribMaxVert
;
1824 frame
.changing
.setX(frame
.rect
.x());
1825 frame
.changing
.setWidth(frame
.rect
.width());
1829 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1830 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1832 frame
.changing
.setY(frame
.rect
.y());
1833 frame
.changing
.setHeight(frame
.rect
.height());
1840 blackbox_attrib
.flags
^= AttribShaded
;
1841 blackbox_attrib
.attrib
^= AttribShaded
;
1842 flags
.shaded
= False
;
1845 flags
.maximized
= button
;
1847 configure(frame
.changing
.x(), frame
.changing
.y(),
1848 frame
.changing
.width(), frame
.changing
.height());
1850 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1851 redrawAllButtons(); // in case it is not called in configure()
1852 setState(current_state
);
1856 // re-maximizes the window to take into account availableArea changes
1857 void BlackboxWindow::remaximize(void) {
1858 // save the original dimensions because maximize will wipe them out
1859 int premax_x
= blackbox_attrib
.premax_x
,
1860 premax_y
= blackbox_attrib
.premax_y
,
1861 premax_w
= blackbox_attrib
.premax_w
,
1862 premax_h
= blackbox_attrib
.premax_h
;
1864 unsigned int button
= flags
.maximized
;
1865 flags
.maximized
= 0; // trick maximize() into working
1868 // restore saved values
1869 blackbox_attrib
.premax_x
= premax_x
;
1870 blackbox_attrib
.premax_y
= premax_y
;
1871 blackbox_attrib
.premax_w
= premax_w
;
1872 blackbox_attrib
.premax_h
= premax_h
;
1876 void BlackboxWindow::setWorkspace(unsigned int n
) {
1877 blackbox_attrib
.flags
|= AttribWorkspace
;
1878 blackbox_attrib
.workspace
= n
;
1879 if (n
== BSENTINEL
) { // iconified window
1881 we set the workspace to 'all workspaces' so that taskbars will show the
1882 window. otherwise, it made uniconifying a window imposible without the
1883 blackbox workspace menu
1887 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
, n
);
1891 void BlackboxWindow::shade(void) {
1893 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1894 frame
.inside_w
, frame
.inside_h
);
1895 flags
.shaded
= False
;
1896 blackbox_attrib
.flags
^= AttribShaded
;
1897 blackbox_attrib
.attrib
^= AttribShaded
;
1899 setState(NormalState
);
1901 // set the frame rect to the normal size
1902 frame
.rect
.setHeight(client
.rect
.height() + frame
.margin
.top
+
1903 frame
.margin
.bottom
);
1905 if (! (decorations
& Decor_Titlebar
))
1906 return; // can't shade it without a titlebar!
1908 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1909 frame
.inside_w
, frame
.title_h
);
1910 flags
.shaded
= True
;
1911 blackbox_attrib
.flags
|= AttribShaded
;
1912 blackbox_attrib
.attrib
|= AttribShaded
;
1914 setState(IconicState
);
1916 // set the frame rect to the shaded size
1917 frame
.rect
.setHeight(frame
.title_h
+ (frame
.border_w
* 2));
1923 * (Un)Sticks a window and its relatives.
1925 void BlackboxWindow::stick(void) {
1927 blackbox_attrib
.flags
^= AttribOmnipresent
;
1928 blackbox_attrib
.attrib
^= AttribOmnipresent
;
1930 flags
.stuck
= False
;
1933 screen
->reassociateWindow(this, BSENTINEL
, True
);
1934 // temporary fix since sticky windows suck. set the hint to what we
1935 // actually hold in our data.
1936 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1937 blackbox_attrib
.workspace
);
1939 setState(current_state
);
1943 blackbox_attrib
.flags
|= AttribOmnipresent
;
1944 blackbox_attrib
.attrib
|= AttribOmnipresent
;
1946 // temporary fix since sticky windows suck. set the hint to a different
1947 // value than that contained in the class' data.
1948 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1951 setState(current_state
);
1954 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1955 client
.transient_for
->isStuck() != flags
.stuck
)
1956 client
.transient_for
->stick();
1957 // go down the chain
1958 BlackboxWindowList::iterator it
;
1959 const BlackboxWindowList::iterator end
= client
.transientList
.end();
1960 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1961 if ((*it
)->isStuck() != flags
.stuck
)
1966 void BlackboxWindow::redrawWindowFrame(void) const {
1967 if (decorations
& Decor_Titlebar
) {
1968 if (flags
.focused
) {
1970 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1971 frame
.title
, frame
.ftitle
);
1973 XSetWindowBackground(blackbox
->getXDisplay(),
1974 frame
.title
, frame
.ftitle_pixel
);
1977 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1978 frame
.title
, frame
.utitle
);
1980 XSetWindowBackground(blackbox
->getXDisplay(),
1981 frame
.title
, frame
.utitle_pixel
);
1983 XClearWindow(blackbox
->getXDisplay(), frame
.title
);
1989 if (decorations
& Decor_Handle
) {
1990 if (flags
.focused
) {
1992 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1993 frame
.handle
, frame
.fhandle
);
1995 XSetWindowBackground(blackbox
->getXDisplay(),
1996 frame
.handle
, frame
.fhandle_pixel
);
1999 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2000 frame
.left_grip
, frame
.fgrip
);
2001 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2002 frame
.right_grip
, frame
.fgrip
);
2004 XSetWindowBackground(blackbox
->getXDisplay(),
2005 frame
.left_grip
, frame
.fgrip_pixel
);
2006 XSetWindowBackground(blackbox
->getXDisplay(),
2007 frame
.right_grip
, frame
.fgrip_pixel
);
2011 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2012 frame
.handle
, frame
.uhandle
);
2014 XSetWindowBackground(blackbox
->getXDisplay(),
2015 frame
.handle
, frame
.uhandle_pixel
);
2018 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2019 frame
.left_grip
, frame
.ugrip
);
2020 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2021 frame
.right_grip
, frame
.ugrip
);
2023 XSetWindowBackground(blackbox
->getXDisplay(),
2024 frame
.left_grip
, frame
.ugrip_pixel
);
2025 XSetWindowBackground(blackbox
->getXDisplay(),
2026 frame
.right_grip
, frame
.ugrip_pixel
);
2029 XClearWindow(blackbox
->getXDisplay(), frame
.handle
);
2030 XClearWindow(blackbox
->getXDisplay(), frame
.left_grip
);
2031 XClearWindow(blackbox
->getXDisplay(), frame
.right_grip
);
2034 if (decorations
& Decor_Border
) {
2036 XSetWindowBorder(blackbox
->getXDisplay(),
2037 frame
.plate
, frame
.fborder_pixel
);
2039 XSetWindowBorder(blackbox
->getXDisplay(),
2040 frame
.plate
, frame
.uborder_pixel
);
2045 void BlackboxWindow::setFocusFlag(bool focus
) {
2046 // only focus a window if it is visible
2047 if (focus
&& !flags
.visible
)
2050 flags
.focused
= focus
;
2052 redrawWindowFrame();
2054 if (screen
->isSloppyFocus() && screen
->doAutoRaise()) {
2055 if (isFocused()) timer
->start();
2060 blackbox
->setFocusedWindow(this);
2062 if (! flags
.iconic
) {
2063 // iconic windows arent in a workspace menu!
2065 screen
->getWorkspace(blackbox_attrib
.workspace
)->getMenu();
2066 menu
->setItemSelected(window_number
, isFocused());
2071 void BlackboxWindow::installColormap(bool install
) {
2072 int i
= 0, ncmap
= 0;
2073 Colormap
*cmaps
= XListInstalledColormaps(blackbox
->getXDisplay(),
2074 client
.window
, &ncmap
);
2076 XWindowAttributes wattrib
;
2077 if (XGetWindowAttributes(blackbox
->getXDisplay(),
2078 client
.window
, &wattrib
)) {
2080 // install the window's colormap
2081 for (i
= 0; i
< ncmap
; i
++) {
2082 if (*(cmaps
+ i
) == wattrib
.colormap
)
2083 // this window is using an installed color map... do not install
2086 // otherwise, install the window's colormap
2088 XInstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2090 // uninstall the window's colormap
2091 for (i
= 0; i
< ncmap
; i
++) {
2092 if (*(cmaps
+ i
) == wattrib
.colormap
)
2093 // we found the colormap to uninstall
2094 XUninstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2104 void BlackboxWindow::setAllowedActions(void) {
2108 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_shade
);
2109 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_change_desktop
);
2110 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_close
);
2112 if (functions
& Func_Move
)
2113 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_move
);
2114 if (functions
& Func_Resize
)
2115 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_resize
);
2116 if (functions
& Func_Maximize
) {
2117 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_horz
);
2118 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_vert
);
2121 xatom
->setValue(client
.window
, XAtom::net_wm_allowed_actions
, XAtom::atom
,
2126 void BlackboxWindow::setState(unsigned long new_state
) {
2127 current_state
= new_state
;
2129 unsigned long state
[2];
2130 state
[0] = current_state
;
2132 xatom
->setValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
, state
, 2);
2134 xatom
->setValue(client
.window
, XAtom::blackbox_attributes
,
2135 XAtom::blackbox_attributes
, (unsigned long *)&blackbox_attrib
,
2136 PropBlackboxAttributesElements
);
2141 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_modal
);
2143 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_shaded
);
2145 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_hidden
);
2146 if (flags
.skip_taskbar
)
2147 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
);
2148 if (flags
.skip_pager
)
2149 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_pager
);
2150 if (flags
.fullscreen
)
2151 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_fullscreen
);
2152 if (flags
.maximized
== 1 || flags
.maximized
== 2)
2153 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_vert
);
2154 if (flags
.maximized
== 1 || flags
.maximized
== 3)
2155 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_horz
);
2156 xatom
->setValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
2161 bool BlackboxWindow::getState(void) {
2162 bool ret
= xatom
->getValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
,
2164 if (! ret
) current_state
= 0;
2169 void BlackboxWindow::restoreAttributes(void) {
2170 unsigned long num
= PropBlackboxAttributesElements
;
2171 BlackboxAttributes
*net
;
2172 if (! xatom
->getValue(client
.window
, XAtom::blackbox_attributes
,
2173 XAtom::blackbox_attributes
, num
,
2174 (unsigned long **)&net
))
2176 if (num
< PropBlackboxAttributesElements
) {
2181 if (net
->flags
& AttribShaded
&& net
->attrib
& AttribShaded
) {
2182 flags
.shaded
= False
;
2183 unsigned long orig_state
= current_state
;
2187 At this point in the life of a window, current_state should only be set
2188 to IconicState if the window was an *icon*, not if it was shaded.
2190 if (orig_state
!= IconicState
)
2191 current_state
= WithdrawnState
;
2194 if (net
->workspace
!= screen
->getCurrentWorkspaceID() &&
2195 net
->workspace
< screen
->getWorkspaceCount())
2196 screen
->reassociateWindow(this, net
->workspace
, True
);
2198 if ((blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID()) &&
2199 (blackbox_attrib
.workspace
< screen
->getWorkspaceCount())) {
2200 // set to WithdrawnState so it will be mapped on the new workspace
2201 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2202 } else if (current_state
== WithdrawnState
) {
2203 // the window is on this workspace and is Withdrawn, so it is waiting to
2205 current_state
= NormalState
;
2208 if (net
->flags
& AttribOmnipresent
&& net
->attrib
& AttribOmnipresent
) {
2209 flags
.stuck
= False
;
2212 // if the window was on another workspace, it was going to be hidden. this
2213 // specifies that the window should be mapped since it is sticky.
2214 if (current_state
== WithdrawnState
) current_state
= NormalState
;
2217 if (net
->flags
& AttribMaxHoriz
|| net
->flags
& AttribMaxVert
) {
2218 int x
= net
->premax_x
, y
= net
->premax_y
;
2219 unsigned int w
= net
->premax_w
, h
= net
->premax_h
;
2220 flags
.maximized
= 0;
2223 if ((net
->flags
& AttribMaxHoriz
) &&
2224 (net
->flags
& AttribMaxVert
))
2225 m
= (net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
2226 else if (net
->flags
& AttribMaxVert
)
2227 m
= (net
->attrib
& AttribMaxVert
) ? 2 : 0;
2228 else if (net
->flags
& AttribMaxHoriz
)
2229 m
= (net
->attrib
& AttribMaxHoriz
) ? 3 : 0;
2233 blackbox_attrib
.premax_x
= x
;
2234 blackbox_attrib
.premax_y
= y
;
2235 blackbox_attrib
.premax_w
= w
;
2236 blackbox_attrib
.premax_h
= h
;
2239 // with the state set it will then be the map event's job to read the
2240 // window's state and behave accordingly
2247 * Positions the Rect r according the the client window position and
2250 void BlackboxWindow::applyGravity(Rect
&r
) {
2251 // apply horizontal window gravity
2252 switch (client
.win_gravity
) {
2254 case NorthWestGravity
:
2255 case SouthWestGravity
:
2257 r
.setX(client
.rect
.x());
2263 r
.setX(client
.rect
.x() - (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2266 case NorthEastGravity
:
2267 case SouthEastGravity
:
2269 r
.setX(client
.rect
.x() - frame
.margin
.left
- frame
.margin
.right
+ 2);
2274 r
.setX(client
.rect
.x() - frame
.margin
.left
);
2278 // apply vertical window gravity
2279 switch (client
.win_gravity
) {
2281 case NorthWestGravity
:
2282 case NorthEastGravity
:
2284 r
.setY(client
.rect
.y());
2290 r
.setY(client
.rect
.y() - (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2293 case SouthWestGravity
:
2294 case SouthEastGravity
:
2296 r
.setY(client
.rect
.y() - frame
.margin
.top
- frame
.margin
.bottom
+ 2);
2301 r
.setY(client
.rect
.y() - frame
.margin
.top
);
2308 * The reverse of the applyGravity function.
2310 * Positions the Rect r according to the frame window position and
2313 void BlackboxWindow::restoreGravity(Rect
&r
) {
2314 // restore horizontal window gravity
2315 switch (client
.win_gravity
) {
2317 case NorthWestGravity
:
2318 case SouthWestGravity
:
2320 r
.setX(frame
.rect
.x());
2326 r
.setX(frame
.rect
.x() + (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2329 case NorthEastGravity
:
2330 case SouthEastGravity
:
2332 r
.setX(frame
.rect
.x() + frame
.margin
.left
+ frame
.margin
.right
- 2);
2337 r
.setX(frame
.rect
.x() + frame
.margin
.left
);
2341 // restore vertical window gravity
2342 switch (client
.win_gravity
) {
2344 case NorthWestGravity
:
2345 case NorthEastGravity
:
2347 r
.setY(frame
.rect
.y());
2353 r
.setY(frame
.rect
.y() + (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2356 case SouthWestGravity
:
2357 case SouthEastGravity
:
2359 r
.setY(frame
.rect
.y() + frame
.margin
.top
+ frame
.margin
.bottom
- 2);
2364 r
.setY(frame
.rect
.y() + frame
.margin
.top
);
2370 void BlackboxWindow::redrawLabel(void) const {
2371 if (flags
.focused
) {
2373 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2374 frame
.label
, frame
.flabel
);
2376 XSetWindowBackground(blackbox
->getXDisplay(),
2377 frame
.label
, frame
.flabel_pixel
);
2380 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2381 frame
.label
, frame
.ulabel
);
2383 XSetWindowBackground(blackbox
->getXDisplay(),
2384 frame
.label
, frame
.ulabel_pixel
);
2386 XClearWindow(blackbox
->getXDisplay(), frame
.label
);
2388 WindowStyle
*style
= screen
->getWindowStyle();
2390 int pos
= frame
.bevel_w
* 2;
2391 style
->doJustify(client
.title
.c_str(), pos
, frame
.label_w
, frame
.bevel_w
* 4);
2392 style
->font
->drawString(frame
.label
, pos
, 1,
2393 (flags
.focused
? style
->l_text_focus
:
2394 style
->l_text_unfocus
),
2399 void BlackboxWindow::redrawAllButtons(void) const {
2400 if (frame
.iconify_button
) redrawIconifyButton(False
);
2401 if (frame
.maximize_button
) redrawMaximizeButton(flags
.maximized
);
2402 if (frame
.close_button
) redrawCloseButton(False
);
2406 void BlackboxWindow::redrawIconifyButton(bool pressed
) const {
2408 if (flags
.focused
) {
2410 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2411 frame
.iconify_button
, frame
.fbutton
);
2413 XSetWindowBackground(blackbox
->getXDisplay(),
2414 frame
.iconify_button
, frame
.fbutton_pixel
);
2417 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2418 frame
.iconify_button
, frame
.ubutton
);
2420 XSetWindowBackground(blackbox
->getXDisplay(), frame
.iconify_button
,
2421 frame
.ubutton_pixel
);
2425 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2426 frame
.iconify_button
, frame
.pbutton
);
2428 XSetWindowBackground(blackbox
->getXDisplay(),
2429 frame
.iconify_button
, frame
.pbutton_pixel
);
2431 XClearWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
2433 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2434 screen
->getWindowStyle()->b_pic_unfocus
);
2435 XDrawRectangle(blackbox
->getXDisplay(), frame
.iconify_button
, pen
.gc(),
2436 2, (frame
.button_w
- 5), (frame
.button_w
- 5), 2);
2440 void BlackboxWindow::redrawMaximizeButton(bool pressed
) const {
2442 if (flags
.focused
) {
2444 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2445 frame
.maximize_button
, frame
.fbutton
);
2447 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2448 frame
.fbutton_pixel
);
2451 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2452 frame
.maximize_button
, frame
.ubutton
);
2454 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2455 frame
.ubutton_pixel
);
2459 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2460 frame
.maximize_button
, frame
.pbutton
);
2462 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2463 frame
.pbutton_pixel
);
2465 XClearWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
2467 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2468 screen
->getWindowStyle()->b_pic_unfocus
);
2469 XDrawRectangle(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2470 2, 2, (frame
.button_w
- 5), (frame
.button_w
- 5));
2471 XDrawLine(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2472 2, 3, (frame
.button_w
- 3), 3);
2476 void BlackboxWindow::redrawCloseButton(bool pressed
) const {
2478 if (flags
.focused
) {
2480 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2483 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2484 frame
.fbutton_pixel
);
2487 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2490 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2491 frame
.ubutton_pixel
);
2495 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2496 frame
.close_button
, frame
.pbutton
);
2498 XSetWindowBackground(blackbox
->getXDisplay(),
2499 frame
.close_button
, frame
.pbutton_pixel
);
2501 XClearWindow(blackbox
->getXDisplay(), frame
.close_button
);
2503 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2504 screen
->getWindowStyle()->b_pic_unfocus
);
2505 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2506 2, 2, (frame
.button_w
- 3), (frame
.button_w
- 3));
2507 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2508 2, (frame
.button_w
- 3), (frame
.button_w
- 3), 2);
2512 void BlackboxWindow::mapRequestEvent(const XMapRequestEvent
*re
) {
2513 if (re
->window
!= client
.window
)
2517 fprintf(stderr
, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2521 switch (current_state
) {
2526 case WithdrawnState
:
2535 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2537 if (! blackbox
->isStartup()) {
2538 XSync(blackbox
->getXDisplay(), False
); // make sure the frame is mapped
2539 if (screen
->doFocusNew()|| (isTransient() && getTransientFor() &&
2540 getTransientFor()->isFocused())) {
2543 if (screen
->getPlacementPolicy() == BScreen::ClickMousePlacement
) {
2547 XQueryPointer(blackbox
->getXDisplay(), screen
->getRootWindow(),
2548 &r
, &c
, &rx
, &ry
, &x
, &y
, &m
);
2558 void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent
*ue
) {
2559 if (ue
->window
!= client
.window
)
2563 fprintf(stderr
, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2567 screen
->unmanageWindow(this, False
);
2571 void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent
*de
) {
2572 if (de
->window
!= client
.window
)
2576 fprintf(stderr
, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2580 screen
->unmanageWindow(this, False
);
2584 void BlackboxWindow::reparentNotifyEvent(const XReparentEvent
*re
) {
2585 if (re
->window
!= client
.window
|| re
->parent
== frame
.plate
)
2589 fprintf(stderr
, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2590 "0x%lx.\n", client
.window
, re
->parent
);
2595 XPutBackEvent(blackbox
->getXDisplay(), &ev
);
2596 screen
->unmanageWindow(this, True
);
2600 void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent
*pe
) {
2601 if (pe
->state
== PropertyDelete
)
2605 fprintf(stderr
, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n",
2611 case XA_WM_CLIENT_MACHINE
:
2615 case XA_WM_TRANSIENT_FOR
: {
2616 // determine if this is a transient window
2619 // adjust the window decorations based on transience
2620 if (isTransient()) {
2621 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2622 functions
&= ~Func_Maximize
;
2623 setAllowedActions();
2634 case XA_WM_ICON_NAME
:
2636 if (flags
.iconic
) screen
->propagateWindowName(this);
2639 case XAtom::net_wm_name
:
2643 if (decorations
& Decor_Titlebar
)
2646 screen
->propagateWindowName(this);
2649 case XA_WM_NORMAL_HINTS
: {
2652 if ((client
.normal_hint_flags
& PMinSize
) &&
2653 (client
.normal_hint_flags
& PMaxSize
)) {
2654 // the window now can/can't resize itself, so the buttons need to be
2657 if (client
.max_width
<= client
.min_width
&&
2658 client
.max_height
<= client
.min_height
) {
2659 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2660 functions
&= ~(Func_Resize
| Func_Maximize
);
2662 if (! isTransient()) {
2663 decorations
|= Decor_Maximize
| Decor_Handle
;
2664 functions
|= Func_Maximize
;
2666 functions
|= Func_Resize
;
2669 setAllowedActions();
2672 Rect old_rect
= frame
.rect
;
2676 if (old_rect
!= frame
.rect
)
2683 if (pe
->atom
== xatom
->getAtom(XAtom::wm_protocols
)) {
2686 if ((decorations
& Decor_Close
) && (! frame
.close_button
)) {
2687 createCloseButton();
2688 if (decorations
& Decor_Titlebar
) {
2689 positionButtons(True
);
2690 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
2692 if (windowmenu
) windowmenu
->reconfigure();
2694 } else if (pe
->atom
== xatom
->getAtom(XAtom::net_wm_strut
)) {
2703 void BlackboxWindow::exposeEvent(const XExposeEvent
*ee
) {
2705 fprintf(stderr
, "BlackboxWindow::exposeEvent() for 0x%lx\n", client
.window
);
2708 if (frame
.label
== ee
->window
&& (decorations
& Decor_Titlebar
))
2710 else if (frame
.close_button
== ee
->window
)
2711 redrawCloseButton(False
);
2712 else if (frame
.maximize_button
== ee
->window
)
2713 redrawMaximizeButton(flags
.maximized
);
2714 else if (frame
.iconify_button
== ee
->window
)
2715 redrawIconifyButton(False
);
2719 void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent
*cr
) {
2720 if (cr
->window
!= client
.window
|| flags
.iconic
)
2723 if (cr
->value_mask
& CWBorderWidth
)
2724 client
.old_bw
= cr
->border_width
;
2726 if (cr
->value_mask
& (CWX
| CWY
| CWWidth
| CWHeight
)) {
2727 Rect req
= frame
.rect
;
2729 if (cr
->value_mask
& (CWX
| CWY
)) {
2730 if (cr
->value_mask
& CWX
)
2731 client
.rect
.setX(cr
->x
);
2732 if (cr
->value_mask
& CWY
)
2733 client
.rect
.setY(cr
->y
);
2738 if (cr
->value_mask
& CWWidth
)
2739 req
.setWidth(cr
->width
+ frame
.margin
.left
+ frame
.margin
.right
);
2741 if (cr
->value_mask
& CWHeight
)
2742 req
.setHeight(cr
->height
+ frame
.margin
.top
+ frame
.margin
.bottom
);
2744 configure(req
.x(), req
.y(), req
.width(), req
.height());
2747 if (cr
->value_mask
& CWStackMode
&& !isDesktop()) {
2748 switch (cr
->detail
) {
2751 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2757 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2764 void BlackboxWindow::buttonPressEvent(const XButtonEvent
*be
) {
2766 fprintf(stderr
, "BlackboxWindow::buttonPressEvent() for 0x%lx\n",
2770 if (frame
.maximize_button
== be
->window
&& be
->button
<= 3) {
2771 redrawMaximizeButton(True
);
2772 } else if (be
->button
== 1 || (be
->button
== 3 && be
->state
== ModMask
)) {
2773 if (! flags
.focused
)
2776 if (frame
.iconify_button
== be
->window
) {
2777 redrawIconifyButton(True
);
2778 } else if (frame
.close_button
== be
->window
) {
2779 redrawCloseButton(True
);
2780 } else if (frame
.plate
== be
->window
) {
2781 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2783 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2785 XAllowEvents(blackbox
->getXDisplay(), ReplayPointer
, be
->time
);
2787 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
2788 if (((be
->time
- lastButtonPressTime
) <=
2789 blackbox
->getDoubleClickInterval()) ||
2790 (be
->state
== ControlMask
)) {
2791 lastButtonPressTime
= 0;
2794 lastButtonPressTime
= be
->time
;
2798 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2800 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2802 } else if (be
->button
== 2 && (be
->window
!= frame
.iconify_button
) &&
2803 (be
->window
!= frame
.close_button
)) {
2804 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2805 } else if (windowmenu
&& be
->button
== 3 &&
2806 (frame
.title
== be
->window
|| frame
.label
== be
->window
||
2807 frame
.handle
== be
->window
|| frame
.window
== be
->window
)) {
2808 if (windowmenu
->isVisible()) {
2811 int mx
= be
->x_root
- windowmenu
->getWidth() / 2,
2812 my
= be
->y_root
- windowmenu
->getHeight() / 2;
2814 // snap the window menu into a corner/side if necessary
2815 int left_edge
, right_edge
, top_edge
, bottom_edge
;
2818 the " + (frame.border_w * 2) - 1" bits are to get the proper width
2819 and height of the menu, as the sizes returned by it do not include
2822 left_edge
= frame
.rect
.x();
2823 right_edge
= frame
.rect
.right() -
2824 (windowmenu
->getWidth() + (frame
.border_w
* 2) - 1);
2825 top_edge
= client
.rect
.top() - (frame
.border_w
+ frame
.mwm_border_w
);
2826 bottom_edge
= client
.rect
.bottom() -
2827 (windowmenu
->getHeight() + (frame
.border_w
* 2) - 1) +
2828 (frame
.border_w
+ frame
.mwm_border_w
);
2832 if (mx
> right_edge
)
2836 if (my
> bottom_edge
)
2839 windowmenu
->move(mx
, my
);
2841 XRaiseWindow(blackbox
->getXDisplay(), windowmenu
->getWindowID());
2842 XRaiseWindow(blackbox
->getXDisplay(),
2843 windowmenu
->getSendToMenu()->getWindowID());
2846 } else if (be
->button
== 4) {
2847 if ((be
->window
== frame
.label
||
2848 be
->window
== frame
.title
||
2849 be
->window
== frame
.maximize_button
||
2850 be
->window
== frame
.iconify_button
||
2851 be
->window
== frame
.close_button
) &&
2855 } else if (be
->button
== 5) {
2856 if ((be
->window
== frame
.label
||
2857 be
->window
== frame
.title
||
2858 be
->window
== frame
.maximize_button
||
2859 be
->window
== frame
.iconify_button
||
2860 be
->window
== frame
.close_button
) &&
2867 void BlackboxWindow::buttonReleaseEvent(const XButtonEvent
*re
) {
2869 fprintf(stderr
, "BlackboxWindow::buttonReleaseEvent() for 0x%lx\n",
2873 if (re
->window
== frame
.maximize_button
&&
2874 re
->button
>= 1 && re
->button
<= 3) {
2875 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2876 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2877 maximize(re
->button
);
2879 redrawMaximizeButton(flags
.maximized
);
2881 } else if (re
->window
== frame
.iconify_button
&& re
->button
== 1) {
2882 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2883 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2886 redrawIconifyButton(False
);
2888 } else if (re
->window
== frame
.close_button
& re
->button
== 1) {
2889 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2890 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
)))
2892 redrawCloseButton(False
);
2893 } else if (flags
.moving
) {
2895 } else if (flags
.resizing
) {
2897 } else if (re
->window
== frame
.window
) {
2898 if (re
->button
== 2 && re
->state
== ModMask
)
2899 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
2905 void BlackboxWindow::beginMove(int x_root
, int y_root
) {
2906 assert(! (flags
.resizing
|| flags
.moving
));
2909 Only one window can be moved/resized at a time. If another window is already
2910 being moved or resized, then stop it before whating to work with this one.
2912 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
2913 if (changing
&& changing
!= this) {
2914 if (changing
->flags
.moving
)
2915 changing
->endMove();
2916 else // if (changing->flags.resizing)
2917 changing
->endResize();
2920 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
2921 PointerMotionMask
| ButtonReleaseMask
,
2922 GrabModeAsync
, GrabModeAsync
,
2923 None
, blackbox
->getMoveCursor(), CurrentTime
);
2925 if (windowmenu
&& windowmenu
->isVisible())
2928 flags
.moving
= True
;
2929 blackbox
->setChangingWindow(this);
2931 if (! screen
->doOpaqueMove()) {
2932 XGrabServer(blackbox
->getXDisplay());
2934 frame
.changing
= frame
.rect
;
2935 screen
->showPosition(frame
.changing
.x(), frame
.changing
.y());
2937 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2941 frame
.changing
.width() - 1,
2942 frame
.changing
.height() - 1);
2945 frame
.grab_x
= x_root
- frame
.rect
.x() - frame
.border_w
;
2946 frame
.grab_y
= y_root
- frame
.rect
.y() - frame
.border_w
;
2950 void BlackboxWindow::doMove(int x_root
, int y_root
) {
2951 assert(flags
.moving
);
2952 assert(blackbox
->getChangingWindow() == this);
2954 int dx
= x_root
- frame
.grab_x
, dy
= y_root
- frame
.grab_y
;
2955 dx
-= frame
.border_w
;
2956 dy
-= frame
.border_w
;
2958 if (screen
->doWorkspaceWarping()) {
2959 // workspace warping
2961 unsigned int dest
= screen
->getCurrentWorkspaceID();
2965 if (dest
> 0) dest
--;
2966 else dest
= screen
->getNumberOfWorkspaces() - 1;
2968 } else if (x_root
>= screen
->getRect().right()) {
2971 if (dest
< screen
->getNumberOfWorkspaces() - 1) dest
++;
2976 bool focus
= flags
.focused
; // had focus while moving?
2978 screen
->reassociateWindow(this, dest
, False
);
2979 screen
->changeWorkspaceID(dest
);
2984 If the XWarpPointer is done after the configure, we can end up
2985 grabbing another window, so made sure you do it first.
2989 dest_x
= screen
->getRect().right() - 1;
2990 XWarpPointer(blackbox
->getXDisplay(), None
,
2991 screen
->getRootWindow(), 0, 0, 0, 0,
2994 configure(dx
+ (screen
->getRect().width() - 1), dy
,
2995 frame
.rect
.width(), frame
.rect
.height());
2998 XWarpPointer(blackbox
->getXDisplay(), None
,
2999 screen
->getRootWindow(), 0, 0, 0, 0,
3002 configure(dx
- (screen
->getRect().width() - 1), dy
,
3003 frame
.rect
.width(), frame
.rect
.height());
3006 beginMove(dest_x
, y_root
);
3011 const int snap_distance
= screen
->getEdgeSnapThreshold();
3013 if (snap_distance
) {
3015 const int wleft
= dx
,
3016 wright
= dx
+ frame
.rect
.width() - 1,
3018 wbottom
= dy
+ frame
.rect
.height() - 1;
3020 if (screen
->getWindowToWindowSnap()) {
3021 Workspace
*w
= screen
->getWorkspace(getWorkspaceNumber());
3024 // try snap to another window
3025 for (unsigned int i
= 0, c
= w
->getCount(); i
< c
; ++i
) {
3026 BlackboxWindow
*snapwin
= w
->getWindow(i
);
3027 if (snapwin
== this)
3028 continue; // don't snap to self
3030 bool snapped
= False
;
3032 const Rect
&winrect
= snapwin
->frameRect();
3033 int dleft
= std::abs(wright
- winrect
.left()),
3034 dright
= std::abs(wleft
- winrect
.right()),
3035 dtop
= std::abs(wbottom
- winrect
.top()),
3036 dbottom
= std::abs(wtop
- winrect
.bottom());
3038 if (wtop
>= (signed)(winrect
.y() - frame
.rect
.height() + 1) &&
3039 wtop
< (signed)(winrect
.y() + winrect
.height() - 1)) {
3041 // snap left of other window?
3042 if (dleft
< snap_distance
&& dleft
<= dright
) {
3043 dx
= winrect
.left() - frame
.rect
.width();
3046 // snap right of other window?
3047 else if (dright
< snap_distance
) {
3048 dx
= winrect
.right() + 1;
3053 if (screen
->getWindowCornerSnap()) {
3054 // try corner-snap to its other sides
3055 dtop
= std::abs(wtop
- winrect
.top());
3056 dbottom
= std::abs(wbottom
- winrect
.bottom());
3057 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3059 else if (dbottom
< snap_distance
)
3060 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
3067 if (wleft
>= (signed)(winrect
.x() - frame
.rect
.width() + 1) &&
3068 wleft
< (signed)(winrect
.x() + winrect
.width() - 1)) {
3070 // snap top of other window?
3071 if (dtop
< snap_distance
&& dtop
<= dbottom
) {
3072 dy
= winrect
.top() - frame
.rect
.height();
3075 // snap bottom of other window?
3076 else if (dbottom
< snap_distance
) {
3077 dy
= winrect
.bottom() + 1;
3082 if (screen
->getWindowCornerSnap()) {
3083 // try corner-snap to its other sides
3084 dleft
= std::abs(wleft
- winrect
.left());
3085 dright
= std::abs(wright
- winrect
.right());
3086 if (dleft
< snap_distance
&& dleft
<= dright
)
3087 dx
= winrect
.left();
3088 else if (dright
< snap_distance
)
3089 dx
= winrect
.right() - frame
.rect
.width() + 1;
3098 RectList snaplist
; // the list of rects we will try to snap to
3100 // snap to the strut (and screen boundaries for xinerama)
3102 if (screen
->isXineramaActive() && blackbox
->doXineramaSnapping()) {
3103 if (! screen
->doFullMax())
3104 snaplist
.insert(snaplist
.begin(),
3105 screen
->allAvailableAreas().begin(),
3106 screen
->allAvailableAreas().end());
3108 // always snap to the screen edges
3109 snaplist
.insert(snaplist
.begin(),
3110 screen
->getXineramaAreas().begin(),
3111 screen
->getXineramaAreas().end());
3115 if (! screen
->doFullMax())
3116 snaplist
.push_back(screen
->availableArea());
3118 // always snap to the screen edges
3119 snaplist
.push_back(screen
->getRect());
3122 RectList::const_iterator it
, end
= snaplist
.end();
3123 for (it
= snaplist
.begin(); it
!= end
; ++it
) {
3124 const Rect
&srect
= *it
;
3126 // if we're not in the rectangle then don't snap to it.
3127 if (! srect
.intersects(Rect(wleft
, wtop
, frame
.rect
.width(),
3128 frame
.rect
.height())))
3131 int dleft
= std::abs(wleft
- srect
.left()),
3132 dright
= std::abs(wright
- srect
.right()),
3133 dtop
= std::abs(wtop
- srect
.top()),
3134 dbottom
= std::abs(wbottom
- srect
.bottom());
3137 if (dleft
< snap_distance
&& dleft
<= dright
)
3140 else if (dright
< snap_distance
)
3141 dx
= srect
.right() - frame
.rect
.width() + 1;
3144 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3147 else if (dbottom
< snap_distance
)
3148 dy
= srect
.bottom() - frame
.rect
.height() + 1;
3152 if (screen
->doOpaqueMove()) {
3153 configure(dx
, dy
, frame
.rect
.width(), frame
.rect
.height());
3155 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3159 frame
.changing
.width() - 1,
3160 frame
.changing
.height() - 1);
3162 frame
.changing
.setPos(dx
, dy
);
3164 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3168 frame
.changing
.width() - 1,
3169 frame
.changing
.height() - 1);
3172 screen
->showPosition(dx
, dy
);
3176 void BlackboxWindow::endMove(void) {
3177 assert(flags
.moving
);
3178 assert(blackbox
->getChangingWindow() == this);
3180 flags
.moving
= False
;
3181 blackbox
->setChangingWindow(0);
3183 if (! screen
->doOpaqueMove()) {
3184 /* when drawing the rubber band, we need to make sure we only draw inside
3185 * the frame... frame.changing_* contain the new coords for the window,
3186 * so we need to subtract 1 from changing_w/changing_h every where we
3187 * draw the rubber band (for both moving and resizing)
3189 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3190 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3191 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3192 XUngrabServer(blackbox
->getXDisplay());
3194 configure(frame
.changing
.x(), frame
.changing
.y(),
3195 frame
.changing
.width(), frame
.changing
.height());
3197 configure(frame
.rect
.x(), frame
.rect
.y(),
3198 frame
.rect
.width(), frame
.rect
.height());
3200 screen
->hideGeometry();
3202 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3204 // if there are any left over motions from the move, drop them now
3205 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3207 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3212 void BlackboxWindow::beginResize(int x_root
, int y_root
, Corner dir
) {
3213 assert(! (flags
.resizing
|| flags
.moving
));
3216 Only one window can be moved/resized at a time. If another window is already
3217 being moved or resized, then stop it before whating to work with this one.
3219 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3220 if (changing
&& changing
!= this) {
3221 if (changing
->flags
.moving
)
3222 changing
->endMove();
3223 else // if (changing->flags.resizing)
3224 changing
->endResize();
3232 switch (resize_dir
) {
3235 cursor
= blackbox
->getLowerLeftAngleCursor();
3240 cursor
= blackbox
->getLowerRightAngleCursor();
3244 anchor
= BottomRight
;
3245 cursor
= blackbox
->getUpperLeftAngleCursor();
3249 anchor
= BottomLeft
;
3250 cursor
= blackbox
->getUpperRightAngleCursor();
3254 assert(false); // unhandled Corner
3255 return; // unreachable, for the compiler
3258 XGrabServer(blackbox
->getXDisplay());
3259 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3260 PointerMotionMask
| ButtonReleaseMask
,
3261 GrabModeAsync
, GrabModeAsync
, None
, cursor
, CurrentTime
);
3263 flags
.resizing
= True
;
3264 blackbox
->setChangingWindow(this);
3267 frame
.changing
= frame
.rect
;
3269 constrain(anchor
, &gw
, &gh
);
3271 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3272 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3273 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3275 screen
->showGeometry(gw
, gh
);
3277 frame
.grab_x
= x_root
;
3278 frame
.grab_y
= y_root
;
3282 void BlackboxWindow::doResize(int x_root
, int y_root
) {
3283 assert(flags
.resizing
);
3284 assert(blackbox
->getChangingWindow() == this);
3286 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3287 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3288 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3293 switch (resize_dir
) {
3296 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3297 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3301 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3302 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3305 anchor
= BottomRight
;
3306 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3307 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3310 anchor
= BottomLeft
;
3311 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3312 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3316 assert(false); // unhandled Corner
3317 return; // unreachable, for the compiler
3320 constrain(anchor
, &gw
, &gh
);
3322 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3323 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3324 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3326 screen
->showGeometry(gw
, gh
);
3330 void BlackboxWindow::endResize(void) {
3331 assert(flags
.resizing
);
3332 assert(blackbox
->getChangingWindow() == this);
3334 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3335 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3336 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3337 XUngrabServer(blackbox
->getXDisplay());
3339 // unset maximized state after resized when fully maximized
3340 if (flags
.maximized
== 1)
3343 flags
.resizing
= False
;
3344 blackbox
->setChangingWindow(0);
3346 configure(frame
.changing
.x(), frame
.changing
.y(),
3347 frame
.changing
.width(), frame
.changing
.height());
3348 screen
->hideGeometry();
3350 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3352 // if there are any left over motions from the resize, drop them now
3353 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3355 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3360 void BlackboxWindow::motionNotifyEvent(const XMotionEvent
*me
) {
3362 fprintf(stderr
, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n",
3367 doMove(me
->x_root
, me
->y_root
);
3368 } else if (flags
.resizing
) {
3369 doResize(me
->x_root
, me
->y_root
);
3371 if (!flags
.resizing
&& me
->state
& Button1Mask
&& (functions
& Func_Move
) &&
3372 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3373 frame
.handle
== me
->window
|| frame
.window
== me
->window
)) {
3374 beginMove(me
->x_root
, me
->y_root
);
3375 } else if ((functions
& Func_Resize
) &&
3376 (me
->state
& Button1Mask
&& (me
->window
== frame
.right_grip
||
3377 me
->window
== frame
.left_grip
)) ||
3378 (me
->state
& Button3Mask
&& me
->state
& ModMask
&&
3379 me
->window
== frame
.window
)) {
3380 unsigned int zones
= screen
->getResizeZones();
3383 if (me
->window
== frame
.left_grip
) {
3384 corner
= BottomLeft
;
3385 } else if (me
->window
== frame
.right_grip
|| zones
== 1) {
3386 corner
= BottomRight
;
3389 bool left
= (me
->x_root
- frame
.rect
.x() <=
3390 static_cast<signed>(frame
.rect
.width() / 2));
3393 else // (zones == 4)
3394 top
= (me
->y_root
- frame
.rect
.y() <=
3395 static_cast<signed>(frame
.rect
.height() / 2));
3396 corner
= (top
? (left
? TopLeft
: TopRight
) :
3397 (left
? BottomLeft
: BottomRight
));
3400 beginResize(me
->x_root
, me
->y_root
, corner
);
3407 void BlackboxWindow::shapeEvent(XShapeEvent
*) {
3408 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
3415 bool BlackboxWindow::validateClient(void) const {
3416 XSync(blackbox
->getXDisplay(), False
);
3419 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3420 DestroyNotify
, &e
) ||
3421 XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3423 XPutBackEvent(blackbox
->getXDisplay(), &e
);
3432 void BlackboxWindow::restore(bool remap
) {
3433 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeDelete
);
3434 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
3435 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, NoEventMask
);
3437 // do not leave a shaded window as an icon unless it was an icon
3438 if (flags
.shaded
&& ! flags
.iconic
) setState(NormalState
);
3440 restoreGravity(client
.rect
);
3442 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
3443 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
3445 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, client
.old_bw
);
3448 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3449 ReparentNotify
, &ev
)) {
3452 // according to the ICCCM - if the client doesn't reparent to
3453 // root, then we have to do it for them
3454 XReparentWindow(blackbox
->getXDisplay(), client
.window
,
3455 screen
->getRootWindow(),
3456 client
.rect
.x(), client
.rect
.y());
3459 if (remap
) XMapWindow(blackbox
->getXDisplay(), client
.window
);
3463 // timer for autoraise
3464 void BlackboxWindow::timeout(void) {
3465 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3469 void BlackboxWindow::changeBlackboxHints(BlackboxHints
*net
) {
3470 if ((net
->flags
& AttribShaded
) &&
3471 ((blackbox_attrib
.attrib
& AttribShaded
) !=
3472 (net
->attrib
& AttribShaded
)))
3475 if (flags
.visible
&& // watch out for requests when we can not be seen
3476 (net
->flags
& (AttribMaxVert
| AttribMaxHoriz
)) &&
3477 ((blackbox_attrib
.attrib
& (AttribMaxVert
| AttribMaxHoriz
)) !=
3478 (net
->attrib
& (AttribMaxVert
| AttribMaxHoriz
)))) {
3479 if (flags
.maximized
) {
3484 if ((net
->flags
& AttribMaxHoriz
) && (net
->flags
& AttribMaxVert
))
3485 button
= ((net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0);
3486 else if (net
->flags
& AttribMaxVert
)
3487 button
= ((net
->attrib
& AttribMaxVert
) ? 2 : 0);
3488 else if (net
->flags
& AttribMaxHoriz
)
3489 button
= ((net
->attrib
& AttribMaxHoriz
) ? 3 : 0);
3495 if ((net
->flags
& AttribOmnipresent
) &&
3496 ((blackbox_attrib
.attrib
& AttribOmnipresent
) !=
3497 (net
->attrib
& AttribOmnipresent
)))
3500 if ((net
->flags
& AttribWorkspace
) &&
3501 (blackbox_attrib
.workspace
!= net
->workspace
)) {
3502 screen
->reassociateWindow(this, net
->workspace
, True
);
3504 if (screen
->getCurrentWorkspaceID() != net
->workspace
) {
3508 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3512 if (net
->flags
& AttribDecoration
) {
3513 switch (net
->decoration
) {
3515 // clear all decorations except close
3516 decorations
&= Decor_Close
;
3522 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Iconify
;
3524 decorations
= ((functions
& Func_Resize
) && !isTransient() ?
3525 decorations
| Decor_Handle
:
3526 decorations
&= ~Decor_Handle
);
3527 decorations
= (functions
& Func_Maximize
?
3528 decorations
| Decor_Maximize
:
3529 decorations
&= ~Decor_Maximize
);
3534 decorations
|= Decor_Titlebar
| Decor_Iconify
;
3535 decorations
&= ~(Decor_Border
| Decor_Handle
);
3537 decorations
= (functions
& Func_Maximize
?
3538 decorations
| Decor_Maximize
:
3539 decorations
&= ~Decor_Maximize
);
3544 decorations
|= Decor_Titlebar
;
3545 decorations
&= ~(Decor_Iconify
| Decor_Border
);
3547 decorations
= ((functions
& Func_Resize
) && !isTransient() ?
3548 decorations
| Decor_Handle
:
3549 decorations
&= ~Decor_Handle
);
3550 decorations
= (functions
& Func_Maximize
?
3551 decorations
| Decor_Maximize
:
3552 decorations
&= ~Decor_Maximize
);
3557 // we can not be shaded if we lack a titlebar
3558 if (flags
.shaded
&& ! (decorations
& Decor_Titlebar
))
3561 if (flags
.visible
&& frame
.window
) {
3562 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
3563 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
3567 setState(current_state
);
3573 * Set the sizes of all components of the window frame
3574 * (the window decorations).
3575 * These values are based upon the current style settings and the client
3576 * window's dimensions.
3578 void BlackboxWindow::upsize(void) {
3579 frame
.bevel_w
= screen
->getBevelWidth();
3581 if (decorations
& Decor_Border
) {
3582 frame
.border_w
= screen
->getBorderWidth();
3583 if (! isTransient())
3584 frame
.mwm_border_w
= screen
->getFrameWidth();
3586 frame
.mwm_border_w
= 0;
3588 frame
.mwm_border_w
= frame
.border_w
= 0;
3591 if (decorations
& Decor_Titlebar
) {
3592 // the height of the titlebar is based upon the height of the font being
3593 // used to display the window's title
3594 WindowStyle
*style
= screen
->getWindowStyle();
3595 frame
.title_h
= style
->font
->height() + (frame
.bevel_w
* 2) + 2;
3597 frame
.label_h
= frame
.title_h
- (frame
.bevel_w
* 2);
3598 frame
.button_w
= (frame
.label_h
- 2);
3600 // set the top frame margin
3601 frame
.margin
.top
= frame
.border_w
+ frame
.title_h
+
3602 frame
.border_w
+ frame
.mwm_border_w
;
3608 // set the top frame margin
3609 frame
.margin
.top
= frame
.border_w
+ frame
.mwm_border_w
;
3612 // set the left/right frame margin
3613 frame
.margin
.left
= frame
.margin
.right
= frame
.border_w
+ frame
.mwm_border_w
;
3615 if (decorations
& Decor_Handle
) {
3616 frame
.grip_w
= frame
.button_w
* 2;
3617 frame
.handle_h
= screen
->getHandleWidth();
3619 // set the bottom frame margin
3620 frame
.margin
.bottom
= frame
.border_w
+ frame
.handle_h
+
3621 frame
.border_w
+ frame
.mwm_border_w
;
3626 // set the bottom frame margin
3627 frame
.margin
.bottom
= frame
.border_w
+ frame
.mwm_border_w
;
3631 We first get the normal dimensions and use this to define the inside_w/h
3632 then we modify the height if shading is in effect.
3633 If the shade state is not considered then frame.rect gets reset to the
3634 normal window size on a reconfigure() call resulting in improper
3635 dimensions appearing in move/resize and other events.
3638 height
= client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
,
3639 width
= client
.rect
.width() + frame
.margin
.left
+ frame
.margin
.right
;
3641 frame
.inside_w
= width
- (frame
.border_w
* 2);
3642 frame
.inside_h
= height
- (frame
.border_w
* 2);
3645 height
= frame
.title_h
+ (frame
.border_w
* 2);
3646 frame
.rect
.setSize(width
, height
);
3651 * Calculate the size of the client window and constrain it to the
3652 * size specified by the size hints of the client window.
3654 * The logical width and height are placed into pw and ph, if they
3655 * are non-zero. Logical size refers to the users perception of
3656 * the window size (for example an xterm resizes in cells, not in pixels).
3658 * The physical geometry is placed into frame.changing_{x,y,width,height}.
3659 * Physical geometry refers to the geometry of the window in pixels.
3661 void BlackboxWindow::constrain(Corner anchor
, int *pw
, int *ph
) {
3662 // frame.changing represents the requested frame size, we need to
3663 // strip the frame margin off and constrain the client size
3664 frame
.changing
.setCoords(frame
.changing
.left() + frame
.margin
.left
,
3665 frame
.changing
.top() + frame
.margin
.top
,
3666 frame
.changing
.right() - frame
.margin
.right
,
3667 frame
.changing
.bottom() - frame
.margin
.bottom
);
3669 int dw
= frame
.changing
.width(), dh
= frame
.changing
.height(),
3670 base_width
= (client
.base_width
) ? client
.base_width
: client
.min_width
,
3671 base_height
= (client
.base_height
) ? client
.base_height
:
3675 if (dw
< static_cast<signed>(client
.min_width
)) dw
= client
.min_width
;
3676 if (dh
< static_cast<signed>(client
.min_height
)) dh
= client
.min_height
;
3677 if (dw
> static_cast<signed>(client
.max_width
)) dw
= client
.max_width
;
3678 if (dh
> static_cast<signed>(client
.max_height
)) dh
= client
.max_height
;
3681 dw
/= client
.width_inc
;
3683 dh
/= client
.height_inc
;
3686 if (client
.width_inc
== 1)
3687 *pw
= dw
+ base_width
;
3692 if (client
.height_inc
== 1)
3693 *ph
= dh
+ base_height
;
3698 dw
*= client
.width_inc
;
3700 dh
*= client
.height_inc
;
3703 frame
.changing
.setSize(dw
, dh
);
3705 // add the frame margin back onto frame.changing
3706 frame
.changing
.setCoords(frame
.changing
.left() - frame
.margin
.left
,
3707 frame
.changing
.top() - frame
.margin
.top
,
3708 frame
.changing
.right() + frame
.margin
.right
,
3709 frame
.changing
.bottom() + frame
.margin
.bottom
);
3711 // move frame.changing to the specified anchor
3719 dx
= frame
.rect
.right() - frame
.changing
.right();
3723 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3727 dx
= frame
.rect
.right() - frame
.changing
.right();
3728 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3732 assert(false); // unhandled corner
3734 frame
.changing
.setPos(frame
.changing
.x() + dx
, frame
.changing
.y() + dy
);
3738 void WindowStyle::doJustify(const std::string
&text
, int &start_pos
,
3739 unsigned int max_length
,
3740 unsigned int modifier
) const {
3741 size_t text_len
= text
.size();
3742 unsigned int length
;
3745 length
= font
->measureString(string(text
, 0, text_len
)) + modifier
;
3746 } while (length
> max_length
&& text_len
-- > 0);
3750 start_pos
+= max_length
- length
;
3754 start_pos
+= (max_length
- length
) / 2;
3764 BWindowGroup::BWindowGroup(Blackbox
*b
, Window _group
)
3765 : blackbox(b
), group(_group
) {
3766 XWindowAttributes wattrib
;
3767 if (! XGetWindowAttributes(blackbox
->getXDisplay(), group
, &wattrib
)) {
3768 // group window doesn't seem to exist anymore
3773 XSelectInput(blackbox
->getXDisplay(), group
,
3774 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
3776 blackbox
->saveGroupSearch(group
, this);
3780 BWindowGroup::~BWindowGroup(void) {
3781 blackbox
->removeGroupSearch(group
);
3786 BWindowGroup::find(BScreen
*screen
, bool allow_transients
) const {
3787 BlackboxWindow
*ret
= blackbox
->getFocusedWindow();
3789 // does the focus window match (or any transient_fors)?
3791 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3792 if (ret
->isTransient() && allow_transients
) break;
3793 else if (! ret
->isTransient()) break;
3796 ret
= ret
->getTransientFor();
3799 if (ret
) return ret
;
3801 // the focus window didn't match, look in the group's window list
3802 BlackboxWindowList::const_iterator it
, end
= windowList
.end();
3803 for (it
= windowList
.begin(); it
!= end
; ++it
) {
3805 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3806 if (ret
->isTransient() && allow_transients
) break;
3807 else if (! ret
->isTransient()) break;