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