1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2 // Window.cc for Blackbox - an X11 Window manager
3 // Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry <shaleh at debian.org>
4 // Copyright (c) 1997 - 2000, 2002 Brad Hughes <bhughes at trolltech.com>
6 // Permission is hereby granted, free of charge, to any person obtaining a
7 // copy of this software and associated documentation files (the "Software"),
8 // to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 // and/or sell copies of the Software, and to permit persons to whom the
11 // Software is furnished to do so, subject to the following conditions:
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 // DEALINGS IN THE SOFTWARE.
25 # include "../config.h"
26 #endif // HAVE_CONFIG_H
29 #include <X11/Xatom.h>
30 #include <X11/keysym.h>
34 #endif // HAVE_STRING_H
39 # endif // HAVE_STDIO_H
46 #include "blackbox.hh"
47 #include "Clientmenu.hh"
50 #include "Iconmenu.hh"
56 #include "Windowmenu.hh"
57 #include "Workspace.hh"
63 * Initializes the class with default values/the window's set initial values.
65 BlackboxWindow::BlackboxWindow(Blackbox
*b
, Window w
, BScreen
*s
) {
66 // fprintf(stderr, "BlackboxWindow size: %d bytes\n",
67 // sizeof(BlackboxWindow));
70 fprintf(stderr
, "BlackboxWindow::BlackboxWindow(): creating 0x%lx\n", w
);
74 set timer to zero... it is initialized properly later, so we check
75 if timer is zero in the destructor, and assume that the window is not
76 fully constructed if timer is zero...
82 xatom
= blackbox
->getXAtom();
84 if (! validateClient()) {
89 // set the eventmask early in the game so that we make sure we get
90 // all the events we are interested in
91 XSetWindowAttributes attrib_set
;
92 attrib_set
.event_mask
= PropertyChangeMask
| FocusChangeMask
|
94 attrib_set
.do_not_propagate_mask
= ButtonPressMask
| ButtonReleaseMask
|
96 XChangeWindowAttributes(blackbox
->getXDisplay(), client
.window
,
97 CWEventMask
|CWDontPropagate
, &attrib_set
);
99 // fetch client size and placement
100 XWindowAttributes wattrib
;
101 if ((! XGetWindowAttributes(blackbox
->getXDisplay(),
102 client
.window
, &wattrib
)) ||
103 (! wattrib
.screen
) || wattrib
.override_redirect
) {
106 "BlackboxWindow::BlackboxWindow(): XGetWindowAttributes failed\n");
113 flags
.moving
= flags
.resizing
= flags
.shaded
= flags
.visible
=
114 flags
.iconic
= flags
.focused
= flags
.stuck
= flags
.modal
=
115 flags
.send_focus_message
= flags
.shaped
= flags
.skip_taskbar
=
116 flags
.skip_pager
= flags
.fullscreen
= False
;
119 blackbox_attrib
.workspace
= window_number
= BSENTINEL
;
121 blackbox_attrib
.flags
= blackbox_attrib
.attrib
= blackbox_attrib
.stack
122 = blackbox_attrib
.decoration
= 0l;
123 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
124 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
127 frame
.window
= frame
.plate
= frame
.title
= frame
.handle
= None
;
128 frame
.close_button
= frame
.iconify_button
= frame
.maximize_button
= None
;
129 frame
.right_grip
= frame
.left_grip
= None
;
131 frame
.ulabel_pixel
= frame
.flabel_pixel
= frame
.utitle_pixel
=
132 frame
.ftitle_pixel
= frame
.uhandle_pixel
= frame
.fhandle_pixel
=
133 frame
.ubutton_pixel
= frame
.fbutton_pixel
= frame
.pbutton_pixel
=
134 frame
.uborder_pixel
= frame
.fborder_pixel
= frame
.ugrip_pixel
=
135 frame
.fgrip_pixel
= 0;
136 frame
.utitle
= frame
.ftitle
= frame
.uhandle
= frame
.fhandle
= None
;
137 frame
.ulabel
= frame
.flabel
= frame
.ubutton
= frame
.fbutton
= None
;
138 frame
.pbutton
= frame
.ugrip
= frame
.fgrip
= None
;
140 decorations
= Decor_Titlebar
| Decor_Border
| Decor_Handle
|
141 Decor_Iconify
| Decor_Maximize
;
142 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
144 client
.wm_hint_flags
= client
.normal_hint_flags
= 0;
145 client
.window_group
= None
;
146 client
.transient_for
= 0;
149 get the initial size and location of client window (relative to the
150 _root window_). This position is the reference point used with the
151 window's gravity to find the window's initial position.
153 client
.rect
.setRect(wattrib
.x
, wattrib
.y
, wattrib
.width
, wattrib
.height
);
154 client
.old_bw
= wattrib
.border_width
;
158 lastButtonPressTime
= 0;
160 // get size, aspect, minimum/maximum size and other hints set by the
166 if (client
.initial_state
== WithdrawnState
) {
167 screen
->getSlit()->addClient(client
.window
);
172 timer
= new BTimer(blackbox
, this);
173 timer
->setTimeout(blackbox
->getAutoRaiseDelay());
175 if (! getBlackboxHints()) {
180 frame
.window
= createToplevelWindow();
181 frame
.plate
= createChildWindow(frame
.window
);
182 associateClientWindow();
184 blackbox
->saveWindowSearch(frame
.window
, this);
185 blackbox
->saveWindowSearch(frame
.plate
, this);
186 blackbox
->saveWindowSearch(client
.window
, this);
188 // determine if this is a transient window
191 // determine the window's type, so we can decide its decorations and
192 // functionality, or if we should not manage it at all
195 // adjust the window decorations/behavior based on the window type
196 switch (window_type
) {
203 // none of these windows are decorated or manipulated by the window manager
206 blackbox_attrib
.workspace
= 0; // we do need to belong to a workspace
207 flags
.stuck
= True
; // we show up on all workspaces
211 // dialogs cannot be maximized, and don't display a handle
212 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
213 functions
&= ~Func_Maximize
;
217 // normal windows retain all of the possible decorations and functionality
221 // further adjeust the window's decorations/behavior based on window sizes
222 if ((client
.normal_hint_flags
& PMinSize
) &&
223 (client
.normal_hint_flags
& PMaxSize
) &&
224 client
.max_width
<= client
.min_width
&&
225 client
.max_height
<= client
.min_height
) {
226 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
227 functions
&= ~(Func_Resize
| Func_Maximize
);
233 bool place_window
= True
;
234 if (blackbox
->isStartup() || isTransient() ||
235 client
.normal_hint_flags
& (PPosition
|USPosition
)) {
236 applyGravity(frame
.rect
);
238 if (blackbox
->isStartup() || client
.rect
.intersects(screen
->getRect()))
239 place_window
= False
;
242 // add the window's strut. note this is done *after* placing the window.
243 screen
->addStrut(&client
.strut
);
246 if (decorations
& Decor_Titlebar
)
249 if (decorations
& Decor_Handle
)
253 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
258 windowmenu
= new Windowmenu(this);
260 if (blackbox_attrib
.workspace
>= screen
->getWorkspaceCount())
261 screen
->getCurrentWorkspace()->addWindow(this, place_window
);
263 screen
->getWorkspace(blackbox_attrib
.workspace
)->
264 addWindow(this, place_window
);
266 if (! place_window
) {
267 // don't need to call configure if we are letting the workspace
269 configure(frame
.rect
.x(), frame
.rect
.y(),
270 frame
.rect
.width(), frame
.rect
.height());
273 // preserve the window's initial state on first map, and its current state
276 if (client
.wm_hint_flags
& StateHint
)
277 current_state
= client
.initial_state
;
279 current_state
= NormalState
;
282 // get sticky state from our parent window if we've got one
283 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
284 client
.transient_for
->isStuck() != flags
.stuck
)
288 flags
.shaded
= False
;
289 unsigned long orig_state
= current_state
;
293 At this point in the life of a window, current_state should only be set
294 to IconicState if the window was an *icon*, not if it was shaded.
296 if (orig_state
!= IconicState
)
297 current_state
= NormalState
;
305 if (flags
.maximized
&& (functions
& Func_Maximize
)) {
310 When the window is mapped (and also when its attributes are restored), the
311 current_state that was set here will be used.
312 It is set to Normal if the window is to be mapped or it is set to Iconic
313 if the window is to be iconified.
314 *Note* that for sticky windows, the same rules apply here, they are in
315 fact never set to Iconic since there is no way for us to tell if a sticky
316 window was iconified previously.
323 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
329 BlackboxWindow::~BlackboxWindow(void) {
331 fprintf(stderr
, "BlackboxWindow::~BlackboxWindow: destroying 0x%lx\n",
335 if (! timer
) // window not managed...
338 screen
->removeStrut(&client
.strut
);
339 screen
->updateAvailableArea();
341 // We don't need to worry about resizing because resizing always grabs the X
342 // server. This should only ever happen if using opaque moving.
350 if (client
.window_group
) {
351 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
352 if (group
) group
->removeWindow(this);
355 // remove ourselves from our transient_for
357 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
358 client
.transient_for
->client
.transientList
.remove(this);
360 client
.transient_for
= (BlackboxWindow
*) 0;
363 if (client
.transientList
.size() > 0) {
364 // reset transient_for for all transients
365 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
366 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
367 (*it
)->client
.transient_for
= (BlackboxWindow
*) 0;
378 blackbox
->removeWindowSearch(frame
.plate
);
379 XDestroyWindow(blackbox
->getXDisplay(), frame
.plate
);
383 blackbox
->removeWindowSearch(frame
.window
);
384 XDestroyWindow(blackbox
->getXDisplay(), frame
.window
);
387 blackbox
->removeWindowSearch(client
.window
);
392 * Creates a new top level window, with a given location, size, and border
394 * Returns: the newly created window
396 Window
BlackboxWindow::createToplevelWindow(void) {
397 XSetWindowAttributes attrib_create
;
398 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
| CWColormap
|
399 CWOverrideRedirect
| CWEventMask
;
401 attrib_create
.background_pixmap
= None
;
402 attrib_create
.colormap
= screen
->getColormap();
403 attrib_create
.override_redirect
= True
;
404 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
405 ButtonMotionMask
| EnterWindowMask
;
407 return XCreateWindow(blackbox
->getXDisplay(), screen
->getRootWindow(),
408 0, 0, 1, 1, frame
.border_w
, screen
->getDepth(),
409 InputOutput
, screen
->getVisual(), create_mask
,
415 * Creates a child window, and optionally associates a given cursor with
418 Window
BlackboxWindow::createChildWindow(Window parent
, Cursor cursor
) {
419 XSetWindowAttributes attrib_create
;
420 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
|
423 attrib_create
.background_pixmap
= None
;
424 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
425 ButtonMotionMask
| ExposureMask
;
428 create_mask
|= CWCursor
;
429 attrib_create
.cursor
= cursor
;
432 return XCreateWindow(blackbox
->getXDisplay(), parent
, 0, 0, 1, 1, 0,
433 screen
->getDepth(), InputOutput
, screen
->getVisual(),
434 create_mask
, &attrib_create
);
438 void BlackboxWindow::associateClientWindow(void) {
439 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, 0);
443 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeInsert
);
445 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, SubstructureRedirectMask
);
447 XGrabServer(blackbox
->getXDisplay());
449 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
451 XSelectInput(blackbox
->getXDisplay(), client
.window
,
452 event_mask
& ~StructureNotifyMask
);
453 XReparentWindow(blackbox
->getXDisplay(), client
.window
, frame
.plate
, 0, 0);
454 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
456 XUngrabServer(blackbox
->getXDisplay());
458 XRaiseWindow(blackbox
->getXDisplay(), frame
.plate
);
459 XMapSubwindows(blackbox
->getXDisplay(), frame
.plate
);
463 if (blackbox
->hasShapeExtensions()) {
464 XShapeSelectInput(blackbox
->getXDisplay(), client
.window
,
471 XShapeQueryExtents(blackbox
->getXDisplay(), client
.window
, &shaped
,
472 &foo
, &foo
, &ufoo
, &ufoo
, &foo
, &foo
, &foo
,
474 flags
.shaped
= shaped
;
480 void BlackboxWindow::decorate(void) {
483 texture
= &(screen
->getWindowStyle()->b_focus
);
484 frame
.fbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
487 frame
.fbutton_pixel
= texture
->color().pixel();
489 texture
= &(screen
->getWindowStyle()->b_unfocus
);
490 frame
.ubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
493 frame
.ubutton_pixel
= texture
->color().pixel();
495 texture
= &(screen
->getWindowStyle()->b_pressed
);
496 frame
.pbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
499 frame
.pbutton_pixel
= texture
->color().pixel();
501 if (decorations
& Decor_Titlebar
) {
502 texture
= &(screen
->getWindowStyle()->t_focus
);
503 frame
.ftitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
506 frame
.ftitle_pixel
= texture
->color().pixel();
508 texture
= &(screen
->getWindowStyle()->t_unfocus
);
509 frame
.utitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
512 frame
.utitle_pixel
= texture
->color().pixel();
514 XSetWindowBorder(blackbox
->getXDisplay(), frame
.title
,
515 screen
->getBorderColor()->pixel());
520 if (decorations
& Decor_Border
) {
521 frame
.fborder_pixel
= screen
->getWindowStyle()->f_focus
.pixel();
522 frame
.uborder_pixel
= screen
->getWindowStyle()->f_unfocus
.pixel();
523 blackbox_attrib
.flags
|= AttribDecoration
;
524 blackbox_attrib
.decoration
= DecorNormal
;
526 blackbox_attrib
.flags
|= AttribDecoration
;
527 blackbox_attrib
.decoration
= DecorNone
;
530 if (decorations
& Decor_Handle
) {
531 texture
= &(screen
->getWindowStyle()->h_focus
);
532 frame
.fhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
535 frame
.fhandle_pixel
= texture
->color().pixel();
537 texture
= &(screen
->getWindowStyle()->h_unfocus
);
538 frame
.uhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
541 frame
.uhandle_pixel
= texture
->color().pixel();
543 texture
= &(screen
->getWindowStyle()->g_focus
);
544 frame
.fgrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.fgrip
);
546 frame
.fgrip_pixel
= texture
->color().pixel();
548 texture
= &(screen
->getWindowStyle()->g_unfocus
);
549 frame
.ugrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.ugrip
);
551 frame
.ugrip_pixel
= texture
->color().pixel();
553 XSetWindowBorder(blackbox
->getXDisplay(), frame
.handle
,
554 screen
->getBorderColor()->pixel());
555 XSetWindowBorder(blackbox
->getXDisplay(), frame
.left_grip
,
556 screen
->getBorderColor()->pixel());
557 XSetWindowBorder(blackbox
->getXDisplay(), frame
.right_grip
,
558 screen
->getBorderColor()->pixel());
561 XSetWindowBorder(blackbox
->getXDisplay(), frame
.window
,
562 screen
->getBorderColor()->pixel());
566 void BlackboxWindow::decorateLabel(void) {
569 texture
= &(screen
->getWindowStyle()->l_focus
);
570 frame
.flabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.flabel
);
572 frame
.flabel_pixel
= texture
->color().pixel();
574 texture
= &(screen
->getWindowStyle()->l_unfocus
);
575 frame
.ulabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.ulabel
);
577 frame
.ulabel_pixel
= texture
->color().pixel();
581 void BlackboxWindow::createHandle(void) {
582 frame
.handle
= createChildWindow(frame
.window
);
583 blackbox
->saveWindowSearch(frame
.handle
, this);
586 createChildWindow(frame
.handle
, blackbox
->getLowerLeftAngleCursor());
587 blackbox
->saveWindowSearch(frame
.left_grip
, this);
590 createChildWindow(frame
.handle
, blackbox
->getLowerRightAngleCursor());
591 blackbox
->saveWindowSearch(frame
.right_grip
, this);
595 void BlackboxWindow::destroyHandle(void) {
597 screen
->getImageControl()->removeImage(frame
.fhandle
);
600 screen
->getImageControl()->removeImage(frame
.uhandle
);
603 screen
->getImageControl()->removeImage(frame
.fgrip
);
606 screen
->getImageControl()->removeImage(frame
.ugrip
);
608 blackbox
->removeWindowSearch(frame
.left_grip
);
609 blackbox
->removeWindowSearch(frame
.right_grip
);
611 XDestroyWindow(blackbox
->getXDisplay(), frame
.left_grip
);
612 XDestroyWindow(blackbox
->getXDisplay(), frame
.right_grip
);
613 frame
.left_grip
= frame
.right_grip
= None
;
615 blackbox
->removeWindowSearch(frame
.handle
);
616 XDestroyWindow(blackbox
->getXDisplay(), frame
.handle
);
621 void BlackboxWindow::createTitlebar(void) {
622 frame
.title
= createChildWindow(frame
.window
);
623 frame
.label
= createChildWindow(frame
.title
);
624 blackbox
->saveWindowSearch(frame
.title
, this);
625 blackbox
->saveWindowSearch(frame
.label
, this);
627 if (decorations
& Decor_Iconify
) createIconifyButton();
628 if (decorations
& Decor_Maximize
) createMaximizeButton();
629 if (decorations
& Decor_Close
) createCloseButton();
633 void BlackboxWindow::destroyTitlebar(void) {
634 if (frame
.close_button
)
635 destroyCloseButton();
637 if (frame
.iconify_button
)
638 destroyIconifyButton();
640 if (frame
.maximize_button
)
641 destroyMaximizeButton();
644 screen
->getImageControl()->removeImage(frame
.ftitle
);
647 screen
->getImageControl()->removeImage(frame
.utitle
);
650 screen
->getImageControl()->removeImage(frame
.flabel
);
653 screen
->getImageControl()->removeImage(frame
.ulabel
);
656 screen
->getImageControl()->removeImage(frame
.fbutton
);
659 screen
->getImageControl()->removeImage(frame
.ubutton
);
662 screen
->getImageControl()->removeImage(frame
.pbutton
);
664 blackbox
->removeWindowSearch(frame
.title
);
665 blackbox
->removeWindowSearch(frame
.label
);
667 XDestroyWindow(blackbox
->getXDisplay(), frame
.label
);
668 XDestroyWindow(blackbox
->getXDisplay(), frame
.title
);
669 frame
.title
= frame
.label
= None
;
673 void BlackboxWindow::createCloseButton(void) {
674 if (frame
.title
!= None
) {
675 frame
.close_button
= createChildWindow(frame
.title
);
676 blackbox
->saveWindowSearch(frame
.close_button
, this);
681 void BlackboxWindow::destroyCloseButton(void) {
682 blackbox
->removeWindowSearch(frame
.close_button
);
683 XDestroyWindow(blackbox
->getXDisplay(), frame
.close_button
);
684 frame
.close_button
= None
;
688 void BlackboxWindow::createIconifyButton(void) {
689 if (frame
.title
!= None
) {
690 frame
.iconify_button
= createChildWindow(frame
.title
);
691 blackbox
->saveWindowSearch(frame
.iconify_button
, this);
696 void BlackboxWindow::destroyIconifyButton(void) {
697 blackbox
->removeWindowSearch(frame
.iconify_button
);
698 XDestroyWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
699 frame
.iconify_button
= None
;
703 void BlackboxWindow::createMaximizeButton(void) {
704 if (frame
.title
!= None
) {
705 frame
.maximize_button
= createChildWindow(frame
.title
);
706 blackbox
->saveWindowSearch(frame
.maximize_button
, this);
711 void BlackboxWindow::destroyMaximizeButton(void) {
712 blackbox
->removeWindowSearch(frame
.maximize_button
);
713 XDestroyWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
714 frame
.maximize_button
= None
;
718 void BlackboxWindow::positionButtons(bool redecorate_label
) {
719 string layout
= blackbox
->getTitlebarLayout();
722 bool hasclose
, hasiconify
, hasmaximize
, haslabel
;
723 hasclose
= hasiconify
= hasmaximize
= haslabel
= false;
725 string::const_iterator it
, end
;
726 for (it
= layout
.begin(), end
= layout
.end(); it
!= end
; ++it
) {
729 if (! hasclose
&& (decorations
& Decor_Close
)) {
735 if (! hasiconify
&& (decorations
& Decor_Iconify
)) {
741 if (! hasmaximize
&& (decorations
& Decor_Maximize
)) {
753 if (! hasclose
&& frame
.close_button
)
754 destroyCloseButton();
755 if (! hasiconify
&& frame
.iconify_button
)
756 destroyIconifyButton();
757 if (! hasmaximize
&& frame
.maximize_button
)
758 destroyMaximizeButton();
760 parsed
+= 'L'; // require that the label be in the layout
762 const unsigned int bsep
= frame
.bevel_w
+ 1; // separation between elements
763 const unsigned int by
= frame
.bevel_w
+ 1;
764 const unsigned int ty
= frame
.bevel_w
;
766 frame
.label_w
= frame
.inside_w
- bsep
* 2 -
767 (frame
.button_w
+ bsep
) * (parsed
.size() - 1);
769 unsigned int x
= bsep
;
770 for (it
= parsed
.begin(), end
= parsed
.end(); it
!= end
; ++it
) {
773 if (! frame
.close_button
) createCloseButton();
774 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.close_button
, x
, by
,
775 frame
.button_w
, frame
.button_w
);
776 x
+= frame
.button_w
+ bsep
;
779 if (! frame
.iconify_button
) createIconifyButton();
780 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.iconify_button
, x
, by
,
781 frame
.button_w
, frame
.button_w
);
782 x
+= frame
.button_w
+ bsep
;
785 if (! frame
.maximize_button
) createMaximizeButton();
786 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.maximize_button
, x
, by
,
787 frame
.button_w
, frame
.button_w
);
788 x
+= frame
.button_w
+ bsep
;
791 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.label
, x
, ty
,
792 frame
.label_w
, frame
.label_h
);
793 x
+= frame
.label_w
+ bsep
;
798 if (redecorate_label
) decorateLabel();
804 void BlackboxWindow::reconfigure(void) {
805 restoreGravity(client
.rect
);
807 applyGravity(frame
.rect
);
816 windowmenu
->move(windowmenu
->getX(), frame
.rect
.y() + frame
.title_h
);
817 windowmenu
->reconfigure();
822 void BlackboxWindow::grabButtons(void) {
823 if ((! screen
->isSloppyFocus()) || screen
->doClickRaise())
824 // grab button 1 for changing focus/raising
825 blackbox
->grabButton(Button1
, 0, frame
.plate
, True
, ButtonPressMask
,
826 GrabModeSync
, GrabModeSync
, frame
.plate
, None
);
828 if (functions
& Func_Move
)
829 blackbox
->grabButton(Button1
, Mod1Mask
, frame
.window
, True
,
830 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
831 GrabModeAsync
, frame
.window
,
832 blackbox
->getMoveCursor());
833 if (functions
& Func_Resize
)
834 blackbox
->grabButton(Button3
, Mod1Mask
, frame
.window
, True
,
835 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
836 GrabModeAsync
, frame
.window
, None
);
837 // alt+middle lowers the window
838 blackbox
->grabButton(Button2
, Mod1Mask
, frame
.window
, True
,
839 ButtonReleaseMask
, GrabModeAsync
, GrabModeAsync
,
844 void BlackboxWindow::ungrabButtons(void) {
845 if ((! screen
->isSloppyFocus()) || screen
->doClickRaise())
846 blackbox
->ungrabButton(Button1
, 0, frame
.plate
);
848 blackbox
->ungrabButton(Button1
, Mod1Mask
, frame
.window
);
849 blackbox
->ungrabButton(Button2
, Mod1Mask
, frame
.window
);
850 blackbox
->ungrabButton(Button3
, Mod1Mask
, frame
.window
);
854 void BlackboxWindow::positionWindows(void) {
855 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.window
,
856 frame
.rect
.x(), frame
.rect
.y(), frame
.inside_w
,
857 (flags
.shaded
) ? frame
.title_h
: frame
.inside_h
);
858 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.window
,
860 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.plate
,
862 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.plate
,
863 frame
.margin
.left
- frame
.mwm_border_w
- frame
.border_w
,
864 frame
.margin
.top
- frame
.mwm_border_w
- frame
.border_w
,
865 client
.rect
.width(), client
.rect
.height());
866 XMoveResizeWindow(blackbox
->getXDisplay(), client
.window
,
867 0, 0, client
.rect
.width(), client
.rect
.height());
868 // ensure client.rect contains the real location
869 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
870 frame
.rect
.top() + frame
.margin
.top
);
872 if (decorations
& Decor_Titlebar
) {
873 if (frame
.title
== None
) createTitlebar();
875 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.title
,
877 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.title
, -frame
.border_w
,
878 -frame
.border_w
, frame
.inside_w
, frame
.title_h
);
881 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
882 XMapWindow(blackbox
->getXDisplay(), frame
.title
);
883 } else if (frame
.title
) {
886 if (decorations
& Decor_Handle
) {
887 if (frame
.handle
== None
) createHandle();
888 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.handle
,
890 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.left_grip
,
892 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.right_grip
,
895 // use client.rect here so the value is correct even if shaded
896 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.handle
,
898 client
.rect
.height() + frame
.margin
.top
+
899 frame
.mwm_border_w
- frame
.border_w
,
900 frame
.inside_w
, frame
.handle_h
);
901 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.left_grip
,
902 -frame
.border_w
, -frame
.border_w
,
903 frame
.grip_w
, frame
.handle_h
);
904 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.right_grip
,
905 frame
.inside_w
- frame
.grip_w
- frame
.border_w
,
906 -frame
.border_w
, frame
.grip_w
, frame
.handle_h
);
908 XMapSubwindows(blackbox
->getXDisplay(), frame
.handle
);
909 XMapWindow(blackbox
->getXDisplay(), frame
.handle
);
910 } else if (frame
.handle
) {
913 XSync(blackbox
->getXDisplay(), False
);
917 void BlackboxWindow::updateStrut(void) {
918 unsigned long num
= 4;
920 if (! xatom
->getValue(client
.window
, XAtom::net_wm_strut
, XAtom::cardinal
,
925 client
.strut
.left
= data
[0];
926 client
.strut
.right
= data
[1];
927 client
.strut
.top
= data
[2];
928 client
.strut
.bottom
= data
[3];
930 screen
->updateAvailableArea();
937 void BlackboxWindow::getWindowType(void) {
939 if (xatom
->getValue(client
.window
, XAtom::net_wm_window_type
, XAtom::atom
,
941 if (val
== xatom
->getAtom(XAtom::net_wm_window_type_desktop
))
942 window_type
= Type_Desktop
;
943 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_dock
))
944 window_type
= Type_Dock
;
945 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_toolbar
))
946 window_type
= Type_Toolbar
;
947 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_menu
))
948 window_type
= Type_Menu
;
949 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_utility
))
950 window_type
= Type_Utility
;
951 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_splash
))
952 window_type
= Type_Splash
;
953 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_dialog
))
954 window_type
= Type_Dialog
;
955 else //if (val[0] == xatom->getAtom(XAtom::net_wm_window_type_normal))
956 window_type
= Type_Normal
;
961 * the window type hint was not set, which means we either classify ourself
962 * as a normal window or a dialog, depending on if we are a transient.
965 window_type
= Type_Dialog
;
967 window_type
= Type_Normal
;
971 void BlackboxWindow::getWMName(void) {
972 if (xatom
->getValue(client
.window
, XAtom::net_wm_name
,
973 XAtom::utf8
, client
.title
) &&
974 !client
.title
.empty()) {
975 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
978 //fall through to using WM_NAME
979 if (xatom
->getValue(client
.window
, XAtom::wm_name
, XAtom::ansi
, client
.title
)
980 && !client
.title
.empty()) {
981 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
984 // fall back to an internal default
985 client
.title
= i18n(WindowSet
, WindowUnnamed
, "Unnamed");
986 xatom
->setValue(client
.window
, XAtom::net_wm_visible_name
, XAtom::utf8
,
991 void BlackboxWindow::getWMIconName(void) {
992 if (xatom
->getValue(client
.window
, XAtom::net_wm_icon_name
,
993 XAtom::utf8
, client
.icon_title
) &&
994 !client
.icon_title
.empty()) {
995 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
998 //fall through to using WM_ICON_NAME
999 if (xatom
->getValue(client
.window
, XAtom::wm_icon_name
, XAtom::ansi
,
1000 client
.icon_title
) &&
1001 !client
.icon_title
.empty()) {
1002 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1005 // fall back to using the main name
1006 client
.icon_title
= client
.title
;
1007 xatom
->setValue(client
.window
, XAtom::net_wm_visible_icon_name
, XAtom::utf8
,
1013 * Retrieve which WM Protocols are supported by the client window.
1014 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
1015 * window's decorations and allow the close behavior.
1016 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
1019 void BlackboxWindow::getWMProtocols(void) {
1023 if (XGetWMProtocols(blackbox
->getXDisplay(), client
.window
,
1024 &proto
, &num_return
)) {
1025 for (int i
= 0; i
< num_return
; ++i
) {
1026 if (proto
[i
] == xatom
->getAtom(XAtom::wm_delete_window
)) {
1027 decorations
|= Decor_Close
;
1028 functions
|= Func_Close
;
1029 } else if (proto
[i
] == xatom
->getAtom(XAtom::wm_take_focus
))
1030 flags
.send_focus_message
= True
;
1031 else if (proto
[i
] == xatom
->getAtom(XAtom::blackbox_structure_messages
))
1032 screen
->addNetizen(new Netizen(screen
, client
.window
));
1041 * Gets the value of the WM_HINTS property.
1042 * If the property is not set, then use a set of default values.
1044 void BlackboxWindow::getWMHints(void) {
1045 focus_mode
= F_Passive
;
1046 client
.initial_state
= NormalState
;
1048 // remove from current window group
1049 if (client
.window_group
) {
1050 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1051 if (group
) group
->removeWindow(this);
1053 client
.window_group
= None
;
1055 XWMHints
*wmhint
= XGetWMHints(blackbox
->getXDisplay(), client
.window
);
1060 if (wmhint
->flags
& InputHint
) {
1061 if (wmhint
->input
== True
) {
1062 if (flags
.send_focus_message
)
1063 focus_mode
= F_LocallyActive
;
1065 if (flags
.send_focus_message
)
1066 focus_mode
= F_GloballyActive
;
1068 focus_mode
= F_NoInput
;
1072 if (wmhint
->flags
& StateHint
)
1073 client
.initial_state
= wmhint
->initial_state
;
1075 if (wmhint
->flags
& WindowGroupHint
) {
1076 client
.window_group
= wmhint
->window_group
;
1078 // add window to the appropriate group
1079 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1080 if (! group
) { // no group found, create it!
1081 new BWindowGroup(blackbox
, client
.window_group
);
1082 group
= blackbox
->searchGroup(client
.window_group
);
1085 group
->addWindow(this);
1088 client
.wm_hint_flags
= wmhint
->flags
;
1094 * Gets the value of the WM_NORMAL_HINTS property.
1095 * If the property is not set, then use a set of default values.
1097 void BlackboxWindow::getWMNormalHints(void) {
1099 XSizeHints sizehint
;
1101 client
.min_width
= client
.min_height
=
1102 client
.width_inc
= client
.height_inc
= 1;
1103 client
.base_width
= client
.base_height
= 0;
1104 client
.win_gravity
= NorthWestGravity
;
1106 client
.min_aspect_x
= client
.min_aspect_y
=
1107 client
.max_aspect_x
= client
.max_aspect_y
= 1;
1111 use the full screen, not the strut modified size. otherwise when the
1112 availableArea changes max_width/height will be incorrect and lead to odd
1115 const Rect
& screen_area
= screen
->getRect();
1116 client
.max_width
= screen_area
.width();
1117 client
.max_height
= screen_area
.height();
1119 if (! XGetWMNormalHints(blackbox
->getXDisplay(), client
.window
,
1120 &sizehint
, &icccm_mask
))
1123 client
.normal_hint_flags
= sizehint
.flags
;
1125 if (sizehint
.flags
& PMinSize
) {
1126 if (sizehint
.min_width
>= 0)
1127 client
.min_width
= sizehint
.min_width
;
1128 if (sizehint
.min_height
>= 0)
1129 client
.min_height
= sizehint
.min_height
;
1132 if (sizehint
.flags
& PMaxSize
) {
1133 if (sizehint
.max_width
> static_cast<signed>(client
.min_width
))
1134 client
.max_width
= sizehint
.max_width
;
1136 client
.max_width
= client
.min_width
;
1138 if (sizehint
.max_height
> static_cast<signed>(client
.min_height
))
1139 client
.max_height
= sizehint
.max_height
;
1141 client
.max_height
= client
.min_height
;
1144 if (sizehint
.flags
& PResizeInc
) {
1145 client
.width_inc
= sizehint
.width_inc
;
1146 client
.height_inc
= sizehint
.height_inc
;
1149 #if 0 // we do not support this at the moment
1150 if (sizehint
.flags
& PAspect
) {
1151 client
.min_aspect_x
= sizehint
.min_aspect
.x
;
1152 client
.min_aspect_y
= sizehint
.min_aspect
.y
;
1153 client
.max_aspect_x
= sizehint
.max_aspect
.x
;
1154 client
.max_aspect_y
= sizehint
.max_aspect
.y
;
1158 if (sizehint
.flags
& PBaseSize
) {
1159 client
.base_width
= sizehint
.base_width
;
1160 client
.base_height
= sizehint
.base_height
;
1163 if (sizehint
.flags
& PWinGravity
)
1164 client
.win_gravity
= sizehint
.win_gravity
;
1169 * Gets the NETWM hints for the class' contained window.
1171 void BlackboxWindow::getNetWMHints(void) {
1172 unsigned long workspace
;
1174 if (xatom
->getValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1176 if (workspace
== 0xffffffff)
1179 blackbox_attrib
.workspace
= workspace
;
1182 unsigned long *state
;
1183 unsigned long num
= (unsigned) -1;
1184 if (xatom
->getValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
1188 for (unsigned long i
= 0; i
< num
; ++i
) {
1189 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
))
1191 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_shaded
))
1192 flags
.shaded
= True
;
1193 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
))
1194 flags
.skip_taskbar
= True
;
1195 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_pager
))
1196 flags
.skip_pager
= True
;
1197 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_fullscreen
))
1198 flags
.fullscreen
= True
;
1199 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_hidden
))
1200 setState(IconicState
);
1201 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_vert
))
1203 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_horz
))
1207 flags
.maximized
= 1;
1209 flags
.maximized
= 2;
1211 flags
.maximized
= 3;
1219 * Gets the MWM hints for the class' contained window.
1220 * This is used while initializing the window to its first state, and not
1222 * Returns: true if the MWM hints are successfully retreived and applied;
1223 * false if they are not.
1225 void BlackboxWindow::getMWMHints(void) {
1229 num
= PropMwmHintsElements
;
1230 if (! xatom
->getValue(client
.window
, XAtom::motif_wm_hints
,
1231 XAtom::motif_wm_hints
, num
,
1232 (unsigned long **)&mwm_hint
))
1234 if (num
< PropMwmHintsElements
) {
1239 if (mwm_hint
->flags
& MwmHintsDecorations
) {
1240 if (mwm_hint
->decorations
& MwmDecorAll
) {
1241 decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
1242 Decor_Iconify
| Decor_Maximize
| Decor_Close
;
1246 if (mwm_hint
->decorations
& MwmDecorBorder
)
1247 decorations
|= Decor_Border
;
1248 if (mwm_hint
->decorations
& MwmDecorHandle
)
1249 decorations
|= Decor_Handle
;
1250 if (mwm_hint
->decorations
& MwmDecorTitle
)
1251 decorations
|= Decor_Titlebar
;
1252 if (mwm_hint
->decorations
& MwmDecorIconify
)
1253 decorations
|= Decor_Iconify
;
1254 if (mwm_hint
->decorations
& MwmDecorMaximize
)
1255 decorations
|= Decor_Maximize
;
1259 if (mwm_hint
->flags
& MwmHintsFunctions
) {
1260 if (mwm_hint
->functions
& MwmFuncAll
) {
1261 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
|
1266 if (mwm_hint
->functions
& MwmFuncResize
)
1267 functions
|= Func_Resize
;
1268 if (mwm_hint
->functions
& MwmFuncMove
)
1269 functions
|= Func_Move
;
1270 if (mwm_hint
->functions
& MwmFuncIconify
)
1271 functions
|= Func_Iconify
;
1272 if (mwm_hint
->functions
& MwmFuncMaximize
)
1273 functions
|= Func_Maximize
;
1274 if (mwm_hint
->functions
& MwmFuncClose
)
1275 functions
|= Func_Close
;
1283 * Gets the blackbox hints from the class' contained window.
1284 * This is used while initializing the window to its first state, and not
1286 * Returns: true if the hints are successfully retreived and applied; false if
1289 bool BlackboxWindow::getBlackboxHints(void) {
1291 BlackboxHints
*blackbox_hint
;
1293 num
= PropBlackboxHintsElements
;
1294 if (! xatom
->getValue(client
.window
, XAtom::blackbox_hints
,
1295 XAtom::blackbox_hints
, num
,
1296 (unsigned long **)&blackbox_hint
))
1298 if (num
< PropBlackboxHintsElements
) {
1299 delete [] blackbox_hint
;
1303 if (blackbox_hint
->flags
& AttribShaded
)
1304 flags
.shaded
= (blackbox_hint
->attrib
& AttribShaded
);
1306 if ((blackbox_hint
->flags
& AttribMaxHoriz
) &&
1307 (blackbox_hint
->flags
& AttribMaxVert
))
1308 flags
.maximized
= (blackbox_hint
->attrib
&
1309 (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1310 else if (blackbox_hint
->flags
& AttribMaxVert
)
1311 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxVert
) ? 2 : 0;
1312 else if (blackbox_hint
->flags
& AttribMaxHoriz
)
1313 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1315 if (blackbox_hint
->flags
& AttribOmnipresent
)
1316 flags
.stuck
= (blackbox_hint
->attrib
& AttribOmnipresent
);
1318 if (blackbox_hint
->flags
& AttribWorkspace
)
1319 blackbox_attrib
.workspace
= blackbox_hint
->workspace
;
1321 // if (blackbox_hint->flags & AttribStack)
1322 // don't yet have always on top/bottom for blackbox yet... working
1325 if (blackbox_hint
->flags
& AttribDecoration
) {
1326 switch (blackbox_hint
->decoration
) {
1328 // clear all decorations except close
1329 decorations
&= Decor_Close
;
1330 // clear all functions except close
1331 functions
&= Func_Close
;
1336 decorations
|= Decor_Titlebar
| Decor_Iconify
;
1337 decorations
&= ~(Decor_Border
| Decor_Handle
| Decor_Maximize
);
1338 functions
|= Func_Move
| Func_Iconify
;
1339 functions
&= ~(Func_Resize
| Func_Maximize
);
1344 decorations
|= Decor_Titlebar
;
1345 decorations
&= ~(Decor_Iconify
| Decor_Border
| Decor_Handle
);
1346 functions
|= Func_Move
;
1347 functions
&= ~(Func_Resize
| Func_Maximize
| Func_Iconify
);
1353 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Handle
|
1354 Decor_Iconify
| Decor_Maximize
;
1355 functions
|= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
1363 delete [] blackbox_hint
;
1369 void BlackboxWindow::getTransientInfo(void) {
1370 if (client
.transient_for
&&
1371 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1372 // the transient for hint was removed, so we need to tell our
1373 // previous transient_for that we are going away
1374 client
.transient_for
->client
.transientList
.remove(this);
1377 // we have no transient_for until we find a new one
1378 client
.transient_for
= 0;
1381 if (! XGetTransientForHint(blackbox
->getXDisplay(), client
.window
,
1383 // transient_for hint not set
1387 if (trans_for
== client
.window
) {
1388 // wierd client... treat this window as a normal window
1392 if (trans_for
== None
|| trans_for
== screen
->getRootWindow()) {
1393 // this is an undocumented interpretation of the ICCCM. a transient
1394 // associated with None/Root/itself is assumed to be a modal root
1395 // transient. we don't support the concept of a global transient,
1396 // so we just associate this transient with nothing, and perhaps
1397 // we will add support later for global modality.
1398 client
.transient_for
= (BlackboxWindow
*) ~0ul;
1403 client
.transient_for
= blackbox
->searchWindow(trans_for
);
1404 if (! client
.transient_for
&&
1405 client
.window_group
&& trans_for
== client
.window_group
) {
1406 // no direct transient_for, perhaps this is a group transient?
1407 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1408 if (group
) client
.transient_for
= group
->find(screen
);
1411 if (! client
.transient_for
|| client
.transient_for
== this) {
1412 // no transient_for found, or we have a wierd client that wants to be
1413 // a transient for itself, so we treat this window as a normal window
1414 client
.transient_for
= (BlackboxWindow
*) 0;
1418 // register ourselves with our new transient_for
1419 client
.transient_for
->client
.transientList
.push_back(this);
1420 flags
.stuck
= client
.transient_for
->flags
.stuck
;
1424 BlackboxWindow
*BlackboxWindow::getTransientFor(void) const {
1425 if (client
.transient_for
&&
1426 client
.transient_for
!= (BlackboxWindow
*) ~0ul)
1427 return client
.transient_for
;
1433 * This function is responsible for updating both the client and the frame
1435 * According to the ICCCM a client message is not sent for a resize, only a
1438 void BlackboxWindow::configure(int dx
, int dy
,
1439 unsigned int dw
, unsigned int dh
) {
1440 bool send_event
= ((frame
.rect
.x() != dx
|| frame
.rect
.y() != dy
) &&
1443 if (dw
!= frame
.rect
.width() || dh
!= frame
.rect
.height()) {
1444 frame
.rect
.setRect(dx
, dy
, dw
, dh
);
1445 frame
.inside_w
= frame
.rect
.width() - (frame
.border_w
* 2);
1446 frame
.inside_h
= frame
.rect
.height() - (frame
.border_w
* 2);
1448 if (frame
.rect
.right() <= 0 || frame
.rect
.bottom() <= 0)
1449 frame
.rect
.setPos(0, 0);
1451 client
.rect
.setCoords(frame
.rect
.left() + frame
.margin
.left
,
1452 frame
.rect
.top() + frame
.margin
.top
,
1453 frame
.rect
.right() - frame
.margin
.right
,
1454 frame
.rect
.bottom() - frame
.margin
.bottom
);
1457 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
1464 redrawWindowFrame();
1466 frame
.rect
.setPos(dx
, dy
);
1468 XMoveWindow(blackbox
->getXDisplay(), frame
.window
,
1469 frame
.rect
.x(), frame
.rect
.y());
1471 we may have been called just after an opaque window move, so even though
1472 the old coords match the new ones no ConfigureNotify has been sent yet.
1473 There are likely other times when this will be relevant as well.
1475 if (! flags
.moving
) send_event
= True
;
1479 // if moving, the update and event will occur when the move finishes
1480 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1481 frame
.rect
.top() + frame
.margin
.top
);
1484 event
.type
= ConfigureNotify
;
1486 event
.xconfigure
.display
= blackbox
->getXDisplay();
1487 event
.xconfigure
.event
= client
.window
;
1488 event
.xconfigure
.window
= client
.window
;
1489 event
.xconfigure
.x
= client
.rect
.x();
1490 event
.xconfigure
.y
= client
.rect
.y();
1491 event
.xconfigure
.width
= client
.rect
.width();
1492 event
.xconfigure
.height
= client
.rect
.height();
1493 event
.xconfigure
.border_width
= client
.old_bw
;
1494 event
.xconfigure
.above
= frame
.window
;
1495 event
.xconfigure
.override_redirect
= False
;
1497 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1498 StructureNotifyMask
, &event
);
1499 screen
->updateNetizenConfigNotify(&event
);
1500 XFlush(blackbox
->getXDisplay());
1506 void BlackboxWindow::configureShape(void) {
1507 XShapeCombineShape(blackbox
->getXDisplay(), frame
.window
, ShapeBounding
,
1508 frame
.margin
.left
- frame
.border_w
,
1509 frame
.margin
.top
- frame
.border_w
,
1510 client
.window
, ShapeBounding
, ShapeSet
);
1513 XRectangle xrect
[2];
1515 if (decorations
& Decor_Titlebar
) {
1516 xrect
[0].x
= xrect
[0].y
= -frame
.border_w
;
1517 xrect
[0].width
= frame
.rect
.width();
1518 xrect
[0].height
= frame
.title_h
+ (frame
.border_w
* 2);
1522 if (decorations
& Decor_Handle
) {
1523 xrect
[1].x
= -frame
.border_w
;
1524 xrect
[1].y
= frame
.rect
.height() - frame
.margin
.bottom
+
1525 frame
.mwm_border_w
- frame
.border_w
;
1526 xrect
[1].width
= frame
.rect
.width();
1527 xrect
[1].height
= frame
.handle_h
+ (frame
.border_w
* 2);
1531 XShapeCombineRectangles(blackbox
->getXDisplay(), frame
.window
,
1532 ShapeBounding
, 0, 0, xrect
, num
,
1533 ShapeUnion
, Unsorted
);
1538 bool BlackboxWindow::setInputFocus(void) {
1539 if (flags
.focused
) return True
;
1541 assert(! flags
.iconic
&&
1542 (flags
.stuck
|| // window must be on the current workspace or sticky
1543 blackbox_attrib
.workspace
== screen
->getCurrentWorkspaceID()));
1545 // if the window is not visible, mark the window as wanting focus rather
1546 // than give it focus.
1547 if (! flags
.visible
) {
1548 Workspace
*wkspc
= screen
->getWorkspace(blackbox_attrib
.workspace
);
1549 wkspc
->setLastFocusedWindow(this);
1554 We only do this check for normal windows and dialogs because other windows
1555 do this on purpose, such as kde's kicker, and we don't want to go moving
1558 if (window_type
== Type_Normal
|| window_type
== Type_Dialog
)
1559 if (! frame
.rect
.intersects(screen
->getRect())) {
1560 // client is outside the screen, move it to the center
1561 configure((screen
->getWidth() - frame
.rect
.width()) / 2,
1562 (screen
->getHeight() - frame
.rect
.height()) / 2,
1563 frame
.rect
.width(), frame
.rect
.height());
1566 if (client
.transientList
.size() > 0) {
1567 // transfer focus to any modal transients
1568 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1569 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1570 if ((*it
)->flags
.modal
) return (*it
)->setInputFocus();
1575 if (focus_mode
== F_LocallyActive
|| focus_mode
== F_Passive
) {
1576 XSetInputFocus(blackbox
->getXDisplay(), client
.window
,
1577 RevertToPointerRoot
, CurrentTime
);
1579 blackbox
->setFocusedWindow(this);
1581 /* we could set the focus to none, since the window doesn't accept focus,
1582 * but we shouldn't set focus to nothing since this would surely make
1588 if (flags
.send_focus_message
) {
1590 ce
.xclient
.type
= ClientMessage
;
1591 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1592 ce
.xclient
.display
= blackbox
->getXDisplay();
1593 ce
.xclient
.window
= client
.window
;
1594 ce
.xclient
.format
= 32;
1595 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_take_focus
);
1596 ce
.xclient
.data
.l
[1] = blackbox
->getLastTime();
1597 ce
.xclient
.data
.l
[2] = 0l;
1598 ce
.xclient
.data
.l
[3] = 0l;
1599 ce
.xclient
.data
.l
[4] = 0l;
1600 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1602 XFlush(blackbox
->getXDisplay());
1609 void BlackboxWindow::iconify(void) {
1610 if (flags
.iconic
) return;
1612 // We don't need to worry about resizing because resizing always grabs the X
1613 // server. This should only ever happen if using opaque moving.
1617 if (windowmenu
) windowmenu
->hide();
1620 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1621 * we need to clear the event mask on client.window for a split second.
1622 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1623 * split second, leaving us with a ghost window... so, we need to do this
1624 * while the X server is grabbed
1626 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1627 StructureNotifyMask
;
1628 XGrabServer(blackbox
->getXDisplay());
1629 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1630 event_mask
& ~StructureNotifyMask
);
1631 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1632 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1633 XUngrabServer(blackbox
->getXDisplay());
1635 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1636 flags
.visible
= False
;
1637 flags
.iconic
= True
;
1639 setState(IconicState
);
1641 screen
->getWorkspace(blackbox_attrib
.workspace
)->removeWindow(this);
1643 if (isTransient()) {
1644 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1645 ! client
.transient_for
->flags
.iconic
) {
1646 // iconify our transient_for
1647 client
.transient_for
->iconify();
1651 screen
->addIcon(this);
1653 if (client
.transientList
.size() > 0) {
1654 // iconify all transients
1655 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1656 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1657 if (! (*it
)->flags
.iconic
) (*it
)->iconify();
1660 screen
->updateStackingList();
1664 void BlackboxWindow::show(void) {
1665 flags
.visible
= True
;
1666 flags
.iconic
= False
;
1668 current_state
= (flags
.shaded
) ? IconicState
: NormalState
;
1669 setState(current_state
);
1671 XMapWindow(blackbox
->getXDisplay(), client
.window
);
1672 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
1673 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
1678 XTranslateCoordinates(blackbox
->getXDisplay(), client
.window
,
1679 screen
->getRootWindow(),
1680 0, 0, &real_x
, &real_y
, &child
);
1681 fprintf(stderr
, "%s -- assumed: (%d, %d), real: (%d, %d)\n", getTitle(),
1682 client
.rect
.left(), client
.rect
.top(), real_x
, real_y
);
1683 assert(client
.rect
.left() == real_x
&& client
.rect
.top() == real_y
);
1688 void BlackboxWindow::deiconify(bool reassoc
, bool raise
) {
1689 if (flags
.iconic
|| reassoc
)
1690 screen
->reassociateWindow(this, BSENTINEL
, False
);
1691 else if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID())
1696 // reassociate and deiconify all transients
1697 if (reassoc
&& client
.transientList
.size() > 0) {
1698 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1699 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1700 (*it
)->deiconify(True
, False
);
1705 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1709 void BlackboxWindow::close(void) {
1711 ce
.xclient
.type
= ClientMessage
;
1712 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1713 ce
.xclient
.display
= blackbox
->getXDisplay();
1714 ce
.xclient
.window
= client
.window
;
1715 ce
.xclient
.format
= 32;
1716 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_delete_window
);
1717 ce
.xclient
.data
.l
[1] = CurrentTime
;
1718 ce
.xclient
.data
.l
[2] = 0l;
1719 ce
.xclient
.data
.l
[3] = 0l;
1720 ce
.xclient
.data
.l
[4] = 0l;
1721 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
, NoEventMask
, &ce
);
1722 XFlush(blackbox
->getXDisplay());
1726 void BlackboxWindow::withdraw(void) {
1727 // We don't need to worry about resizing because resizing always grabs the X
1728 // server. This should only ever happen if using opaque moving.
1732 flags
.visible
= False
;
1733 flags
.iconic
= False
;
1735 setState(current_state
);
1737 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1739 XGrabServer(blackbox
->getXDisplay());
1741 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1742 StructureNotifyMask
;
1743 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1744 event_mask
& ~StructureNotifyMask
);
1745 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1746 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1748 XUngrabServer(blackbox
->getXDisplay());
1750 if (windowmenu
) windowmenu
->hide();
1754 void BlackboxWindow::maximize(unsigned int button
) {
1755 // We don't need to worry about resizing because resizing always grabs the X
1756 // server. This should only ever happen if using opaque moving.
1760 // handle case where menu is open then the max button is used instead
1761 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
1763 if (flags
.maximized
) {
1764 flags
.maximized
= 0;
1766 blackbox_attrib
.flags
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1767 blackbox_attrib
.attrib
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1770 when a resize finishes, maximize(0) is called to clear any maximization
1771 flags currently set. Otherwise it still thinks it is maximized.
1772 so we do not need to call configure() because resizing will handle it
1774 if (! flags
.resizing
)
1775 configure(blackbox_attrib
.premax_x
, blackbox_attrib
.premax_y
,
1776 blackbox_attrib
.premax_w
, blackbox_attrib
.premax_h
);
1778 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
1779 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
1781 redrawAllButtons(); // in case it is not called in configure()
1782 setState(current_state
);
1786 blackbox_attrib
.premax_x
= frame
.rect
.x();
1787 blackbox_attrib
.premax_y
= frame
.rect
.y();
1788 blackbox_attrib
.premax_w
= frame
.rect
.width();
1789 // use client.rect so that clients can be restored even if shaded
1790 blackbox_attrib
.premax_h
=
1791 client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
;
1793 const Rect
&screen_area
= screen
->availableArea();
1794 frame
.changing
= screen_area
;
1798 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1799 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1803 blackbox_attrib
.flags
|= AttribMaxVert
;
1804 blackbox_attrib
.attrib
|= AttribMaxVert
;
1806 frame
.changing
.setX(frame
.rect
.x());
1807 frame
.changing
.setWidth(frame
.rect
.width());
1811 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1812 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1814 frame
.changing
.setY(frame
.rect
.y());
1815 frame
.changing
.setHeight(frame
.rect
.height());
1822 blackbox_attrib
.flags
^= AttribShaded
;
1823 blackbox_attrib
.attrib
^= AttribShaded
;
1824 flags
.shaded
= False
;
1827 flags
.maximized
= button
;
1829 configure(frame
.changing
.x(), frame
.changing
.y(),
1830 frame
.changing
.width(), frame
.changing
.height());
1832 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1833 redrawAllButtons(); // in case it is not called in configure()
1834 setState(current_state
);
1838 // re-maximizes the window to take into account availableArea changes
1839 void BlackboxWindow::remaximize(void) {
1840 // save the original dimensions because maximize will wipe them out
1841 int premax_x
= blackbox_attrib
.premax_x
,
1842 premax_y
= blackbox_attrib
.premax_y
,
1843 premax_w
= blackbox_attrib
.premax_w
,
1844 premax_h
= blackbox_attrib
.premax_h
;
1846 unsigned int button
= flags
.maximized
;
1847 flags
.maximized
= 0; // trick maximize() into working
1850 // restore saved values
1851 blackbox_attrib
.premax_x
= premax_x
;
1852 blackbox_attrib
.premax_y
= premax_y
;
1853 blackbox_attrib
.premax_w
= premax_w
;
1854 blackbox_attrib
.premax_h
= premax_h
;
1858 void BlackboxWindow::setWorkspace(unsigned int n
) {
1859 blackbox_attrib
.flags
|= AttribWorkspace
;
1860 blackbox_attrib
.workspace
= n
;
1861 if (n
== BSENTINEL
) { // iconified window
1863 we set the workspace to 'all workspaces' so that taskbars will show the
1864 window. otherwise, it made uniconifying a window imposible without the
1865 blackbox workspace menu
1869 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
, n
);
1873 void BlackboxWindow::shade(void) {
1875 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1876 frame
.inside_w
, frame
.inside_h
);
1877 flags
.shaded
= False
;
1878 blackbox_attrib
.flags
^= AttribShaded
;
1879 blackbox_attrib
.attrib
^= AttribShaded
;
1881 setState(NormalState
);
1883 // set the frame rect to the normal size
1884 frame
.rect
.setHeight(client
.rect
.height() + frame
.margin
.top
+
1885 frame
.margin
.bottom
);
1887 if (! (decorations
& Decor_Titlebar
))
1888 return; // can't shade it without a titlebar!
1890 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1891 frame
.inside_w
, frame
.title_h
);
1892 flags
.shaded
= True
;
1893 blackbox_attrib
.flags
|= AttribShaded
;
1894 blackbox_attrib
.attrib
|= AttribShaded
;
1896 setState(IconicState
);
1898 // set the frame rect to the shaded size
1899 frame
.rect
.setHeight(frame
.title_h
+ (frame
.border_w
* 2));
1905 * (Un)Sticks a window and its relatives.
1907 void BlackboxWindow::stick(void) {
1909 blackbox_attrib
.flags
^= AttribOmnipresent
;
1910 blackbox_attrib
.attrib
^= AttribOmnipresent
;
1912 flags
.stuck
= False
;
1915 screen
->reassociateWindow(this, BSENTINEL
, True
);
1916 // temporary fix since sticky windows suck. set the hint to what we
1917 // actually hold in our data.
1918 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1919 blackbox_attrib
.workspace
);
1921 setState(current_state
);
1925 blackbox_attrib
.flags
|= AttribOmnipresent
;
1926 blackbox_attrib
.attrib
|= AttribOmnipresent
;
1928 // temporary fix since sticky windows suck. set the hint to a different
1929 // value than that contained in the class' data.
1930 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1933 setState(current_state
);
1936 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1937 client
.transient_for
->isStuck() != flags
.stuck
)
1938 client
.transient_for
->stick();
1939 // go down the chain
1940 BlackboxWindowList::iterator it
;
1941 const BlackboxWindowList::iterator end
= client
.transientList
.end();
1942 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1943 if ((*it
)->isStuck() != flags
.stuck
)
1948 void BlackboxWindow::redrawWindowFrame(void) const {
1949 if (decorations
& Decor_Titlebar
) {
1950 if (flags
.focused
) {
1952 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1953 frame
.title
, frame
.ftitle
);
1955 XSetWindowBackground(blackbox
->getXDisplay(),
1956 frame
.title
, frame
.ftitle_pixel
);
1959 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1960 frame
.title
, frame
.utitle
);
1962 XSetWindowBackground(blackbox
->getXDisplay(),
1963 frame
.title
, frame
.utitle_pixel
);
1965 XClearWindow(blackbox
->getXDisplay(), frame
.title
);
1971 if (decorations
& Decor_Handle
) {
1972 if (flags
.focused
) {
1974 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1975 frame
.handle
, frame
.fhandle
);
1977 XSetWindowBackground(blackbox
->getXDisplay(),
1978 frame
.handle
, frame
.fhandle_pixel
);
1981 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1982 frame
.left_grip
, frame
.fgrip
);
1983 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1984 frame
.right_grip
, frame
.fgrip
);
1986 XSetWindowBackground(blackbox
->getXDisplay(),
1987 frame
.left_grip
, frame
.fgrip_pixel
);
1988 XSetWindowBackground(blackbox
->getXDisplay(),
1989 frame
.right_grip
, frame
.fgrip_pixel
);
1993 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1994 frame
.handle
, frame
.uhandle
);
1996 XSetWindowBackground(blackbox
->getXDisplay(),
1997 frame
.handle
, frame
.uhandle_pixel
);
2000 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2001 frame
.left_grip
, frame
.ugrip
);
2002 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2003 frame
.right_grip
, frame
.ugrip
);
2005 XSetWindowBackground(blackbox
->getXDisplay(),
2006 frame
.left_grip
, frame
.ugrip_pixel
);
2007 XSetWindowBackground(blackbox
->getXDisplay(),
2008 frame
.right_grip
, frame
.ugrip_pixel
);
2011 XClearWindow(blackbox
->getXDisplay(), frame
.handle
);
2012 XClearWindow(blackbox
->getXDisplay(), frame
.left_grip
);
2013 XClearWindow(blackbox
->getXDisplay(), frame
.right_grip
);
2016 if (decorations
& Decor_Border
) {
2018 XSetWindowBorder(blackbox
->getXDisplay(),
2019 frame
.plate
, frame
.fborder_pixel
);
2021 XSetWindowBorder(blackbox
->getXDisplay(),
2022 frame
.plate
, frame
.uborder_pixel
);
2027 void BlackboxWindow::setFocusFlag(bool focus
) {
2028 // only focus a window if it is visible
2029 if (focus
&& !flags
.visible
)
2032 flags
.focused
= focus
;
2034 redrawWindowFrame();
2036 if (screen
->isSloppyFocus() && screen
->doAutoRaise()) {
2037 if (isFocused()) timer
->start();
2042 blackbox
->setFocusedWindow(this);
2044 Clientmenu
*menu
= screen
->getWorkspace(blackbox_attrib
.workspace
)->getMenu();
2045 menu
->setItemSelected(window_number
, isFocused());
2049 void BlackboxWindow::installColormap(bool install
) {
2050 int i
= 0, ncmap
= 0;
2051 Colormap
*cmaps
= XListInstalledColormaps(blackbox
->getXDisplay(),
2052 client
.window
, &ncmap
);
2054 XWindowAttributes wattrib
;
2055 if (XGetWindowAttributes(blackbox
->getXDisplay(),
2056 client
.window
, &wattrib
)) {
2058 // install the window's colormap
2059 for (i
= 0; i
< ncmap
; i
++) {
2060 if (*(cmaps
+ i
) == wattrib
.colormap
)
2061 // this window is using an installed color map... do not install
2064 // otherwise, install the window's colormap
2066 XInstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2068 // uninstall the window's colormap
2069 for (i
= 0; i
< ncmap
; i
++) {
2070 if (*(cmaps
+ i
) == wattrib
.colormap
)
2071 // we found the colormap to uninstall
2072 XUninstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2082 void BlackboxWindow::setAllowedActions(void) {
2086 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_shade
);
2087 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_change_desktop
);
2088 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_close
);
2090 if (functions
& Func_Move
)
2091 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_move
);
2092 if (functions
& Func_Resize
)
2093 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_resize
);
2094 if (functions
& Func_Maximize
) {
2095 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_horz
);
2096 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_vert
);
2099 xatom
->setValue(client
.window
, XAtom::net_wm_allowed_actions
, XAtom::atom
,
2104 void BlackboxWindow::setState(unsigned long new_state
) {
2105 current_state
= new_state
;
2107 unsigned long state
[2];
2108 state
[0] = current_state
;
2110 xatom
->setValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
, state
, 2);
2112 xatom
->setValue(client
.window
, XAtom::blackbox_attributes
,
2113 XAtom::blackbox_attributes
, (unsigned long *)&blackbox_attrib
,
2114 PropBlackboxAttributesElements
);
2119 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_modal
);
2121 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_shaded
);
2123 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_hidden
);
2124 if (flags
.skip_taskbar
)
2125 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
);
2126 if (flags
.skip_pager
)
2127 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_pager
);
2128 if (flags
.fullscreen
)
2129 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_fullscreen
);
2130 if (flags
.maximized
== 1 || flags
.maximized
== 2)
2131 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_vert
);
2132 if (flags
.maximized
== 1 || flags
.maximized
== 3)
2133 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_horz
);
2134 xatom
->setValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
2139 bool BlackboxWindow::getState(void) {
2140 bool ret
= xatom
->getValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
,
2142 if (! ret
) current_state
= 0;
2147 void BlackboxWindow::restoreAttributes(void) {
2148 unsigned long num
= PropBlackboxAttributesElements
;
2149 BlackboxAttributes
*net
;
2150 if (! xatom
->getValue(client
.window
, XAtom::blackbox_attributes
,
2151 XAtom::blackbox_attributes
, num
,
2152 (unsigned long **)&net
))
2154 if (num
< PropBlackboxAttributesElements
) {
2159 if (net
->flags
& AttribShaded
&& net
->attrib
& AttribShaded
) {
2160 flags
.shaded
= False
;
2161 unsigned long orig_state
= current_state
;
2165 At this point in the life of a window, current_state should only be set
2166 to IconicState if the window was an *icon*, not if it was shaded.
2168 if (orig_state
!= IconicState
)
2169 current_state
= WithdrawnState
;
2172 if (net
->workspace
!= screen
->getCurrentWorkspaceID() &&
2173 net
->workspace
< screen
->getWorkspaceCount())
2174 screen
->reassociateWindow(this, net
->workspace
, True
);
2176 if ((blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID()) &&
2177 (blackbox_attrib
.workspace
< screen
->getWorkspaceCount())) {
2178 // set to WithdrawnState so it will be mapped on the new workspace
2179 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2180 } else if (current_state
== WithdrawnState
) {
2181 // the window is on this workspace and is Withdrawn, so it is waiting to
2183 current_state
= NormalState
;
2186 if (net
->flags
& AttribOmnipresent
&& net
->attrib
& AttribOmnipresent
) {
2187 flags
.stuck
= False
;
2190 // if the window was on another workspace, it was going to be hidden. this
2191 // specifies that the window should be mapped since it is sticky.
2192 if (current_state
== WithdrawnState
) current_state
= NormalState
;
2195 if (net
->flags
& AttribMaxHoriz
|| net
->flags
& AttribMaxVert
) {
2196 int x
= net
->premax_x
, y
= net
->premax_y
;
2197 unsigned int w
= net
->premax_w
, h
= net
->premax_h
;
2198 flags
.maximized
= 0;
2201 if ((net
->flags
& AttribMaxHoriz
) &&
2202 (net
->flags
& AttribMaxVert
))
2203 m
= (net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
2204 else if (net
->flags
& AttribMaxVert
)
2205 m
= (net
->attrib
& AttribMaxVert
) ? 2 : 0;
2206 else if (net
->flags
& AttribMaxHoriz
)
2207 m
= (net
->attrib
& AttribMaxHoriz
) ? 3 : 0;
2211 blackbox_attrib
.premax_x
= x
;
2212 blackbox_attrib
.premax_y
= y
;
2213 blackbox_attrib
.premax_w
= w
;
2214 blackbox_attrib
.premax_h
= h
;
2217 // with the state set it will then be the map event's job to read the
2218 // window's state and behave accordingly
2225 * Positions the Rect r according the the client window position and
2228 void BlackboxWindow::applyGravity(Rect
&r
) {
2229 // apply horizontal window gravity
2230 switch (client
.win_gravity
) {
2232 case NorthWestGravity
:
2233 case SouthWestGravity
:
2235 r
.setX(client
.rect
.x());
2241 r
.setX(client
.rect
.x() - (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2244 case NorthEastGravity
:
2245 case SouthEastGravity
:
2247 r
.setX(client
.rect
.x() - frame
.margin
.left
- frame
.margin
.right
+ 2);
2252 r
.setX(client
.rect
.x() - frame
.margin
.left
);
2256 // apply vertical window gravity
2257 switch (client
.win_gravity
) {
2259 case NorthWestGravity
:
2260 case NorthEastGravity
:
2262 r
.setY(client
.rect
.y());
2268 r
.setY(client
.rect
.y() - (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2271 case SouthWestGravity
:
2272 case SouthEastGravity
:
2274 r
.setY(client
.rect
.y() - frame
.margin
.top
- frame
.margin
.bottom
+ 2);
2279 r
.setY(client
.rect
.y() - frame
.margin
.top
);
2286 * The reverse of the applyGravity function.
2288 * Positions the Rect r according to the frame window position and
2291 void BlackboxWindow::restoreGravity(Rect
&r
) {
2292 // restore horizontal window gravity
2293 switch (client
.win_gravity
) {
2295 case NorthWestGravity
:
2296 case SouthWestGravity
:
2298 r
.setX(frame
.rect
.x());
2304 r
.setX(frame
.rect
.x() + (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2307 case NorthEastGravity
:
2308 case SouthEastGravity
:
2310 r
.setX(frame
.rect
.x() + frame
.margin
.left
+ frame
.margin
.right
- 2);
2315 r
.setX(frame
.rect
.x() + frame
.margin
.left
);
2319 // restore vertical window gravity
2320 switch (client
.win_gravity
) {
2322 case NorthWestGravity
:
2323 case NorthEastGravity
:
2325 r
.setY(frame
.rect
.y());
2331 r
.setY(frame
.rect
.y() + (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2334 case SouthWestGravity
:
2335 case SouthEastGravity
:
2337 r
.setY(frame
.rect
.y() + frame
.margin
.top
+ frame
.margin
.bottom
- 2);
2342 r
.setY(frame
.rect
.y() + frame
.margin
.top
);
2348 void BlackboxWindow::redrawLabel(void) const {
2349 if (flags
.focused
) {
2351 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2352 frame
.label
, frame
.flabel
);
2354 XSetWindowBackground(blackbox
->getXDisplay(),
2355 frame
.label
, frame
.flabel_pixel
);
2358 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2359 frame
.label
, frame
.ulabel
);
2361 XSetWindowBackground(blackbox
->getXDisplay(),
2362 frame
.label
, frame
.ulabel_pixel
);
2364 XClearWindow(blackbox
->getXDisplay(), frame
.label
);
2366 WindowStyle
*style
= screen
->getWindowStyle();
2368 int pos
= frame
.bevel_w
* 2;
2369 style
->doJustify(client
.title
.c_str(), pos
, frame
.label_w
, frame
.bevel_w
* 4);
2370 style
->font
->drawString(frame
.label
, pos
, 1,
2371 (flags
.focused
? style
->l_text_focus
:
2372 style
->l_text_unfocus
),
2377 void BlackboxWindow::redrawAllButtons(void) const {
2378 if (frame
.iconify_button
) redrawIconifyButton(False
);
2379 if (frame
.maximize_button
) redrawMaximizeButton(flags
.maximized
);
2380 if (frame
.close_button
) redrawCloseButton(False
);
2384 void BlackboxWindow::redrawIconifyButton(bool pressed
) const {
2386 if (flags
.focused
) {
2388 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2389 frame
.iconify_button
, frame
.fbutton
);
2391 XSetWindowBackground(blackbox
->getXDisplay(),
2392 frame
.iconify_button
, frame
.fbutton_pixel
);
2395 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2396 frame
.iconify_button
, frame
.ubutton
);
2398 XSetWindowBackground(blackbox
->getXDisplay(), frame
.iconify_button
,
2399 frame
.ubutton_pixel
);
2403 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2404 frame
.iconify_button
, frame
.pbutton
);
2406 XSetWindowBackground(blackbox
->getXDisplay(),
2407 frame
.iconify_button
, frame
.pbutton_pixel
);
2409 XClearWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
2411 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2412 screen
->getWindowStyle()->b_pic_unfocus
);
2413 XDrawRectangle(blackbox
->getXDisplay(), frame
.iconify_button
, pen
.gc(),
2414 2, (frame
.button_w
- 5), (frame
.button_w
- 5), 2);
2418 void BlackboxWindow::redrawMaximizeButton(bool pressed
) const {
2420 if (flags
.focused
) {
2422 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2423 frame
.maximize_button
, frame
.fbutton
);
2425 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2426 frame
.fbutton_pixel
);
2429 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2430 frame
.maximize_button
, frame
.ubutton
);
2432 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2433 frame
.ubutton_pixel
);
2437 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2438 frame
.maximize_button
, frame
.pbutton
);
2440 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2441 frame
.pbutton_pixel
);
2443 XClearWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
2445 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2446 screen
->getWindowStyle()->b_pic_unfocus
);
2447 XDrawRectangle(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2448 2, 2, (frame
.button_w
- 5), (frame
.button_w
- 5));
2449 XDrawLine(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2450 2, 3, (frame
.button_w
- 3), 3);
2454 void BlackboxWindow::redrawCloseButton(bool pressed
) const {
2456 if (flags
.focused
) {
2458 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2461 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2462 frame
.fbutton_pixel
);
2465 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2468 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2469 frame
.ubutton_pixel
);
2473 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2474 frame
.close_button
, frame
.pbutton
);
2476 XSetWindowBackground(blackbox
->getXDisplay(),
2477 frame
.close_button
, frame
.pbutton_pixel
);
2479 XClearWindow(blackbox
->getXDisplay(), frame
.close_button
);
2481 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2482 screen
->getWindowStyle()->b_pic_unfocus
);
2483 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2484 2, 2, (frame
.button_w
- 3), (frame
.button_w
- 3));
2485 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2486 2, (frame
.button_w
- 3), (frame
.button_w
- 3), 2);
2490 void BlackboxWindow::mapRequestEvent(const XMapRequestEvent
*re
) {
2491 if (re
->window
!= client
.window
)
2495 fprintf(stderr
, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2499 switch (current_state
) {
2504 case WithdrawnState
:
2513 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2515 if (! blackbox
->isStartup()) {
2516 XSync(blackbox
->getXDisplay(), False
); // make sure the frame is mapped
2517 if (screen
->doFocusNew()|| (isTransient() && getTransientFor() &&
2518 getTransientFor()->isFocused())) {
2521 if (screen
->getPlacementPolicy() == BScreen::ClickMousePlacement
) {
2525 XQueryPointer(blackbox
->getXDisplay(), screen
->getRootWindow(),
2526 &r
, &c
, &rx
, &ry
, &x
, &y
, &m
);
2536 void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent
*ue
) {
2537 if (ue
->window
!= client
.window
)
2541 fprintf(stderr
, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2545 screen
->unmanageWindow(this, False
);
2549 void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent
*de
) {
2550 if (de
->window
!= client
.window
)
2554 fprintf(stderr
, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2558 screen
->unmanageWindow(this, False
);
2562 void BlackboxWindow::reparentNotifyEvent(const XReparentEvent
*re
) {
2563 if (re
->window
!= client
.window
|| re
->parent
== frame
.plate
)
2567 fprintf(stderr
, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2568 "0x%lx.\n", client
.window
, re
->parent
);
2573 XPutBackEvent(blackbox
->getXDisplay(), &ev
);
2574 screen
->unmanageWindow(this, True
);
2578 void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent
*pe
) {
2579 if (pe
->state
== PropertyDelete
)
2583 fprintf(stderr
, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n",
2589 case XA_WM_CLIENT_MACHINE
:
2593 case XA_WM_TRANSIENT_FOR
: {
2594 // determine if this is a transient window
2597 // adjust the window decorations based on transience
2598 if (isTransient()) {
2599 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2600 functions
&= ~Func_Maximize
;
2601 setAllowedActions();
2612 case XA_WM_ICON_NAME
:
2614 if (flags
.iconic
) screen
->propagateWindowName(this);
2617 case XAtom::net_wm_name
:
2621 if (decorations
& Decor_Titlebar
)
2624 screen
->propagateWindowName(this);
2627 case XA_WM_NORMAL_HINTS
: {
2630 if ((client
.normal_hint_flags
& PMinSize
) &&
2631 (client
.normal_hint_flags
& PMaxSize
)) {
2632 // the window now can/can't resize itself, so the buttons need to be
2635 if (client
.max_width
<= client
.min_width
&&
2636 client
.max_height
<= client
.min_height
) {
2637 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2638 functions
&= ~(Func_Resize
| Func_Maximize
);
2640 if (! isTransient()) {
2641 decorations
|= Decor_Maximize
| Decor_Handle
;
2642 functions
|= Func_Maximize
;
2644 functions
|= Func_Resize
;
2647 setAllowedActions();
2650 Rect old_rect
= frame
.rect
;
2654 if (old_rect
!= frame
.rect
)
2661 if (pe
->atom
== xatom
->getAtom(XAtom::wm_protocols
)) {
2664 if ((decorations
& Decor_Close
) && (! frame
.close_button
)) {
2665 createCloseButton();
2666 if (decorations
& Decor_Titlebar
) {
2667 positionButtons(True
);
2668 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
2670 if (windowmenu
) windowmenu
->reconfigure();
2672 } else if (pe
->atom
== xatom
->getAtom(XAtom::net_wm_strut
)) {
2681 void BlackboxWindow::exposeEvent(const XExposeEvent
*ee
) {
2683 fprintf(stderr
, "BlackboxWindow::exposeEvent() for 0x%lx\n", client
.window
);
2686 if (frame
.label
== ee
->window
&& (decorations
& Decor_Titlebar
))
2688 else if (frame
.close_button
== ee
->window
)
2689 redrawCloseButton(False
);
2690 else if (frame
.maximize_button
== ee
->window
)
2691 redrawMaximizeButton(flags
.maximized
);
2692 else if (frame
.iconify_button
== ee
->window
)
2693 redrawIconifyButton(False
);
2697 void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent
*cr
) {
2698 if (cr
->window
!= client
.window
|| flags
.iconic
)
2701 if (cr
->value_mask
& CWBorderWidth
)
2702 client
.old_bw
= cr
->border_width
;
2704 if (cr
->value_mask
& (CWX
| CWY
| CWWidth
| CWHeight
)) {
2705 Rect req
= frame
.rect
;
2707 if (cr
->value_mask
& (CWX
| CWY
)) {
2708 if (cr
->value_mask
& CWX
)
2709 client
.rect
.setX(cr
->x
);
2710 if (cr
->value_mask
& CWY
)
2711 client
.rect
.setY(cr
->y
);
2716 if (cr
->value_mask
& CWWidth
)
2717 req
.setWidth(cr
->width
+ frame
.margin
.left
+ frame
.margin
.right
);
2719 if (cr
->value_mask
& CWHeight
)
2720 req
.setHeight(cr
->height
+ frame
.margin
.top
+ frame
.margin
.bottom
);
2722 configure(req
.x(), req
.y(), req
.width(), req
.height());
2725 if (cr
->value_mask
& CWStackMode
&& !isDesktop()) {
2726 switch (cr
->detail
) {
2729 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2735 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2742 void BlackboxWindow::buttonPressEvent(const XButtonEvent
*be
) {
2744 fprintf(stderr
, "BlackboxWindow::buttonPressEvent() for 0x%lx\n",
2748 if (frame
.maximize_button
== be
->window
&& be
->button
<= 3) {
2749 redrawMaximizeButton(True
);
2750 } else if (be
->button
== 1 || (be
->button
== 3 && be
->state
== Mod1Mask
)) {
2751 if (! flags
.focused
)
2754 if (frame
.iconify_button
== be
->window
) {
2755 redrawIconifyButton(True
);
2756 } else if (frame
.close_button
== be
->window
) {
2757 redrawCloseButton(True
);
2758 } else if (frame
.plate
== be
->window
) {
2759 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2761 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2763 XAllowEvents(blackbox
->getXDisplay(), ReplayPointer
, be
->time
);
2765 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
2766 if (((be
->time
- lastButtonPressTime
) <=
2767 blackbox
->getDoubleClickInterval()) ||
2768 (be
->state
== ControlMask
)) {
2769 lastButtonPressTime
= 0;
2772 lastButtonPressTime
= be
->time
;
2776 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2778 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2780 } else if (be
->button
== 2 && (be
->window
!= frame
.iconify_button
) &&
2781 (be
->window
!= frame
.close_button
)) {
2782 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2783 } else if (windowmenu
&& be
->button
== 3 &&
2784 (frame
.title
== be
->window
|| frame
.label
== be
->window
||
2785 frame
.handle
== be
->window
|| frame
.window
== be
->window
)) {
2786 if (windowmenu
->isVisible()) {
2789 int mx
= be
->x_root
- windowmenu
->getWidth() / 2,
2790 my
= be
->y_root
- windowmenu
->getHeight() / 2;
2792 // snap the window menu into a corner/side if necessary
2793 int left_edge
, right_edge
, top_edge
, bottom_edge
;
2796 the " + (frame.border_w * 2) - 1" bits are to get the proper width
2797 and height of the menu, as the sizes returned by it do not include
2800 left_edge
= frame
.rect
.x();
2801 right_edge
= frame
.rect
.right() -
2802 (windowmenu
->getWidth() + (frame
.border_w
* 2) - 1);
2803 top_edge
= client
.rect
.top() - (frame
.border_w
+ frame
.mwm_border_w
);
2804 bottom_edge
= client
.rect
.bottom() -
2805 (windowmenu
->getHeight() + (frame
.border_w
* 2) - 1) +
2806 (frame
.border_w
+ frame
.mwm_border_w
);
2810 if (mx
> right_edge
)
2814 if (my
> bottom_edge
)
2817 windowmenu
->move(mx
, my
);
2819 XRaiseWindow(blackbox
->getXDisplay(), windowmenu
->getWindowID());
2820 XRaiseWindow(blackbox
->getXDisplay(),
2821 windowmenu
->getSendToMenu()->getWindowID());
2824 } else if (be
->button
== 4) {
2825 if ((be
->window
== frame
.label
||
2826 be
->window
== frame
.title
||
2827 be
->window
== frame
.maximize_button
||
2828 be
->window
== frame
.iconify_button
||
2829 be
->window
== frame
.close_button
) &&
2833 } else if (be
->button
== 5) {
2834 if ((be
->window
== frame
.label
||
2835 be
->window
== frame
.title
||
2836 be
->window
== frame
.maximize_button
||
2837 be
->window
== frame
.iconify_button
||
2838 be
->window
== frame
.close_button
) &&
2845 void BlackboxWindow::buttonReleaseEvent(const XButtonEvent
*re
) {
2847 fprintf(stderr
, "BlackboxWindow::buttonReleaseEvent() for 0x%lx\n",
2851 if (re
->window
== frame
.maximize_button
&&
2852 re
->button
>= 1 && re
->button
<= 3) {
2853 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2854 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2855 maximize(re
->button
);
2857 redrawMaximizeButton(flags
.maximized
);
2859 } else if (re
->window
== frame
.iconify_button
&& re
->button
== 1) {
2860 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2861 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2864 redrawIconifyButton(False
);
2866 } else if (re
->window
== frame
.close_button
& re
->button
== 1) {
2867 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2868 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
)))
2870 redrawCloseButton(False
);
2871 } else if (flags
.moving
) {
2873 } else if (flags
.resizing
) {
2875 } else if (re
->window
== frame
.window
) {
2876 if (re
->button
== 2 && re
->state
== Mod1Mask
)
2877 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
2883 void BlackboxWindow::beginMove(int x_root
, int y_root
) {
2884 assert(! (flags
.resizing
|| flags
.moving
));
2887 Only one window can be moved/resized at a time. If another window is already
2888 being moved or resized, then stop it before whating to work with this one.
2890 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
2891 if (changing
&& changing
!= this) {
2892 if (changing
->flags
.moving
)
2893 changing
->endMove();
2894 else // if (changing->flags.resizing)
2895 changing
->endResize();
2898 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
2899 PointerMotionMask
| ButtonReleaseMask
,
2900 GrabModeAsync
, GrabModeAsync
,
2901 None
, blackbox
->getMoveCursor(), CurrentTime
);
2903 if (windowmenu
&& windowmenu
->isVisible())
2906 flags
.moving
= True
;
2907 blackbox
->setChangingWindow(this);
2909 if (! screen
->doOpaqueMove()) {
2910 XGrabServer(blackbox
->getXDisplay());
2912 frame
.changing
= frame
.rect
;
2913 screen
->showPosition(frame
.changing
.x(), frame
.changing
.y());
2915 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2919 frame
.changing
.width() - 1,
2920 frame
.changing
.height() - 1);
2923 frame
.grab_x
= x_root
- frame
.rect
.x() - frame
.border_w
;
2924 frame
.grab_y
= y_root
- frame
.rect
.y() - frame
.border_w
;
2928 void BlackboxWindow::doMove(int x_root
, int y_root
) {
2929 assert(flags
.moving
);
2930 assert(blackbox
->getChangingWindow() == this);
2932 int dx
= x_root
- frame
.grab_x
, dy
= y_root
- frame
.grab_y
;
2933 dx
-= frame
.border_w
;
2934 dy
-= frame
.border_w
;
2936 const int snap_distance
= screen
->getEdgeSnapThreshold();
2938 if (snap_distance
) {
2940 const int wleft
= dx
,
2941 wright
= dx
+ frame
.rect
.width() - 1,
2943 wbottom
= dy
+ frame
.rect
.height() - 1;
2945 if (screen
->getWindowToWindowSnap()) {
2946 Workspace
*w
= screen
->getWorkspace(getWorkspaceNumber());
2949 // try snap to another window
2950 for (unsigned int i
= 0, c
= w
->getCount(); i
< c
; ++i
) {
2951 BlackboxWindow
*snapwin
= w
->getWindow(i
);
2952 if (snapwin
== this)
2953 continue; // don't snap to self
2955 bool snapped
= False
;
2957 const Rect
&winrect
= snapwin
->frameRect();
2958 int dleft
= std::abs(wright
- winrect
.left()),
2959 dright
= std::abs(wleft
- winrect
.right()),
2960 dtop
= std::abs(wbottom
- winrect
.top()),
2961 dbottom
= std::abs(wtop
- winrect
.bottom());
2963 if (wtop
>= (signed)(winrect
.y() - frame
.rect
.height() + 1) &&
2964 wtop
< (signed)(winrect
.y() + winrect
.height() - 1)) {
2966 // snap left of other window?
2967 if (dleft
< snap_distance
&& dleft
<= dright
) {
2968 dx
= winrect
.left() - frame
.rect
.width();
2971 // snap right of other window?
2972 else if (dright
< snap_distance
) {
2973 dx
= winrect
.right() + 1;
2978 if (screen
->getWindowCornerSnap()) {
2979 // try corner-snap to its other sides
2980 dtop
= std::abs(wtop
- winrect
.top());
2981 dbottom
= std::abs(wbottom
- winrect
.bottom());
2982 if (dtop
< snap_distance
&& dtop
<= dbottom
)
2984 else if (dbottom
< snap_distance
)
2985 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
2992 if (wleft
>= (signed)(winrect
.x() - frame
.rect
.width() + 1) &&
2993 wleft
< (signed)(winrect
.x() + winrect
.width() - 1)) {
2995 // snap top of other window?
2996 if (dtop
< snap_distance
&& dtop
<= dbottom
) {
2997 dy
= winrect
.top() - frame
.rect
.height();
3000 // snap bottom of other window?
3001 else if (dbottom
< snap_distance
) {
3002 dy
= winrect
.bottom() + 1;
3007 if (screen
->getWindowCornerSnap()) {
3008 // try corner-snap to its other sides
3009 dleft
= std::abs(wleft
- winrect
.left());
3010 dright
= std::abs(wright
- winrect
.right());
3011 if (dleft
< snap_distance
&& dleft
<= dright
)
3012 dx
= winrect
.left();
3013 else if (dright
< snap_distance
)
3014 dx
= winrect
.right() - frame
.rect
.width() + 1;
3023 // try snap to the screen's available area
3024 Rect srect
= screen
->availableArea();
3026 int dleft
= std::abs(wleft
- srect
.left()),
3027 dright
= std::abs(wright
- srect
.right()),
3028 dtop
= std::abs(wtop
- srect
.top()),
3029 dbottom
= std::abs(wbottom
- srect
.bottom());
3032 if (dleft
< snap_distance
&& dleft
<= dright
)
3035 else if (dright
< snap_distance
)
3036 dx
= srect
.right() - frame
.rect
.width() + 1;
3039 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3042 else if (dbottom
< snap_distance
)
3043 dy
= srect
.bottom() - frame
.rect
.height() + 1;
3045 srect
= screen
->getRect(); // now get the full screen
3047 dleft
= std::abs(wleft
- srect
.left()),
3048 dright
= std::abs(wright
- srect
.right()),
3049 dtop
= std::abs(wtop
- srect
.top()),
3050 dbottom
= std::abs(wbottom
- srect
.bottom());
3053 if (dleft
< snap_distance
&& dleft
<= dright
)
3056 else if (dright
< snap_distance
)
3057 dx
= srect
.right() - frame
.rect
.width() + 1;
3060 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3063 else if (dbottom
< snap_distance
)
3064 dy
= srect
.bottom() - frame
.rect
.height() + 1;
3067 if (screen
->doOpaqueMove()) {
3068 configure(dx
, dy
, frame
.rect
.width(), frame
.rect
.height());
3070 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3074 frame
.changing
.width() - 1,
3075 frame
.changing
.height() - 1);
3077 frame
.changing
.setPos(dx
, dy
);
3079 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3083 frame
.changing
.width() - 1,
3084 frame
.changing
.height() - 1);
3087 screen
->showPosition(dx
, dy
);
3091 void BlackboxWindow::endMove(void) {
3092 assert(flags
.moving
);
3093 assert(blackbox
->getChangingWindow() == this);
3095 flags
.moving
= False
;
3096 blackbox
->setChangingWindow(0);
3098 if (! screen
->doOpaqueMove()) {
3099 /* when drawing the rubber band, we need to make sure we only draw inside
3100 * the frame... frame.changing_* contain the new coords for the window,
3101 * so we need to subtract 1 from changing_w/changing_h every where we
3102 * draw the rubber band (for both moving and resizing)
3104 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3105 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3106 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3107 XUngrabServer(blackbox
->getXDisplay());
3109 configure(frame
.changing
.x(), frame
.changing
.y(),
3110 frame
.changing
.width(), frame
.changing
.height());
3112 configure(frame
.rect
.x(), frame
.rect
.y(),
3113 frame
.rect
.width(), frame
.rect
.height());
3115 screen
->hideGeometry();
3117 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3119 // if there are any left over motions from the move, drop them now
3120 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3122 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3127 void BlackboxWindow::beginResize(int x_root
, int y_root
, Corner dir
) {
3128 assert(! (flags
.resizing
|| flags
.moving
));
3131 Only one window can be moved/resized at a time. If another window is already
3132 being moved or resized, then stop it before whating to work with this one.
3134 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3135 if (changing
&& changing
!= this) {
3136 if (changing
->flags
.moving
)
3137 changing
->endMove();
3138 else // if (changing->flags.resizing)
3139 changing
->endResize();
3147 switch (resize_dir
) {
3150 cursor
= blackbox
->getLowerLeftAngleCursor();
3155 cursor
= blackbox
->getLowerRightAngleCursor();
3159 anchor
= BottomRight
;
3160 cursor
= blackbox
->getUpperLeftAngleCursor();
3164 anchor
= BottomLeft
;
3165 cursor
= blackbox
->getUpperRightAngleCursor();
3169 assert(false); // unhandled Corner
3170 return; // unreachable, for the compiler
3173 XGrabServer(blackbox
->getXDisplay());
3174 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3175 PointerMotionMask
| ButtonReleaseMask
,
3176 GrabModeAsync
, GrabModeAsync
, None
, cursor
, CurrentTime
);
3178 flags
.resizing
= True
;
3179 blackbox
->setChangingWindow(this);
3182 frame
.changing
= frame
.rect
;
3184 constrain(anchor
, &gw
, &gh
);
3186 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3187 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3188 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3190 screen
->showGeometry(gw
, gh
);
3192 frame
.grab_x
= x_root
;
3193 frame
.grab_y
= y_root
;
3197 void BlackboxWindow::doResize(int x_root
, int y_root
) {
3198 assert(flags
.resizing
);
3199 assert(blackbox
->getChangingWindow() == this);
3201 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3202 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3203 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3208 switch (resize_dir
) {
3211 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3212 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3216 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3217 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3220 anchor
= BottomRight
;
3221 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3222 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3225 anchor
= BottomLeft
;
3226 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3227 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3231 assert(false); // unhandled Corner
3232 return; // unreachable, for the compiler
3235 constrain(anchor
, &gw
, &gh
);
3237 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3238 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3239 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3241 screen
->showGeometry(gw
, gh
);
3245 void BlackboxWindow::endResize(void) {
3246 assert(flags
.resizing
);
3247 assert(blackbox
->getChangingWindow() == this);
3249 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3250 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3251 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3252 XUngrabServer(blackbox
->getXDisplay());
3254 // unset maximized state after resized when fully maximized
3255 if (flags
.maximized
== 1)
3258 flags
.resizing
= False
;
3259 blackbox
->setChangingWindow(0);
3261 configure(frame
.changing
.x(), frame
.changing
.y(),
3262 frame
.changing
.width(), frame
.changing
.height());
3263 screen
->hideGeometry();
3265 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3267 // if there are any left over motions from the resize, drop them now
3268 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3270 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3275 void BlackboxWindow::motionNotifyEvent(const XMotionEvent
*me
) {
3277 fprintf(stderr
, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n",
3282 doMove(me
->x_root
, me
->y_root
);
3283 } else if (flags
.resizing
) {
3284 doResize(me
->x_root
, me
->y_root
);
3286 if (!flags
.resizing
&& me
->state
& Button1Mask
&& (functions
& Func_Move
) &&
3287 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3288 frame
.handle
== me
->window
|| frame
.window
== me
->window
)) {
3289 beginMove(me
->x_root
, me
->y_root
);
3290 } else if ((functions
& Func_Resize
) &&
3291 (me
->state
& Button1Mask
&& (me
->window
== frame
.right_grip
||
3292 me
->window
== frame
.left_grip
)) ||
3293 (me
->state
& Button3Mask
&& me
->state
& Mod1Mask
&&
3294 me
->window
== frame
.window
)) {
3295 unsigned int zones
= screen
->getResizeZones();
3298 if (me
->window
== frame
.left_grip
) {
3299 corner
= BottomLeft
;
3300 } else if (me
->window
== frame
.right_grip
|| zones
== 1) {
3301 corner
= BottomRight
;
3304 bool left
= (me
->x_root
- frame
.rect
.x() <=
3305 static_cast<signed>(frame
.rect
.width() / 2));
3308 else // (zones == 4)
3309 top
= (me
->y_root
- frame
.rect
.y() <=
3310 static_cast<signed>(frame
.rect
.height() / 2));
3311 corner
= (top
? (left
? TopLeft
: TopRight
) :
3312 (left
? BottomLeft
: BottomRight
));
3315 beginResize(me
->x_root
, me
->y_root
, corner
);
3322 void BlackboxWindow::shapeEvent(XShapeEvent
*) {
3323 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
3330 bool BlackboxWindow::validateClient(void) const {
3331 XSync(blackbox
->getXDisplay(), False
);
3334 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3335 DestroyNotify
, &e
) ||
3336 XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3338 XPutBackEvent(blackbox
->getXDisplay(), &e
);
3347 void BlackboxWindow::restore(bool remap
) {
3348 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeDelete
);
3349 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
3350 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, NoEventMask
);
3352 // do not leave a shaded window as an icon unless it was an icon
3353 if (flags
.shaded
&& ! flags
.iconic
) setState(NormalState
);
3355 restoreGravity(client
.rect
);
3357 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
3358 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
3360 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, client
.old_bw
);
3363 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3364 ReparentNotify
, &ev
)) {
3367 // according to the ICCCM - if the client doesn't reparent to
3368 // root, then we have to do it for them
3369 XReparentWindow(blackbox
->getXDisplay(), client
.window
,
3370 screen
->getRootWindow(),
3371 client
.rect
.x(), client
.rect
.y());
3374 if (remap
) XMapWindow(blackbox
->getXDisplay(), client
.window
);
3378 // timer for autoraise
3379 void BlackboxWindow::timeout(void) {
3380 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3384 void BlackboxWindow::changeBlackboxHints(BlackboxHints
*net
) {
3385 if ((net
->flags
& AttribShaded
) &&
3386 ((blackbox_attrib
.attrib
& AttribShaded
) !=
3387 (net
->attrib
& AttribShaded
)))
3390 if (flags
.visible
&& // watch out for requests when we can not be seen
3391 (net
->flags
& (AttribMaxVert
| AttribMaxHoriz
)) &&
3392 ((blackbox_attrib
.attrib
& (AttribMaxVert
| AttribMaxHoriz
)) !=
3393 (net
->attrib
& (AttribMaxVert
| AttribMaxHoriz
)))) {
3394 if (flags
.maximized
) {
3399 if ((net
->flags
& AttribMaxHoriz
) && (net
->flags
& AttribMaxVert
))
3400 button
= ((net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0);
3401 else if (net
->flags
& AttribMaxVert
)
3402 button
= ((net
->attrib
& AttribMaxVert
) ? 2 : 0);
3403 else if (net
->flags
& AttribMaxHoriz
)
3404 button
= ((net
->attrib
& AttribMaxHoriz
) ? 3 : 0);
3410 if ((net
->flags
& AttribOmnipresent
) &&
3411 ((blackbox_attrib
.attrib
& AttribOmnipresent
) !=
3412 (net
->attrib
& AttribOmnipresent
)))
3415 if ((net
->flags
& AttribWorkspace
) &&
3416 (blackbox_attrib
.workspace
!= net
->workspace
)) {
3417 screen
->reassociateWindow(this, net
->workspace
, True
);
3419 if (screen
->getCurrentWorkspaceID() != net
->workspace
) {
3423 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3427 if (net
->flags
& AttribDecoration
) {
3428 switch (net
->decoration
) {
3430 // clear all decorations except close
3431 decorations
&= Decor_Close
;
3437 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Iconify
;
3439 decorations
= ((functions
& Func_Resize
) && !isTransient() ?
3440 decorations
| Decor_Handle
:
3441 decorations
&= ~Decor_Handle
);
3442 decorations
= (functions
& Func_Maximize
?
3443 decorations
| Decor_Maximize
:
3444 decorations
&= ~Decor_Maximize
);
3449 decorations
|= Decor_Titlebar
| Decor_Iconify
;
3450 decorations
&= ~(Decor_Border
| Decor_Handle
);
3452 decorations
= (functions
& Func_Maximize
?
3453 decorations
| Decor_Maximize
:
3454 decorations
&= ~Decor_Maximize
);
3459 decorations
|= Decor_Titlebar
;
3460 decorations
&= ~(Decor_Iconify
| Decor_Border
);
3462 decorations
= ((functions
& Func_Resize
) && !isTransient() ?
3463 decorations
| Decor_Handle
:
3464 decorations
&= ~Decor_Handle
);
3465 decorations
= (functions
& Func_Maximize
?
3466 decorations
| Decor_Maximize
:
3467 decorations
&= ~Decor_Maximize
);
3472 // we can not be shaded if we lack a titlebar
3473 if (flags
.shaded
&& ! (decorations
& Decor_Titlebar
))
3476 if (flags
.visible
&& frame
.window
) {
3477 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
3478 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
3482 setState(current_state
);
3488 * Set the sizes of all components of the window frame
3489 * (the window decorations).
3490 * These values are based upon the current style settings and the client
3491 * window's dimensions.
3493 void BlackboxWindow::upsize(void) {
3494 frame
.bevel_w
= screen
->getBevelWidth();
3496 if (decorations
& Decor_Border
) {
3497 frame
.border_w
= screen
->getBorderWidth();
3498 if (! isTransient())
3499 frame
.mwm_border_w
= screen
->getFrameWidth();
3501 frame
.mwm_border_w
= 0;
3503 frame
.mwm_border_w
= frame
.border_w
= 0;
3506 if (decorations
& Decor_Titlebar
) {
3507 // the height of the titlebar is based upon the height of the font being
3508 // used to display the window's title
3509 WindowStyle
*style
= screen
->getWindowStyle();
3510 frame
.title_h
= style
->font
->height() + (frame
.bevel_w
* 2) + 2;
3512 frame
.label_h
= frame
.title_h
- (frame
.bevel_w
* 2);
3513 frame
.button_w
= (frame
.label_h
- 2);
3515 // set the top frame margin
3516 frame
.margin
.top
= frame
.border_w
+ frame
.title_h
+
3517 frame
.border_w
+ frame
.mwm_border_w
;
3523 // set the top frame margin
3524 frame
.margin
.top
= frame
.border_w
+ frame
.mwm_border_w
;
3527 // set the left/right frame margin
3528 frame
.margin
.left
= frame
.margin
.right
= frame
.border_w
+ frame
.mwm_border_w
;
3530 if (decorations
& Decor_Handle
) {
3531 frame
.grip_w
= frame
.button_w
* 2;
3532 frame
.handle_h
= screen
->getHandleWidth();
3534 // set the bottom frame margin
3535 frame
.margin
.bottom
= frame
.border_w
+ frame
.handle_h
+
3536 frame
.border_w
+ frame
.mwm_border_w
;
3541 // set the bottom frame margin
3542 frame
.margin
.bottom
= frame
.border_w
+ frame
.mwm_border_w
;
3546 We first get the normal dimensions and use this to define the inside_w/h
3547 then we modify the height if shading is in effect.
3548 If the shade state is not considered then frame.rect gets reset to the
3549 normal window size on a reconfigure() call resulting in improper
3550 dimensions appearing in move/resize and other events.
3553 height
= client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
,
3554 width
= client
.rect
.width() + frame
.margin
.left
+ frame
.margin
.right
;
3556 frame
.inside_w
= width
- (frame
.border_w
* 2);
3557 frame
.inside_h
= height
- (frame
.border_w
* 2);
3560 height
= frame
.title_h
+ (frame
.border_w
* 2);
3561 frame
.rect
.setSize(width
, height
);
3566 * Calculate the size of the client window and constrain it to the
3567 * size specified by the size hints of the client window.
3569 * The logical width and height are placed into pw and ph, if they
3570 * are non-zero. Logical size refers to the users perception of
3571 * the window size (for example an xterm resizes in cells, not in pixels).
3573 * The physical geometry is placed into frame.changing_{x,y,width,height}.
3574 * Physical geometry refers to the geometry of the window in pixels.
3576 void BlackboxWindow::constrain(Corner anchor
, int *pw
, int *ph
) {
3577 // frame.changing represents the requested frame size, we need to
3578 // strip the frame margin off and constrain the client size
3579 frame
.changing
.setCoords(frame
.changing
.left() + frame
.margin
.left
,
3580 frame
.changing
.top() + frame
.margin
.top
,
3581 frame
.changing
.right() - frame
.margin
.right
,
3582 frame
.changing
.bottom() - frame
.margin
.bottom
);
3584 int dw
= frame
.changing
.width(), dh
= frame
.changing
.height(),
3585 base_width
= (client
.base_width
) ? client
.base_width
: client
.min_width
,
3586 base_height
= (client
.base_height
) ? client
.base_height
:
3590 if (dw
< static_cast<signed>(client
.min_width
)) dw
= client
.min_width
;
3591 if (dh
< static_cast<signed>(client
.min_height
)) dh
= client
.min_height
;
3592 if (dw
> static_cast<signed>(client
.max_width
)) dw
= client
.max_width
;
3593 if (dh
> static_cast<signed>(client
.max_height
)) dh
= client
.max_height
;
3596 dw
/= client
.width_inc
;
3598 dh
/= client
.height_inc
;
3601 if (client
.width_inc
== 1)
3602 *pw
= dw
+ base_width
;
3607 if (client
.height_inc
== 1)
3608 *ph
= dh
+ base_height
;
3613 dw
*= client
.width_inc
;
3615 dh
*= client
.height_inc
;
3618 frame
.changing
.setSize(dw
, dh
);
3620 // add the frame margin back onto frame.changing
3621 frame
.changing
.setCoords(frame
.changing
.left() - frame
.margin
.left
,
3622 frame
.changing
.top() - frame
.margin
.top
,
3623 frame
.changing
.right() + frame
.margin
.right
,
3624 frame
.changing
.bottom() + frame
.margin
.bottom
);
3626 // move frame.changing to the specified anchor
3634 dx
= frame
.rect
.right() - frame
.changing
.right();
3638 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3642 dx
= frame
.rect
.right() - frame
.changing
.right();
3643 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3647 assert(false); // unhandled corner
3649 frame
.changing
.setPos(frame
.changing
.x() + dx
, frame
.changing
.y() + dy
);
3653 void WindowStyle::doJustify(const std::string
&text
, int &start_pos
,
3654 unsigned int max_length
,
3655 unsigned int modifier
) const {
3656 size_t text_len
= text
.size();
3657 unsigned int length
;
3660 length
= font
->measureString(string(text
, 0, text_len
)) + modifier
;
3661 } while (length
> max_length
&& text_len
-- > 0);
3665 start_pos
+= max_length
- length
;
3669 start_pos
+= (max_length
- length
) / 2;
3679 BWindowGroup::BWindowGroup(Blackbox
*b
, Window _group
)
3680 : blackbox(b
), group(_group
) {
3681 XWindowAttributes wattrib
;
3682 if (! XGetWindowAttributes(blackbox
->getXDisplay(), group
, &wattrib
)) {
3683 // group window doesn't seem to exist anymore
3688 XSelectInput(blackbox
->getXDisplay(), group
,
3689 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
3691 blackbox
->saveGroupSearch(group
, this);
3695 BWindowGroup::~BWindowGroup(void) {
3696 blackbox
->removeGroupSearch(group
);
3701 BWindowGroup::find(BScreen
*screen
, bool allow_transients
) const {
3702 BlackboxWindow
*ret
= blackbox
->getFocusedWindow();
3704 // does the focus window match (or any transient_fors)?
3706 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3707 if (ret
->isTransient() && allow_transients
) break;
3708 else if (! ret
->isTransient()) break;
3711 ret
= ret
->getTransientFor();
3714 if (ret
) return ret
;
3716 // the focus window didn't match, look in the group's window list
3717 BlackboxWindowList::const_iterator it
, end
= windowList
.end();
3718 for (it
= windowList
.begin(); it
!= end
; ++it
) {
3720 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3721 if (ret
->isTransient() && allow_transients
) break;
3722 else if (! ret
->isTransient()) break;