1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2 // Window.cc for Blackbox - an X11 Window manager
3 // Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry <shaleh at debian.org>
4 // Copyright (c) 1997 - 2000, 2002 Brad Hughes <bhughes at trolltech.com>
6 // Permission is hereby granted, free of charge, to any person obtaining a
7 // copy of this software and associated documentation files (the "Software"),
8 // to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 // and/or sell copies of the Software, and to permit persons to whom the
11 // Software is furnished to do so, subject to the following conditions:
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 // DEALINGS IN THE SOFTWARE.
25 # include "../config.h"
26 #endif // HAVE_CONFIG_H
29 #include <X11/Xatom.h>
30 #include <X11/keysym.h>
34 #endif // HAVE_STRING_H
39 # endif // HAVE_STDIO_H
46 #include "blackbox.hh"
49 #include "Iconmenu.hh"
55 #include "Windowmenu.hh"
56 #include "Workspace.hh"
62 * Initializes the class with default values/the window's set initial values.
64 BlackboxWindow::BlackboxWindow(Blackbox
*b
, Window w
, BScreen
*s
) {
65 // fprintf(stderr, "BlackboxWindow size: %d bytes\n",
66 // sizeof(BlackboxWindow));
69 fprintf(stderr
, "BlackboxWindow::BlackboxWindow(): creating 0x%lx\n", w
);
73 set timer to zero... it is initialized properly later, so we check
74 if timer is zero in the destructor, and assume that the window is not
75 fully constructed if timer is zero...
81 xatom
= blackbox
->getXAtom();
83 if (! validateClient()) {
88 // set the eventmask early in the game so that we make sure we get
89 // all the events we are interested in
90 XSetWindowAttributes attrib_set
;
91 attrib_set
.event_mask
= PropertyChangeMask
| FocusChangeMask
|
93 attrib_set
.do_not_propagate_mask
= ButtonPressMask
| ButtonReleaseMask
|
95 XChangeWindowAttributes(blackbox
->getXDisplay(), client
.window
,
96 CWEventMask
|CWDontPropagate
, &attrib_set
);
98 // fetch client size and placement
99 XWindowAttributes wattrib
;
100 if ((! XGetWindowAttributes(blackbox
->getXDisplay(),
101 client
.window
, &wattrib
)) ||
102 (! wattrib
.screen
) || wattrib
.override_redirect
) {
105 "BlackboxWindow::BlackboxWindow(): XGetWindowAttributes failed\n");
112 flags
.moving
= flags
.resizing
= flags
.shaded
= flags
.visible
=
113 flags
.iconic
= flags
.focused
= flags
.stuck
= flags
.modal
=
114 flags
.send_focus_message
= flags
.shaped
= flags
.skip_taskbar
=
115 flags
.skip_pager
= flags
.fullscreen
= False
;
118 blackbox_attrib
.workspace
= window_number
= BSENTINEL
;
120 blackbox_attrib
.flags
= blackbox_attrib
.attrib
= blackbox_attrib
.stack
121 = blackbox_attrib
.decoration
= 0l;
122 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
123 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
126 frame
.window
= frame
.plate
= frame
.title
= frame
.handle
= None
;
127 frame
.close_button
= frame
.iconify_button
= frame
.maximize_button
= None
;
128 frame
.right_grip
= frame
.left_grip
= None
;
130 frame
.ulabel_pixel
= frame
.flabel_pixel
= frame
.utitle_pixel
=
131 frame
.ftitle_pixel
= frame
.uhandle_pixel
= frame
.fhandle_pixel
=
132 frame
.ubutton_pixel
= frame
.fbutton_pixel
= frame
.pbutton_pixel
=
133 frame
.uborder_pixel
= frame
.fborder_pixel
= frame
.ugrip_pixel
=
134 frame
.fgrip_pixel
= 0;
135 frame
.utitle
= frame
.ftitle
= frame
.uhandle
= frame
.fhandle
= None
;
136 frame
.ulabel
= frame
.flabel
= frame
.ubutton
= frame
.fbutton
= None
;
137 frame
.pbutton
= frame
.ugrip
= frame
.fgrip
= None
;
139 decorations
= Decor_Titlebar
| Decor_Border
| Decor_Handle
|
140 Decor_Iconify
| Decor_Maximize
;
141 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
143 client
.wm_hint_flags
= client
.normal_hint_flags
= 0;
144 client
.window_group
= None
;
145 client
.transient_for
= 0;
148 get the initial size and location of client window (relative to the
149 _root window_). This position is the reference point used with the
150 window's gravity to find the window's initial position.
152 client
.rect
.setRect(wattrib
.x
, wattrib
.y
, wattrib
.width
, wattrib
.height
);
153 client
.old_bw
= wattrib
.border_width
;
156 lastButtonPressTime
= 0;
158 timer
= new BTimer(blackbox
, this);
159 timer
->setTimeout(blackbox
->getAutoRaiseDelay());
161 if (! getBlackboxHints()) {
166 // get size, aspect, minimum/maximum size and other hints set by the
172 if (client
.initial_state
== WithdrawnState
) {
173 screen
->getSlit()->addClient(client
.window
);
178 if (isKDESystrayWindow()) {
179 screen
->addSystrayWindow(client
.window
);
184 frame
.window
= createToplevelWindow();
185 frame
.plate
= createChildWindow(frame
.window
);
186 associateClientWindow();
188 blackbox
->saveWindowSearch(frame
.window
, this);
189 blackbox
->saveWindowSearch(frame
.plate
, this);
190 blackbox
->saveWindowSearch(client
.window
, this);
192 // determine if this is a transient window
195 // determine the window's type, so we can decide its decorations and
196 // functionality, or if we should not manage it at all
199 // adjust the window decorations/behavior based on the window type
200 switch (window_type
) {
202 // desktop windows are not managed by us, we just make sure they stay on the
208 // docks (such as kicker) and menus (as used by kde for the 'desktop menu'
209 // which mimics apple, cannot be moved, and appear on all workspaces
210 // also, these have no decorations
211 functions
&= ~(Func_Move
);
212 decorations
&= ~Decor_Titlebar
;
216 // these windows have minimal decorations, only a titlebar, and cannot
217 // be resized or iconified
218 decorations
&= ~(Decor_Maximize
| Decor_Handle
| Decor_Border
|
220 functions
&= ~(Func_Resize
| Func_Maximize
| Func_Iconify
);
224 // splash screens have no functionality or decorations, they are left up
225 // to the application which created them
231 // dialogs cannot be maximized, and don't display a handle
232 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
233 functions
&= ~Func_Maximize
;
237 // normal windows retain all of the possible decorations and functionality
241 // further adjeust the window's decorations/behavior based on window sizes
242 if ((client
.normal_hint_flags
& PMinSize
) &&
243 (client
.normal_hint_flags
& PMaxSize
) &&
244 client
.max_width
<= client
.min_width
&&
245 client
.max_height
<= client
.min_height
) {
246 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
247 functions
&= ~(Func_Resize
| Func_Maximize
);
253 bool place_window
= True
;
254 if (blackbox
->isStartup() || isTransient() ||
255 client
.normal_hint_flags
& (PPosition
|USPosition
)) {
256 applyGravity(frame
.rect
);
258 if (blackbox
->isStartup() || client
.rect
.intersects(screen
->getRect()))
259 place_window
= False
;
262 // add the window's strut. note this is done *after* placing the window.
263 screen
->addStrut(&client
.strut
);
266 if (decorations
& Decor_Titlebar
)
269 if (decorations
& Decor_Handle
)
273 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
278 windowmenu
= new Windowmenu(this);
280 if (blackbox_attrib
.workspace
>= screen
->getWorkspaceCount())
281 screen
->getCurrentWorkspace()->addWindow(this, place_window
);
283 screen
->getWorkspace(blackbox_attrib
.workspace
)->
284 addWindow(this, place_window
);
286 if (! place_window
) {
287 // don't need to call configure if we are letting the workspace
289 configure(frame
.rect
.x(), frame
.rect
.y(),
290 frame
.rect
.width(), frame
.rect
.height());
293 // preserve the window's initial state on first map, and its current state
296 if (client
.wm_hint_flags
& StateHint
)
297 current_state
= client
.initial_state
;
299 current_state
= NormalState
;
302 // get sticky state from our parent window if we've got one
303 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
304 client
.transient_for
->isStuck() != flags
.stuck
)
308 flags
.shaded
= False
;
309 unsigned long orig_state
= current_state
;
313 At this point in the life of a window, current_state should only be set
314 to IconicState if the window was an *icon*, not if it was shaded.
316 if (orig_state
!= IconicState
)
317 current_state
= NormalState
;
325 if (flags
.maximized
&& (functions
& Func_Maximize
)) {
330 When the window is mapped (and also when its attributes are restored), the
331 current_state that was set here will be used.
332 It is set to Normal if the window is to be mapped or it is set to Iconic
333 if the window is to be iconified.
334 *Note* that for sticky windows, the same rules apply here, they are in
335 fact never set to Iconic since there is no way for us to tell if a sticky
336 window was iconified previously.
343 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
349 BlackboxWindow::~BlackboxWindow(void) {
351 fprintf(stderr
, "BlackboxWindow::~BlackboxWindow: destroying 0x%lx\n",
355 if (! timer
) // window not managed...
358 screen
->removeStrut(&client
.strut
);
359 screen
->updateAvailableArea();
361 // We don't need to worry about resizing because resizing always grabs the X
362 // server. This should only ever happen if using opaque moving.
370 if (client
.window_group
) {
371 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
372 if (group
) group
->removeWindow(this);
375 // remove ourselves from our transient_for
377 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
378 client
.transient_for
->client
.transientList
.remove(this);
380 client
.transient_for
= (BlackboxWindow
*) 0;
383 if (client
.transientList
.size() > 0) {
384 // reset transient_for for all transients
385 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
386 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
387 (*it
)->client
.transient_for
= (BlackboxWindow
*) 0;
398 blackbox
->removeWindowSearch(frame
.plate
);
399 XDestroyWindow(blackbox
->getXDisplay(), frame
.plate
);
403 blackbox
->removeWindowSearch(frame
.window
);
404 XDestroyWindow(blackbox
->getXDisplay(), frame
.window
);
407 blackbox
->removeWindowSearch(client
.window
);
412 * Creates a new top level window, with a given location, size, and border
414 * Returns: the newly created window
416 Window
BlackboxWindow::createToplevelWindow(void) {
417 XSetWindowAttributes attrib_create
;
418 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
| CWColormap
|
419 CWOverrideRedirect
| CWEventMask
;
421 attrib_create
.background_pixmap
= None
;
422 attrib_create
.colormap
= screen
->getColormap();
423 attrib_create
.override_redirect
= True
;
424 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
425 ButtonMotionMask
| EnterWindowMask
;
427 return XCreateWindow(blackbox
->getXDisplay(), screen
->getRootWindow(),
428 0, 0, 1, 1, frame
.border_w
, screen
->getDepth(),
429 InputOutput
, screen
->getVisual(), create_mask
,
435 * Creates a child window, and optionally associates a given cursor with
438 Window
BlackboxWindow::createChildWindow(Window parent
, Cursor cursor
) {
439 XSetWindowAttributes attrib_create
;
440 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
|
443 attrib_create
.background_pixmap
= None
;
444 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
445 ButtonMotionMask
| ExposureMask
;
448 create_mask
|= CWCursor
;
449 attrib_create
.cursor
= cursor
;
452 return XCreateWindow(blackbox
->getXDisplay(), parent
, 0, 0, 1, 1, 0,
453 screen
->getDepth(), InputOutput
, screen
->getVisual(),
454 create_mask
, &attrib_create
);
458 void BlackboxWindow::associateClientWindow(void) {
459 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, 0);
463 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeInsert
);
465 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, SubstructureRedirectMask
);
467 XGrabServer(blackbox
->getXDisplay());
469 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
471 XSelectInput(blackbox
->getXDisplay(), client
.window
,
472 event_mask
& ~StructureNotifyMask
);
473 XReparentWindow(blackbox
->getXDisplay(), client
.window
, frame
.plate
, 0, 0);
474 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
476 XUngrabServer(blackbox
->getXDisplay());
478 XRaiseWindow(blackbox
->getXDisplay(), frame
.plate
);
479 XMapSubwindows(blackbox
->getXDisplay(), frame
.plate
);
483 if (blackbox
->hasShapeExtensions()) {
484 XShapeSelectInput(blackbox
->getXDisplay(), client
.window
,
491 XShapeQueryExtents(blackbox
->getXDisplay(), client
.window
, &shaped
,
492 &foo
, &foo
, &ufoo
, &ufoo
, &foo
, &foo
, &foo
,
494 flags
.shaped
= shaped
;
500 void BlackboxWindow::decorate(void) {
503 texture
= &(screen
->getWindowStyle()->b_focus
);
504 frame
.fbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
507 frame
.fbutton_pixel
= texture
->color().pixel();
509 texture
= &(screen
->getWindowStyle()->b_unfocus
);
510 frame
.ubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
513 frame
.ubutton_pixel
= texture
->color().pixel();
515 texture
= &(screen
->getWindowStyle()->b_pressed
);
516 frame
.pbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
519 frame
.pbutton_pixel
= texture
->color().pixel();
521 if (decorations
& Decor_Titlebar
) {
522 texture
= &(screen
->getWindowStyle()->t_focus
);
523 frame
.ftitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
526 frame
.ftitle_pixel
= texture
->color().pixel();
528 texture
= &(screen
->getWindowStyle()->t_unfocus
);
529 frame
.utitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
532 frame
.utitle_pixel
= texture
->color().pixel();
534 XSetWindowBorder(blackbox
->getXDisplay(), frame
.title
,
535 screen
->getBorderColor()->pixel());
540 if (decorations
& Decor_Border
) {
541 frame
.fborder_pixel
= screen
->getWindowStyle()->f_focus
.pixel();
542 frame
.uborder_pixel
= screen
->getWindowStyle()->f_unfocus
.pixel();
543 blackbox_attrib
.flags
|= AttribDecoration
;
544 blackbox_attrib
.decoration
= DecorNormal
;
546 blackbox_attrib
.flags
|= AttribDecoration
;
547 blackbox_attrib
.decoration
= DecorNone
;
550 if (decorations
& Decor_Handle
) {
551 texture
= &(screen
->getWindowStyle()->h_focus
);
552 frame
.fhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
555 frame
.fhandle_pixel
= texture
->color().pixel();
557 texture
= &(screen
->getWindowStyle()->h_unfocus
);
558 frame
.uhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
561 frame
.uhandle_pixel
= texture
->color().pixel();
563 texture
= &(screen
->getWindowStyle()->g_focus
);
564 frame
.fgrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.fgrip
);
566 frame
.fgrip_pixel
= texture
->color().pixel();
568 texture
= &(screen
->getWindowStyle()->g_unfocus
);
569 frame
.ugrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.ugrip
);
571 frame
.ugrip_pixel
= texture
->color().pixel();
573 XSetWindowBorder(blackbox
->getXDisplay(), frame
.handle
,
574 screen
->getBorderColor()->pixel());
575 XSetWindowBorder(blackbox
->getXDisplay(), frame
.left_grip
,
576 screen
->getBorderColor()->pixel());
577 XSetWindowBorder(blackbox
->getXDisplay(), frame
.right_grip
,
578 screen
->getBorderColor()->pixel());
581 XSetWindowBorder(blackbox
->getXDisplay(), frame
.window
,
582 screen
->getBorderColor()->pixel());
586 void BlackboxWindow::decorateLabel(void) {
589 texture
= &(screen
->getWindowStyle()->l_focus
);
590 frame
.flabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.flabel
);
592 frame
.flabel_pixel
= texture
->color().pixel();
594 texture
= &(screen
->getWindowStyle()->l_unfocus
);
595 frame
.ulabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.ulabel
);
597 frame
.ulabel_pixel
= texture
->color().pixel();
601 void BlackboxWindow::createHandle(void) {
602 frame
.handle
= createChildWindow(frame
.window
);
603 blackbox
->saveWindowSearch(frame
.handle
, this);
606 createChildWindow(frame
.handle
, blackbox
->getLowerLeftAngleCursor());
607 blackbox
->saveWindowSearch(frame
.left_grip
, this);
610 createChildWindow(frame
.handle
, blackbox
->getLowerRightAngleCursor());
611 blackbox
->saveWindowSearch(frame
.right_grip
, this);
615 void BlackboxWindow::destroyHandle(void) {
617 screen
->getImageControl()->removeImage(frame
.fhandle
);
620 screen
->getImageControl()->removeImage(frame
.uhandle
);
623 screen
->getImageControl()->removeImage(frame
.fgrip
);
626 screen
->getImageControl()->removeImage(frame
.ugrip
);
628 blackbox
->removeWindowSearch(frame
.left_grip
);
629 blackbox
->removeWindowSearch(frame
.right_grip
);
631 XDestroyWindow(blackbox
->getXDisplay(), frame
.left_grip
);
632 XDestroyWindow(blackbox
->getXDisplay(), frame
.right_grip
);
633 frame
.left_grip
= frame
.right_grip
= None
;
635 blackbox
->removeWindowSearch(frame
.handle
);
636 XDestroyWindow(blackbox
->getXDisplay(), frame
.handle
);
641 void BlackboxWindow::createTitlebar(void) {
642 frame
.title
= createChildWindow(frame
.window
);
643 frame
.label
= createChildWindow(frame
.title
);
644 blackbox
->saveWindowSearch(frame
.title
, this);
645 blackbox
->saveWindowSearch(frame
.label
, this);
647 if (decorations
& Decor_Iconify
) createIconifyButton();
648 if (decorations
& Decor_Maximize
) createMaximizeButton();
649 if (decorations
& Decor_Close
) createCloseButton();
653 void BlackboxWindow::destroyTitlebar(void) {
654 if (frame
.close_button
)
655 destroyCloseButton();
657 if (frame
.iconify_button
)
658 destroyIconifyButton();
660 if (frame
.maximize_button
)
661 destroyMaximizeButton();
664 screen
->getImageControl()->removeImage(frame
.ftitle
);
667 screen
->getImageControl()->removeImage(frame
.utitle
);
670 screen
->getImageControl()->removeImage(frame
.flabel
);
673 screen
->getImageControl()->removeImage(frame
.ulabel
);
676 screen
->getImageControl()->removeImage(frame
.fbutton
);
679 screen
->getImageControl()->removeImage(frame
.ubutton
);
682 screen
->getImageControl()->removeImage(frame
.pbutton
);
684 blackbox
->removeWindowSearch(frame
.title
);
685 blackbox
->removeWindowSearch(frame
.label
);
687 XDestroyWindow(blackbox
->getXDisplay(), frame
.label
);
688 XDestroyWindow(blackbox
->getXDisplay(), frame
.title
);
689 frame
.title
= frame
.label
= None
;
693 void BlackboxWindow::createCloseButton(void) {
694 if (frame
.title
!= None
) {
695 frame
.close_button
= createChildWindow(frame
.title
);
696 blackbox
->saveWindowSearch(frame
.close_button
, this);
701 void BlackboxWindow::destroyCloseButton(void) {
702 blackbox
->removeWindowSearch(frame
.close_button
);
703 XDestroyWindow(blackbox
->getXDisplay(), frame
.close_button
);
704 frame
.close_button
= None
;
708 void BlackboxWindow::createIconifyButton(void) {
709 if (frame
.title
!= None
) {
710 frame
.iconify_button
= createChildWindow(frame
.title
);
711 blackbox
->saveWindowSearch(frame
.iconify_button
, this);
716 void BlackboxWindow::destroyIconifyButton(void) {
717 blackbox
->removeWindowSearch(frame
.iconify_button
);
718 XDestroyWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
719 frame
.iconify_button
= None
;
723 void BlackboxWindow::createMaximizeButton(void) {
724 if (frame
.title
!= None
) {
725 frame
.maximize_button
= createChildWindow(frame
.title
);
726 blackbox
->saveWindowSearch(frame
.maximize_button
, this);
731 void BlackboxWindow::destroyMaximizeButton(void) {
732 blackbox
->removeWindowSearch(frame
.maximize_button
);
733 XDestroyWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
734 frame
.maximize_button
= None
;
738 void BlackboxWindow::positionButtons(bool redecorate_label
) {
739 string layout
= blackbox
->getTitlebarLayout();
742 bool hasclose
, hasiconify
, hasmaximize
, haslabel
;
743 hasclose
= hasiconify
= hasmaximize
= haslabel
= false;
745 string::const_iterator it
, end
;
746 for (it
= layout
.begin(), end
= layout
.end(); it
!= end
; ++it
) {
749 if (! hasclose
&& (decorations
& Decor_Close
)) {
755 if (! hasiconify
&& (decorations
& Decor_Iconify
)) {
761 if (! hasmaximize
&& (decorations
& Decor_Maximize
)) {
773 if (! hasclose
&& frame
.close_button
)
774 destroyCloseButton();
775 if (! hasiconify
&& frame
.iconify_button
)
776 destroyIconifyButton();
777 if (! hasmaximize
&& frame
.maximize_button
)
778 destroyMaximizeButton();
780 parsed
+= 'L'; // require that the label be in the layout
782 const unsigned int bsep
= frame
.bevel_w
+ 1; // separation between elements
783 const unsigned int by
= frame
.bevel_w
+ 1;
784 const unsigned int ty
= frame
.bevel_w
;
786 frame
.label_w
= frame
.inside_w
- bsep
* 2 -
787 (frame
.button_w
+ bsep
) * (parsed
.size() - 1);
789 unsigned int x
= bsep
;
790 for (it
= parsed
.begin(), end
= parsed
.end(); it
!= end
; ++it
) {
793 if (! frame
.close_button
) createCloseButton();
794 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.close_button
, x
, by
,
795 frame
.button_w
, frame
.button_w
);
796 x
+= frame
.button_w
+ bsep
;
799 if (! frame
.iconify_button
) createIconifyButton();
800 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.iconify_button
, x
, by
,
801 frame
.button_w
, frame
.button_w
);
802 x
+= frame
.button_w
+ bsep
;
805 if (! frame
.maximize_button
) createMaximizeButton();
806 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.maximize_button
, x
, by
,
807 frame
.button_w
, frame
.button_w
);
808 x
+= frame
.button_w
+ bsep
;
811 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.label
, x
, ty
,
812 frame
.label_w
, frame
.label_h
);
813 x
+= frame
.label_w
+ bsep
;
818 if (redecorate_label
) decorateLabel();
824 void BlackboxWindow::reconfigure(void) {
825 restoreGravity(client
.rect
);
827 applyGravity(frame
.rect
);
836 windowmenu
->move(windowmenu
->getX(), frame
.rect
.y() + frame
.title_h
);
837 windowmenu
->reconfigure();
842 void BlackboxWindow::grabButtons(void) {
843 if ((! screen
->isSloppyFocus()) || screen
->doClickRaise())
844 // grab button 1 for changing focus/raising
845 blackbox
->grabButton(Button1
, 0, frame
.plate
, True
, ButtonPressMask
,
846 GrabModeSync
, GrabModeSync
, frame
.plate
, None
);
848 if (functions
& Func_Move
)
849 blackbox
->grabButton(Button1
, Mod1Mask
, frame
.window
, True
,
850 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
851 GrabModeAsync
, frame
.window
,
852 blackbox
->getMoveCursor());
853 if (functions
& Func_Resize
)
854 blackbox
->grabButton(Button3
, Mod1Mask
, frame
.window
, True
,
855 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
856 GrabModeAsync
, frame
.window
, None
);
857 // alt+middle lowers the window
858 blackbox
->grabButton(Button2
, Mod1Mask
, frame
.window
, True
,
859 ButtonReleaseMask
, GrabModeAsync
, GrabModeAsync
,
864 void BlackboxWindow::ungrabButtons(void) {
865 if ((! screen
->isSloppyFocus()) || screen
->doClickRaise())
866 blackbox
->ungrabButton(Button1
, 0, frame
.plate
);
868 blackbox
->ungrabButton(Button1
, Mod1Mask
, frame
.window
);
869 blackbox
->ungrabButton(Button2
, Mod1Mask
, frame
.window
);
870 blackbox
->ungrabButton(Button3
, Mod1Mask
, frame
.window
);
874 void BlackboxWindow::positionWindows(void) {
875 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.window
,
876 frame
.rect
.x(), frame
.rect
.y(), frame
.inside_w
,
877 (flags
.shaded
) ? frame
.title_h
: frame
.inside_h
);
878 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.window
,
880 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.plate
,
882 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.plate
,
883 frame
.margin
.left
- frame
.mwm_border_w
- frame
.border_w
,
884 frame
.margin
.top
- frame
.mwm_border_w
- frame
.border_w
,
885 client
.rect
.width(), client
.rect
.height());
886 XMoveResizeWindow(blackbox
->getXDisplay(), client
.window
,
887 0, 0, client
.rect
.width(), client
.rect
.height());
888 // ensure client.rect contains the real location
889 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
890 frame
.rect
.top() + frame
.margin
.top
);
892 if (decorations
& Decor_Titlebar
) {
893 if (frame
.title
== None
) createTitlebar();
895 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.title
,
897 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.title
, -frame
.border_w
,
898 -frame
.border_w
, frame
.inside_w
, frame
.title_h
);
901 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
902 XMapWindow(blackbox
->getXDisplay(), frame
.title
);
903 } else if (frame
.title
) {
906 if (decorations
& Decor_Handle
) {
907 if (frame
.handle
== None
) createHandle();
908 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.handle
,
910 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.left_grip
,
912 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.right_grip
,
915 // use client.rect here so the value is correct even if shaded
916 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.handle
,
918 client
.rect
.height() + frame
.margin
.top
+
919 frame
.mwm_border_w
- frame
.border_w
,
920 frame
.inside_w
, frame
.handle_h
);
921 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.left_grip
,
922 -frame
.border_w
, -frame
.border_w
,
923 frame
.grip_w
, frame
.handle_h
);
924 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.right_grip
,
925 frame
.inside_w
- frame
.grip_w
- frame
.border_w
,
926 -frame
.border_w
, frame
.grip_w
, frame
.handle_h
);
928 XMapSubwindows(blackbox
->getXDisplay(), frame
.handle
);
929 XMapWindow(blackbox
->getXDisplay(), frame
.handle
);
930 } else if (frame
.handle
) {
933 XSync(blackbox
->getXDisplay(), False
);
937 void BlackboxWindow::updateStrut(void) {
938 unsigned long num
= 4;
940 if (! xatom
->getValue(client
.window
, XAtom::net_wm_strut
, XAtom::cardinal
,
945 client
.strut
.left
= data
[0];
946 client
.strut
.right
= data
[1];
947 client
.strut
.top
= data
[2];
948 client
.strut
.bottom
= data
[3];
950 screen
->updateAvailableArea();
957 void BlackboxWindow::getWindowType(void) {
959 if (xatom
->getValue(client
.window
, XAtom::net_wm_window_type
, XAtom::atom
,
961 if (val
== xatom
->getAtom(XAtom::net_wm_window_type_desktop
))
962 window_type
= Type_Desktop
;
963 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_dock
))
964 window_type
= Type_Dock
;
965 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_toolbar
))
966 window_type
= Type_Toolbar
;
967 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_menu
))
968 window_type
= Type_Menu
;
969 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_utility
))
970 window_type
= Type_Utility
;
971 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_splash
))
972 window_type
= Type_Splash
;
973 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_dialog
))
974 window_type
= Type_Dialog
;
975 else //if (val[0] == xatom->getAtom(XAtom::net_wm_window_type_normal))
976 window_type
= Type_Normal
;
981 * the window type hint was not set, which means we either classify ourself
982 * as a normal window or a dialog, depending on if we are a transient.
985 window_type
= Type_Dialog
;
987 window_type
= Type_Normal
;
991 void BlackboxWindow::getWMName(void) {
992 if (xatom
->getValue(client
.window
, XAtom::net_wm_name
,
993 XAtom::utf8
, client
.title
) &&
994 !client
.title
.empty()) {
995 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
998 //fall through to using WM_NAME
999 if (xatom
->getValue(client
.window
, XAtom::wm_name
, XAtom::ansi
, client
.title
)
1000 && !client
.title
.empty()) {
1001 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
1004 // fall back to an internal default
1005 client
.title
= i18n(WindowSet
, WindowUnnamed
, "Unnamed");
1006 xatom
->setValue(client
.window
, XAtom::net_wm_visible_name
, XAtom::utf8
,
1011 void BlackboxWindow::getWMIconName(void) {
1012 if (xatom
->getValue(client
.window
, XAtom::net_wm_icon_name
,
1013 XAtom::utf8
, client
.icon_title
) &&
1014 !client
.icon_title
.empty()) {
1015 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1018 //fall through to using WM_ICON_NAME
1019 if (xatom
->getValue(client
.window
, XAtom::wm_icon_name
, XAtom::ansi
,
1020 client
.icon_title
) &&
1021 !client
.icon_title
.empty()) {
1022 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1025 // fall back to using the main name
1026 client
.icon_title
= client
.title
;
1027 xatom
->setValue(client
.window
, XAtom::net_wm_visible_icon_name
, XAtom::utf8
,
1033 * Retrieve which WM Protocols are supported by the client window.
1034 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
1035 * window's decorations and allow the close behavior.
1036 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
1039 void BlackboxWindow::getWMProtocols(void) {
1043 if (XGetWMProtocols(blackbox
->getXDisplay(), client
.window
,
1044 &proto
, &num_return
)) {
1045 for (int i
= 0; i
< num_return
; ++i
) {
1046 if (proto
[i
] == xatom
->getAtom(XAtom::wm_delete_window
)) {
1047 decorations
|= Decor_Close
;
1048 functions
|= Func_Close
;
1049 } else if (proto
[i
] == xatom
->getAtom(XAtom::wm_take_focus
))
1050 flags
.send_focus_message
= True
;
1051 else if (proto
[i
] == xatom
->getAtom(XAtom::blackbox_structure_messages
))
1052 screen
->addNetizen(new Netizen(screen
, client
.window
));
1061 * Gets the value of the WM_HINTS property.
1062 * If the property is not set, then use a set of default values.
1064 void BlackboxWindow::getWMHints(void) {
1065 focus_mode
= F_Passive
;
1066 client
.initial_state
= NormalState
;
1068 // remove from current window group
1069 if (client
.window_group
) {
1070 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1071 if (group
) group
->removeWindow(this);
1073 client
.window_group
= None
;
1075 XWMHints
*wmhint
= XGetWMHints(blackbox
->getXDisplay(), client
.window
);
1080 if (wmhint
->flags
& InputHint
) {
1081 if (wmhint
->input
== True
) {
1082 if (flags
.send_focus_message
)
1083 focus_mode
= F_LocallyActive
;
1085 if (flags
.send_focus_message
)
1086 focus_mode
= F_GloballyActive
;
1088 focus_mode
= F_NoInput
;
1092 if (wmhint
->flags
& StateHint
)
1093 client
.initial_state
= wmhint
->initial_state
;
1095 if (wmhint
->flags
& WindowGroupHint
) {
1096 client
.window_group
= wmhint
->window_group
;
1098 // add window to the appropriate group
1099 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1100 if (! group
) { // no group found, create it!
1101 new BWindowGroup(blackbox
, client
.window_group
);
1102 group
= blackbox
->searchGroup(client
.window_group
);
1105 group
->addWindow(this);
1108 client
.wm_hint_flags
= wmhint
->flags
;
1114 * Gets the value of the WM_NORMAL_HINTS property.
1115 * If the property is not set, then use a set of default values.
1117 void BlackboxWindow::getWMNormalHints(void) {
1119 XSizeHints sizehint
;
1121 client
.min_width
= client
.min_height
=
1122 client
.width_inc
= client
.height_inc
= 1;
1123 client
.base_width
= client
.base_height
= 0;
1124 client
.win_gravity
= NorthWestGravity
;
1126 client
.min_aspect_x
= client
.min_aspect_y
=
1127 client
.max_aspect_x
= client
.max_aspect_y
= 1;
1131 use the full screen, not the strut modified size. otherwise when the
1132 availableArea changes max_width/height will be incorrect and lead to odd
1135 const Rect
& screen_area
= screen
->getRect();
1136 client
.max_width
= screen_area
.width();
1137 client
.max_height
= screen_area
.height();
1139 if (! XGetWMNormalHints(blackbox
->getXDisplay(), client
.window
,
1140 &sizehint
, &icccm_mask
))
1143 client
.normal_hint_flags
= sizehint
.flags
;
1145 if (sizehint
.flags
& PMinSize
) {
1146 if (sizehint
.min_width
>= 0)
1147 client
.min_width
= sizehint
.min_width
;
1148 if (sizehint
.min_height
>= 0)
1149 client
.min_height
= sizehint
.min_height
;
1152 if (sizehint
.flags
& PMaxSize
) {
1153 if (sizehint
.max_width
> static_cast<signed>(client
.min_width
))
1154 client
.max_width
= sizehint
.max_width
;
1156 client
.max_width
= client
.min_width
;
1158 if (sizehint
.max_height
> static_cast<signed>(client
.min_height
))
1159 client
.max_height
= sizehint
.max_height
;
1161 client
.max_height
= client
.min_height
;
1164 if (sizehint
.flags
& PResizeInc
) {
1165 client
.width_inc
= sizehint
.width_inc
;
1166 client
.height_inc
= sizehint
.height_inc
;
1169 #if 0 // we do not support this at the moment
1170 if (sizehint
.flags
& PAspect
) {
1171 client
.min_aspect_x
= sizehint
.min_aspect
.x
;
1172 client
.min_aspect_y
= sizehint
.min_aspect
.y
;
1173 client
.max_aspect_x
= sizehint
.max_aspect
.x
;
1174 client
.max_aspect_y
= sizehint
.max_aspect
.y
;
1178 if (sizehint
.flags
& PBaseSize
) {
1179 client
.base_width
= sizehint
.base_width
;
1180 client
.base_height
= sizehint
.base_height
;
1183 if (sizehint
.flags
& PWinGravity
)
1184 client
.win_gravity
= sizehint
.win_gravity
;
1189 * Gets the NETWM hints for the class' contained window.
1191 void BlackboxWindow::getNetWMHints(void) {
1192 unsigned long workspace
;
1194 if (xatom
->getValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1196 if (workspace
== 0xffffffff)
1199 blackbox_attrib
.workspace
= workspace
;
1202 unsigned long *state
;
1203 unsigned long num
= (unsigned) -1;
1204 if (xatom
->getValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
1208 for (unsigned long i
= 0; i
< num
; ++i
) {
1209 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
))
1211 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_shaded
))
1212 flags
.shaded
= True
;
1213 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
))
1214 flags
.skip_taskbar
= True
;
1215 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_pager
))
1216 flags
.skip_pager
= True
;
1217 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_fullscreen
))
1218 flags
.fullscreen
= True
;
1219 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_hidden
))
1220 setState(IconicState
);
1221 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_vert
))
1223 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_horz
))
1227 flags
.maximized
= 1;
1229 flags
.maximized
= 2;
1231 flags
.maximized
= 3;
1239 * Gets the MWM hints for the class' contained window.
1240 * This is used while initializing the window to its first state, and not
1242 * Returns: true if the MWM hints are successfully retreived and applied;
1243 * false if they are not.
1245 void BlackboxWindow::getMWMHints(void) {
1249 num
= PropMwmHintsElements
;
1250 if (! xatom
->getValue(client
.window
, XAtom::motif_wm_hints
,
1251 XAtom::motif_wm_hints
, num
,
1252 (unsigned long **)&mwm_hint
))
1254 if (num
< PropMwmHintsElements
) {
1259 if (mwm_hint
->flags
& MwmHintsDecorations
) {
1260 if (mwm_hint
->decorations
& MwmDecorAll
) {
1261 decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
1262 Decor_Iconify
| Decor_Maximize
| Decor_Close
;
1266 if (mwm_hint
->decorations
& MwmDecorBorder
)
1267 decorations
|= Decor_Border
;
1268 if (mwm_hint
->decorations
& MwmDecorHandle
)
1269 decorations
|= Decor_Handle
;
1270 if (mwm_hint
->decorations
& MwmDecorTitle
)
1271 decorations
|= Decor_Titlebar
;
1272 if (mwm_hint
->decorations
& MwmDecorIconify
)
1273 decorations
|= Decor_Iconify
;
1274 if (mwm_hint
->decorations
& MwmDecorMaximize
)
1275 decorations
|= Decor_Maximize
;
1279 if (mwm_hint
->flags
& MwmHintsFunctions
) {
1280 if (mwm_hint
->functions
& MwmFuncAll
) {
1281 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
|
1286 if (mwm_hint
->functions
& MwmFuncResize
)
1287 functions
|= Func_Resize
;
1288 if (mwm_hint
->functions
& MwmFuncMove
)
1289 functions
|= Func_Move
;
1290 if (mwm_hint
->functions
& MwmFuncIconify
)
1291 functions
|= Func_Iconify
;
1292 if (mwm_hint
->functions
& MwmFuncMaximize
)
1293 functions
|= Func_Maximize
;
1294 if (mwm_hint
->functions
& MwmFuncClose
)
1295 functions
|= Func_Close
;
1303 * Gets the blackbox hints from the class' contained window.
1304 * This is used while initializing the window to its first state, and not
1306 * Returns: true if the hints are successfully retreived and applied; false if
1309 bool BlackboxWindow::getBlackboxHints(void) {
1311 BlackboxHints
*blackbox_hint
;
1313 num
= PropBlackboxHintsElements
;
1314 if (! xatom
->getValue(client
.window
, XAtom::blackbox_hints
,
1315 XAtom::blackbox_hints
, num
,
1316 (unsigned long **)&blackbox_hint
))
1318 if (num
< PropBlackboxHintsElements
) {
1319 delete [] blackbox_hint
;
1323 if (blackbox_hint
->flags
& AttribShaded
)
1324 flags
.shaded
= (blackbox_hint
->attrib
& AttribShaded
);
1326 if ((blackbox_hint
->flags
& AttribMaxHoriz
) &&
1327 (blackbox_hint
->flags
& AttribMaxVert
))
1328 flags
.maximized
= (blackbox_hint
->attrib
&
1329 (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1330 else if (blackbox_hint
->flags
& AttribMaxVert
)
1331 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxVert
) ? 2 : 0;
1332 else if (blackbox_hint
->flags
& AttribMaxHoriz
)
1333 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1335 if (blackbox_hint
->flags
& AttribOmnipresent
)
1336 flags
.stuck
= (blackbox_hint
->attrib
& AttribOmnipresent
);
1338 if (blackbox_hint
->flags
& AttribWorkspace
)
1339 blackbox_attrib
.workspace
= blackbox_hint
->workspace
;
1341 // if (blackbox_hint->flags & AttribStack)
1342 // don't yet have always on top/bottom for blackbox yet... working
1345 if (blackbox_hint
->flags
& AttribDecoration
) {
1346 switch (blackbox_hint
->decoration
) {
1348 // clear all decorations except close
1349 decorations
&= Decor_Close
;
1350 // clear all functions except close
1351 functions
&= Func_Close
;
1356 decorations
|= Decor_Titlebar
| Decor_Iconify
;
1357 decorations
&= ~(Decor_Border
| Decor_Handle
| Decor_Maximize
);
1358 functions
|= Func_Move
| Func_Iconify
;
1359 functions
&= ~(Func_Resize
| Func_Maximize
);
1364 decorations
|= Decor_Titlebar
;
1365 decorations
&= ~(Decor_Iconify
| Decor_Border
| Decor_Handle
);
1366 functions
|= Func_Move
;
1367 functions
&= ~(Func_Resize
| Func_Maximize
| Func_Iconify
);
1373 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Handle
|
1374 Decor_Iconify
| Decor_Maximize
;
1375 functions
|= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
1383 delete [] blackbox_hint
;
1389 void BlackboxWindow::getTransientInfo(void) {
1390 if (client
.transient_for
&&
1391 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1392 // the transient for hint was removed, so we need to tell our
1393 // previous transient_for that we are going away
1394 client
.transient_for
->client
.transientList
.remove(this);
1397 // we have no transient_for until we find a new one
1398 client
.transient_for
= 0;
1401 if (! XGetTransientForHint(blackbox
->getXDisplay(), client
.window
,
1403 // transient_for hint not set
1407 if (trans_for
== client
.window
) {
1408 // wierd client... treat this window as a normal window
1412 if (trans_for
== None
|| trans_for
== screen
->getRootWindow()) {
1413 // this is an undocumented interpretation of the ICCCM. a transient
1414 // associated with None/Root/itself is assumed to be a modal root
1415 // transient. we don't support the concept of a global transient,
1416 // so we just associate this transient with nothing, and perhaps
1417 // we will add support later for global modality.
1418 client
.transient_for
= (BlackboxWindow
*) ~0ul;
1423 client
.transient_for
= blackbox
->searchWindow(trans_for
);
1424 if (! client
.transient_for
&&
1425 client
.window_group
&& trans_for
== client
.window_group
) {
1426 // no direct transient_for, perhaps this is a group transient?
1427 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1428 if (group
) client
.transient_for
= group
->find(screen
);
1431 if (! client
.transient_for
|| client
.transient_for
== this) {
1432 // no transient_for found, or we have a wierd client that wants to be
1433 // a transient for itself, so we treat this window as a normal window
1434 client
.transient_for
= (BlackboxWindow
*) 0;
1438 // register ourselves with our new transient_for
1439 client
.transient_for
->client
.transientList
.push_back(this);
1440 flags
.stuck
= client
.transient_for
->flags
.stuck
;
1444 bool BlackboxWindow::isKDESystrayWindow(void) {
1446 if (xatom
->getValue(client
.window
, XAtom::kde_net_wm_system_tray_window_for
,
1447 XAtom::window
, systray
) && systray
)
1453 BlackboxWindow
*BlackboxWindow::getTransientFor(void) const {
1454 if (client
.transient_for
&&
1455 client
.transient_for
!= (BlackboxWindow
*) ~0ul)
1456 return client
.transient_for
;
1462 * This function is responsible for updating both the client and the frame
1464 * According to the ICCCM a client message is not sent for a resize, only a
1467 void BlackboxWindow::configure(int dx
, int dy
,
1468 unsigned int dw
, unsigned int dh
) {
1469 bool send_event
= ((frame
.rect
.x() != dx
|| frame
.rect
.y() != dy
) &&
1472 if (dw
!= frame
.rect
.width() || dh
!= frame
.rect
.height()) {
1473 frame
.rect
.setRect(dx
, dy
, dw
, dh
);
1474 frame
.inside_w
= frame
.rect
.width() - (frame
.border_w
* 2);
1475 frame
.inside_h
= frame
.rect
.height() - (frame
.border_w
* 2);
1477 if (frame
.rect
.right() <= 0 || frame
.rect
.bottom() <= 0)
1478 frame
.rect
.setPos(0, 0);
1480 client
.rect
.setCoords(frame
.rect
.left() + frame
.margin
.left
,
1481 frame
.rect
.top() + frame
.margin
.top
,
1482 frame
.rect
.right() - frame
.margin
.right
,
1483 frame
.rect
.bottom() - frame
.margin
.bottom
);
1486 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
1493 redrawWindowFrame();
1495 frame
.rect
.setPos(dx
, dy
);
1497 XMoveWindow(blackbox
->getXDisplay(), frame
.window
,
1498 frame
.rect
.x(), frame
.rect
.y());
1500 we may have been called just after an opaque window move, so even though
1501 the old coords match the new ones no ConfigureNotify has been sent yet.
1502 There are likely other times when this will be relevant as well.
1504 if (! flags
.moving
) send_event
= True
;
1508 // if moving, the update and event will occur when the move finishes
1509 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1510 frame
.rect
.top() + frame
.margin
.top
);
1513 event
.type
= ConfigureNotify
;
1515 event
.xconfigure
.display
= blackbox
->getXDisplay();
1516 event
.xconfigure
.event
= client
.window
;
1517 event
.xconfigure
.window
= client
.window
;
1518 event
.xconfigure
.x
= client
.rect
.x();
1519 event
.xconfigure
.y
= client
.rect
.y();
1520 event
.xconfigure
.width
= client
.rect
.width();
1521 event
.xconfigure
.height
= client
.rect
.height();
1522 event
.xconfigure
.border_width
= client
.old_bw
;
1523 event
.xconfigure
.above
= frame
.window
;
1524 event
.xconfigure
.override_redirect
= False
;
1526 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1527 StructureNotifyMask
, &event
);
1528 screen
->updateNetizenConfigNotify(&event
);
1529 XFlush(blackbox
->getXDisplay());
1535 void BlackboxWindow::configureShape(void) {
1536 XShapeCombineShape(blackbox
->getXDisplay(), frame
.window
, ShapeBounding
,
1537 frame
.margin
.left
- frame
.border_w
,
1538 frame
.margin
.top
- frame
.border_w
,
1539 client
.window
, ShapeBounding
, ShapeSet
);
1542 XRectangle xrect
[2];
1544 if (decorations
& Decor_Titlebar
) {
1545 xrect
[0].x
= xrect
[0].y
= -frame
.border_w
;
1546 xrect
[0].width
= frame
.rect
.width();
1547 xrect
[0].height
= frame
.title_h
+ (frame
.border_w
* 2);
1551 if (decorations
& Decor_Handle
) {
1552 xrect
[1].x
= -frame
.border_w
;
1553 xrect
[1].y
= frame
.rect
.height() - frame
.margin
.bottom
+
1554 frame
.mwm_border_w
- frame
.border_w
;
1555 xrect
[1].width
= frame
.rect
.width();
1556 xrect
[1].height
= frame
.handle_h
+ (frame
.border_w
* 2);
1560 XShapeCombineRectangles(blackbox
->getXDisplay(), frame
.window
,
1561 ShapeBounding
, 0, 0, xrect
, num
,
1562 ShapeUnion
, Unsorted
);
1567 bool BlackboxWindow::setInputFocus(void) {
1568 if (flags
.focused
) return True
;
1570 assert(! flags
.iconic
&&
1571 (flags
.stuck
|| // window must be on the current workspace or sticky
1572 blackbox_attrib
.workspace
== screen
->getCurrentWorkspaceID()));
1574 // if the window is not visible, mark the window as wanting focus rather
1575 // than give it focus.
1576 if (! flags
.visible
) {
1577 Workspace
*wkspc
= screen
->getWorkspace(blackbox_attrib
.workspace
);
1578 wkspc
->setLastFocusedWindow(this);
1583 We only do this check for normal windows and dialogs because other windows
1584 do this on purpose, such as kde's kicker, and we don't want to go moving
1587 if (window_type
== Type_Normal
|| window_type
== Type_Dialog
)
1588 if (! frame
.rect
.intersects(screen
->getRect())) {
1589 // client is outside the screen, move it to the center
1590 configure((screen
->getWidth() - frame
.rect
.width()) / 2,
1591 (screen
->getHeight() - frame
.rect
.height()) / 2,
1592 frame
.rect
.width(), frame
.rect
.height());
1595 if (client
.transientList
.size() > 0) {
1596 // transfer focus to any modal transients
1597 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1598 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1599 if ((*it
)->flags
.modal
) return (*it
)->setInputFocus();
1604 if (focus_mode
== F_LocallyActive
|| focus_mode
== F_Passive
) {
1605 XSetInputFocus(blackbox
->getXDisplay(), client
.window
,
1606 RevertToPointerRoot
, CurrentTime
);
1608 blackbox
->setFocusedWindow(this);
1610 /* we could set the focus to none, since the window doesn't accept focus,
1611 * but we shouldn't set focus to nothing since this would surely make
1617 if (flags
.send_focus_message
) {
1619 ce
.xclient
.type
= ClientMessage
;
1620 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1621 ce
.xclient
.display
= blackbox
->getXDisplay();
1622 ce
.xclient
.window
= client
.window
;
1623 ce
.xclient
.format
= 32;
1624 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_take_focus
);
1625 ce
.xclient
.data
.l
[1] = blackbox
->getLastTime();
1626 ce
.xclient
.data
.l
[2] = 0l;
1627 ce
.xclient
.data
.l
[3] = 0l;
1628 ce
.xclient
.data
.l
[4] = 0l;
1629 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1631 XFlush(blackbox
->getXDisplay());
1638 void BlackboxWindow::iconify(void) {
1639 if (flags
.iconic
) return;
1641 // We don't need to worry about resizing because resizing always grabs the X
1642 // server. This should only ever happen if using opaque moving.
1646 if (windowmenu
) windowmenu
->hide();
1649 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1650 * we need to clear the event mask on client.window for a split second.
1651 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1652 * split second, leaving us with a ghost window... so, we need to do this
1653 * while the X server is grabbed
1655 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1656 StructureNotifyMask
;
1657 XGrabServer(blackbox
->getXDisplay());
1658 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1659 event_mask
& ~StructureNotifyMask
);
1660 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1661 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1662 XUngrabServer(blackbox
->getXDisplay());
1664 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1665 flags
.visible
= False
;
1666 flags
.iconic
= True
;
1668 setState(IconicState
);
1670 screen
->getWorkspace(blackbox_attrib
.workspace
)->removeWindow(this);
1672 if (isTransient()) {
1673 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1674 ! client
.transient_for
->flags
.iconic
) {
1675 // iconify our transient_for
1676 client
.transient_for
->iconify();
1680 screen
->addIcon(this);
1682 if (client
.transientList
.size() > 0) {
1683 // iconify all transients
1684 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1685 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1686 if (! (*it
)->flags
.iconic
) (*it
)->iconify();
1689 screen
->updateStackingList();
1693 void BlackboxWindow::show(void) {
1694 flags
.visible
= True
;
1695 flags
.iconic
= False
;
1697 current_state
= (flags
.shaded
) ? IconicState
: NormalState
;
1698 setState(current_state
);
1700 XMapWindow(blackbox
->getXDisplay(), client
.window
);
1701 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
1702 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
1707 XTranslateCoordinates(blackbox
->getXDisplay(), client
.window
,
1708 screen
->getRootWindow(),
1709 0, 0, &real_x
, &real_y
, &child
);
1710 fprintf(stderr
, "%s -- assumed: (%d, %d), real: (%d, %d)\n", getTitle(),
1711 client
.rect
.left(), client
.rect
.top(), real_x
, real_y
);
1712 assert(client
.rect
.left() == real_x
&& client
.rect
.top() == real_y
);
1717 void BlackboxWindow::deiconify(bool reassoc
, bool raise
) {
1718 if (flags
.iconic
|| reassoc
)
1719 screen
->reassociateWindow(this, BSENTINEL
, False
);
1720 else if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID())
1725 // reassociate and deiconify all transients
1726 if (reassoc
&& client
.transientList
.size() > 0) {
1727 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1728 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1729 (*it
)->deiconify(True
, False
);
1734 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1738 void BlackboxWindow::close(void) {
1740 ce
.xclient
.type
= ClientMessage
;
1741 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1742 ce
.xclient
.display
= blackbox
->getXDisplay();
1743 ce
.xclient
.window
= client
.window
;
1744 ce
.xclient
.format
= 32;
1745 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_delete_window
);
1746 ce
.xclient
.data
.l
[1] = CurrentTime
;
1747 ce
.xclient
.data
.l
[2] = 0l;
1748 ce
.xclient
.data
.l
[3] = 0l;
1749 ce
.xclient
.data
.l
[4] = 0l;
1750 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
, NoEventMask
, &ce
);
1751 XFlush(blackbox
->getXDisplay());
1755 void BlackboxWindow::withdraw(void) {
1756 // We don't need to worry about resizing because resizing always grabs the X
1757 // server. This should only ever happen if using opaque moving.
1761 flags
.visible
= False
;
1762 flags
.iconic
= False
;
1764 setState(current_state
);
1766 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1768 XGrabServer(blackbox
->getXDisplay());
1770 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1771 StructureNotifyMask
;
1772 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1773 event_mask
& ~StructureNotifyMask
);
1774 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1775 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1777 XUngrabServer(blackbox
->getXDisplay());
1779 if (windowmenu
) windowmenu
->hide();
1783 void BlackboxWindow::maximize(unsigned int button
) {
1784 // We don't need to worry about resizing because resizing always grabs the X
1785 // server. This should only ever happen if using opaque moving.
1789 // handle case where menu is open then the max button is used instead
1790 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
1792 if (flags
.maximized
) {
1793 flags
.maximized
= 0;
1795 blackbox_attrib
.flags
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1796 blackbox_attrib
.attrib
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1799 when a resize finishes, maximize(0) is called to clear any maximization
1800 flags currently set. Otherwise it still thinks it is maximized.
1801 so we do not need to call configure() because resizing will handle it
1803 if (! flags
.resizing
)
1804 configure(blackbox_attrib
.premax_x
, blackbox_attrib
.premax_y
,
1805 blackbox_attrib
.premax_w
, blackbox_attrib
.premax_h
);
1807 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
1808 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
1810 redrawAllButtons(); // in case it is not called in configure()
1811 setState(current_state
);
1815 blackbox_attrib
.premax_x
= frame
.rect
.x();
1816 blackbox_attrib
.premax_y
= frame
.rect
.y();
1817 blackbox_attrib
.premax_w
= frame
.rect
.width();
1818 // use client.rect so that clients can be restored even if shaded
1819 blackbox_attrib
.premax_h
=
1820 client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
;
1822 const Rect
&screen_area
= screen
->availableArea();
1823 frame
.changing
= screen_area
;
1827 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1828 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1832 blackbox_attrib
.flags
|= AttribMaxVert
;
1833 blackbox_attrib
.attrib
|= AttribMaxVert
;
1835 frame
.changing
.setX(frame
.rect
.x());
1836 frame
.changing
.setWidth(frame
.rect
.width());
1840 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1841 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1843 frame
.changing
.setY(frame
.rect
.y());
1844 frame
.changing
.setHeight(frame
.rect
.height());
1851 blackbox_attrib
.flags
^= AttribShaded
;
1852 blackbox_attrib
.attrib
^= AttribShaded
;
1853 flags
.shaded
= False
;
1856 flags
.maximized
= button
;
1858 configure(frame
.changing
.x(), frame
.changing
.y(),
1859 frame
.changing
.width(), frame
.changing
.height());
1861 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1862 redrawAllButtons(); // in case it is not called in configure()
1863 setState(current_state
);
1867 // re-maximizes the window to take into account availableArea changes
1868 void BlackboxWindow::remaximize(void) {
1869 // save the original dimensions because maximize will wipe them out
1870 int premax_x
= blackbox_attrib
.premax_x
,
1871 premax_y
= blackbox_attrib
.premax_y
,
1872 premax_w
= blackbox_attrib
.premax_w
,
1873 premax_h
= blackbox_attrib
.premax_h
;
1875 unsigned int button
= flags
.maximized
;
1876 flags
.maximized
= 0; // trick maximize() into working
1879 // restore saved values
1880 blackbox_attrib
.premax_x
= premax_x
;
1881 blackbox_attrib
.premax_y
= premax_y
;
1882 blackbox_attrib
.premax_w
= premax_w
;
1883 blackbox_attrib
.premax_h
= premax_h
;
1887 void BlackboxWindow::setWorkspace(unsigned int n
) {
1888 blackbox_attrib
.flags
|= AttribWorkspace
;
1889 blackbox_attrib
.workspace
= n
;
1890 if (n
== BSENTINEL
) { // iconified window
1892 we set the workspace to 'all workspaces' so that taskbars will show the
1893 window. otherwise, it made uniconifying a window imposible without the
1894 blackbox workspace menu
1898 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
, n
);
1902 void BlackboxWindow::shade(void) {
1904 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1905 frame
.inside_w
, frame
.inside_h
);
1906 flags
.shaded
= False
;
1907 blackbox_attrib
.flags
^= AttribShaded
;
1908 blackbox_attrib
.attrib
^= AttribShaded
;
1910 setState(NormalState
);
1912 // set the frame rect to the normal size
1913 frame
.rect
.setHeight(client
.rect
.height() + frame
.margin
.top
+
1914 frame
.margin
.bottom
);
1916 if (! (decorations
& Decor_Titlebar
))
1917 return; // can't shade it without a titlebar!
1919 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1920 frame
.inside_w
, frame
.title_h
);
1921 flags
.shaded
= True
;
1922 blackbox_attrib
.flags
|= AttribShaded
;
1923 blackbox_attrib
.attrib
|= AttribShaded
;
1925 setState(IconicState
);
1927 // set the frame rect to the shaded size
1928 frame
.rect
.setHeight(frame
.title_h
+ (frame
.border_w
* 2));
1934 * (Un)Sticks a window and its relatives.
1936 void BlackboxWindow::stick(void) {
1938 blackbox_attrib
.flags
^= AttribOmnipresent
;
1939 blackbox_attrib
.attrib
^= AttribOmnipresent
;
1941 flags
.stuck
= False
;
1944 screen
->reassociateWindow(this, BSENTINEL
, True
);
1946 // temporary fix since sticky windows suck. set the hint to what we
1947 // actually hold in our data.
1948 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1949 blackbox_attrib
.workspace
);
1951 setState(current_state
);
1955 blackbox_attrib
.flags
|= AttribOmnipresent
;
1956 blackbox_attrib
.attrib
|= AttribOmnipresent
;
1958 // temporary fix since sticky windows suck. set the hint to a different
1959 // value than that contained in the class' data.
1960 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1963 setState(current_state
);
1966 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1967 client
.transient_for
->isStuck() != flags
.stuck
)
1968 client
.transient_for
->stick();
1969 // go down the chain
1970 BlackboxWindowList::iterator it
;
1971 const BlackboxWindowList::iterator end
= client
.transientList
.end();
1972 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1973 if ((*it
)->isStuck() != flags
.stuck
)
1978 void BlackboxWindow::redrawWindowFrame(void) const {
1979 if (decorations
& Decor_Titlebar
) {
1980 if (flags
.focused
) {
1982 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1983 frame
.title
, frame
.ftitle
);
1985 XSetWindowBackground(blackbox
->getXDisplay(),
1986 frame
.title
, frame
.ftitle_pixel
);
1989 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1990 frame
.title
, frame
.utitle
);
1992 XSetWindowBackground(blackbox
->getXDisplay(),
1993 frame
.title
, frame
.utitle_pixel
);
1995 XClearWindow(blackbox
->getXDisplay(), frame
.title
);
2001 if (decorations
& Decor_Handle
) {
2002 if (flags
.focused
) {
2004 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2005 frame
.handle
, frame
.fhandle
);
2007 XSetWindowBackground(blackbox
->getXDisplay(),
2008 frame
.handle
, frame
.fhandle_pixel
);
2011 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2012 frame
.left_grip
, frame
.fgrip
);
2013 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2014 frame
.right_grip
, frame
.fgrip
);
2016 XSetWindowBackground(blackbox
->getXDisplay(),
2017 frame
.left_grip
, frame
.fgrip_pixel
);
2018 XSetWindowBackground(blackbox
->getXDisplay(),
2019 frame
.right_grip
, frame
.fgrip_pixel
);
2023 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2024 frame
.handle
, frame
.uhandle
);
2026 XSetWindowBackground(blackbox
->getXDisplay(),
2027 frame
.handle
, frame
.uhandle_pixel
);
2030 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2031 frame
.left_grip
, frame
.ugrip
);
2032 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2033 frame
.right_grip
, frame
.ugrip
);
2035 XSetWindowBackground(blackbox
->getXDisplay(),
2036 frame
.left_grip
, frame
.ugrip_pixel
);
2037 XSetWindowBackground(blackbox
->getXDisplay(),
2038 frame
.right_grip
, frame
.ugrip_pixel
);
2041 XClearWindow(blackbox
->getXDisplay(), frame
.handle
);
2042 XClearWindow(blackbox
->getXDisplay(), frame
.left_grip
);
2043 XClearWindow(blackbox
->getXDisplay(), frame
.right_grip
);
2046 if (decorations
& Decor_Border
) {
2048 XSetWindowBorder(blackbox
->getXDisplay(),
2049 frame
.plate
, frame
.fborder_pixel
);
2051 XSetWindowBorder(blackbox
->getXDisplay(),
2052 frame
.plate
, frame
.uborder_pixel
);
2057 void BlackboxWindow::setFocusFlag(bool focus
) {
2058 // only focus a window if it is visible
2059 if (focus
&& !flags
.visible
)
2062 flags
.focused
= focus
;
2064 redrawWindowFrame();
2066 if (screen
->isSloppyFocus() && screen
->doAutoRaise()) {
2067 if (isFocused()) timer
->start();
2072 blackbox
->setFocusedWindow(this);
2076 void BlackboxWindow::installColormap(bool install
) {
2077 int i
= 0, ncmap
= 0;
2078 Colormap
*cmaps
= XListInstalledColormaps(blackbox
->getXDisplay(),
2079 client
.window
, &ncmap
);
2081 XWindowAttributes wattrib
;
2082 if (XGetWindowAttributes(blackbox
->getXDisplay(),
2083 client
.window
, &wattrib
)) {
2085 // install the window's colormap
2086 for (i
= 0; i
< ncmap
; i
++) {
2087 if (*(cmaps
+ i
) == wattrib
.colormap
)
2088 // this window is using an installed color map... do not install
2091 // otherwise, install the window's colormap
2093 XInstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2095 // uninstall the window's colormap
2096 for (i
= 0; i
< ncmap
; i
++) {
2097 if (*(cmaps
+ i
) == wattrib
.colormap
)
2098 // we found the colormap to uninstall
2099 XUninstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2109 void BlackboxWindow::setAllowedActions(void) {
2113 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_shade
);
2114 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_change_desktop
);
2115 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_close
);
2117 if (functions
& Func_Move
)
2118 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_move
);
2119 if (functions
& Func_Resize
)
2120 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_resize
);
2121 if (functions
& Func_Maximize
) {
2122 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_horz
);
2123 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_vert
);
2126 xatom
->setValue(client
.window
, XAtom::net_wm_allowed_actions
, XAtom::atom
,
2131 void BlackboxWindow::setState(unsigned long new_state
) {
2132 current_state
= new_state
;
2134 unsigned long state
[2];
2135 state
[0] = current_state
;
2137 xatom
->setValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
, state
, 2);
2139 xatom
->setValue(client
.window
, XAtom::blackbox_attributes
,
2140 XAtom::blackbox_attributes
, (unsigned long *)&blackbox_attrib
,
2141 PropBlackboxAttributesElements
);
2146 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_modal
);
2148 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_shaded
);
2150 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_hidden
);
2151 if (flags
.skip_taskbar
)
2152 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
);
2153 if (flags
.skip_pager
)
2154 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_pager
);
2155 if (flags
.fullscreen
)
2156 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_fullscreen
);
2157 if (flags
.maximized
== 1 || flags
.maximized
== 2)
2158 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_vert
);
2159 if (flags
.maximized
== 1 || flags
.maximized
== 3)
2160 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_horz
);
2161 xatom
->setValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
2166 bool BlackboxWindow::getState(void) {
2167 bool ret
= xatom
->getValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
,
2169 if (! ret
) current_state
= 0;
2174 void BlackboxWindow::restoreAttributes(void) {
2175 unsigned long num
= PropBlackboxAttributesElements
;
2176 BlackboxAttributes
*net
;
2177 if (! xatom
->getValue(client
.window
, XAtom::blackbox_attributes
,
2178 XAtom::blackbox_attributes
, num
,
2179 (unsigned long **)&net
))
2181 if (num
< PropBlackboxAttributesElements
) {
2186 if (net
->flags
& AttribShaded
&& net
->attrib
& AttribShaded
) {
2187 flags
.shaded
= False
;
2188 unsigned long orig_state
= current_state
;
2192 At this point in the life of a window, current_state should only be set
2193 to IconicState if the window was an *icon*, not if it was shaded.
2195 if (orig_state
!= IconicState
)
2196 current_state
= WithdrawnState
;
2199 if (net
->workspace
!= screen
->getCurrentWorkspaceID() &&
2200 net
->workspace
< screen
->getWorkspaceCount())
2201 screen
->reassociateWindow(this, net
->workspace
, True
);
2203 if ((blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID()) &&
2204 (blackbox_attrib
.workspace
< screen
->getWorkspaceCount())) {
2205 // set to WithdrawnState so it will be mapped on the new workspace
2206 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2207 } else if (current_state
== WithdrawnState
) {
2208 // the window is on this workspace and is Withdrawn, so it is waiting to
2210 current_state
= NormalState
;
2213 if (net
->flags
& AttribOmnipresent
&& net
->attrib
& AttribOmnipresent
) {
2214 flags
.stuck
= False
;
2217 // if the window was on another workspace, it was going to be hidden. this
2218 // specifies that the window should be mapped since it is sticky.
2219 if (current_state
== WithdrawnState
) current_state
= NormalState
;
2222 if (net
->flags
& AttribMaxHoriz
|| net
->flags
& AttribMaxVert
) {
2223 int x
= net
->premax_x
, y
= net
->premax_y
;
2224 unsigned int w
= net
->premax_w
, h
= net
->premax_h
;
2225 flags
.maximized
= 0;
2228 if ((net
->flags
& AttribMaxHoriz
) &&
2229 (net
->flags
& AttribMaxVert
))
2230 m
= (net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
2231 else if (net
->flags
& AttribMaxVert
)
2232 m
= (net
->attrib
& AttribMaxVert
) ? 2 : 0;
2233 else if (net
->flags
& AttribMaxHoriz
)
2234 m
= (net
->attrib
& AttribMaxHoriz
) ? 3 : 0;
2238 blackbox_attrib
.premax_x
= x
;
2239 blackbox_attrib
.premax_y
= y
;
2240 blackbox_attrib
.premax_w
= w
;
2241 blackbox_attrib
.premax_h
= h
;
2244 // with the state set it will then be the map event's job to read the
2245 // window's state and behave accordingly
2252 * Positions the Rect r according the the client window position and
2255 void BlackboxWindow::applyGravity(Rect
&r
) {
2256 // apply horizontal window gravity
2257 switch (client
.win_gravity
) {
2259 case NorthWestGravity
:
2260 case SouthWestGravity
:
2262 r
.setX(client
.rect
.x());
2268 r
.setX(client
.rect
.x() - (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2271 case NorthEastGravity
:
2272 case SouthEastGravity
:
2274 r
.setX(client
.rect
.x() - frame
.margin
.left
- frame
.margin
.right
+ 2);
2279 r
.setX(client
.rect
.x() - frame
.margin
.left
);
2283 // apply vertical window gravity
2284 switch (client
.win_gravity
) {
2286 case NorthWestGravity
:
2287 case NorthEastGravity
:
2289 r
.setY(client
.rect
.y());
2295 r
.setY(client
.rect
.y() - (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2298 case SouthWestGravity
:
2299 case SouthEastGravity
:
2301 r
.setY(client
.rect
.y() - frame
.margin
.top
- frame
.margin
.bottom
+ 2);
2306 r
.setY(client
.rect
.y() - frame
.margin
.top
);
2313 * The reverse of the applyGravity function.
2315 * Positions the Rect r according to the frame window position and
2318 void BlackboxWindow::restoreGravity(Rect
&r
) {
2319 // restore horizontal window gravity
2320 switch (client
.win_gravity
) {
2322 case NorthWestGravity
:
2323 case SouthWestGravity
:
2325 r
.setX(frame
.rect
.x());
2331 r
.setX(frame
.rect
.x() + (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2334 case NorthEastGravity
:
2335 case SouthEastGravity
:
2337 r
.setX(frame
.rect
.x() + frame
.margin
.left
+ frame
.margin
.right
- 2);
2342 r
.setX(frame
.rect
.x() + frame
.margin
.left
);
2346 // restore vertical window gravity
2347 switch (client
.win_gravity
) {
2349 case NorthWestGravity
:
2350 case NorthEastGravity
:
2352 r
.setY(frame
.rect
.y());
2358 r
.setY(frame
.rect
.y() + (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2361 case SouthWestGravity
:
2362 case SouthEastGravity
:
2364 r
.setY(frame
.rect
.y() + frame
.margin
.top
+ frame
.margin
.bottom
- 2);
2369 r
.setY(frame
.rect
.y() + frame
.margin
.top
);
2375 void BlackboxWindow::redrawLabel(void) const {
2376 if (flags
.focused
) {
2378 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2379 frame
.label
, frame
.flabel
);
2381 XSetWindowBackground(blackbox
->getXDisplay(),
2382 frame
.label
, frame
.flabel_pixel
);
2385 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2386 frame
.label
, frame
.ulabel
);
2388 XSetWindowBackground(blackbox
->getXDisplay(),
2389 frame
.label
, frame
.ulabel_pixel
);
2391 XClearWindow(blackbox
->getXDisplay(), frame
.label
);
2393 WindowStyle
*style
= screen
->getWindowStyle();
2395 int pos
= frame
.bevel_w
* 2;
2396 style
->doJustify(client
.title
.c_str(), pos
, frame
.label_w
, frame
.bevel_w
* 4);
2397 style
->font
->drawString(frame
.label
, pos
, 1,
2398 (flags
.focused
? style
->l_text_focus
:
2399 style
->l_text_unfocus
),
2404 void BlackboxWindow::redrawAllButtons(void) const {
2405 if (frame
.iconify_button
) redrawIconifyButton(False
);
2406 if (frame
.maximize_button
) redrawMaximizeButton(flags
.maximized
);
2407 if (frame
.close_button
) redrawCloseButton(False
);
2411 void BlackboxWindow::redrawIconifyButton(bool pressed
) const {
2413 if (flags
.focused
) {
2415 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2416 frame
.iconify_button
, frame
.fbutton
);
2418 XSetWindowBackground(blackbox
->getXDisplay(),
2419 frame
.iconify_button
, frame
.fbutton_pixel
);
2422 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2423 frame
.iconify_button
, frame
.ubutton
);
2425 XSetWindowBackground(blackbox
->getXDisplay(), frame
.iconify_button
,
2426 frame
.ubutton_pixel
);
2430 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2431 frame
.iconify_button
, frame
.pbutton
);
2433 XSetWindowBackground(blackbox
->getXDisplay(),
2434 frame
.iconify_button
, frame
.pbutton_pixel
);
2436 XClearWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
2438 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2439 screen
->getWindowStyle()->b_pic_unfocus
);
2440 XDrawRectangle(blackbox
->getXDisplay(), frame
.iconify_button
, pen
.gc(),
2441 2, (frame
.button_w
- 5), (frame
.button_w
- 5), 2);
2445 void BlackboxWindow::redrawMaximizeButton(bool pressed
) const {
2447 if (flags
.focused
) {
2449 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2450 frame
.maximize_button
, frame
.fbutton
);
2452 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2453 frame
.fbutton_pixel
);
2456 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2457 frame
.maximize_button
, frame
.ubutton
);
2459 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2460 frame
.ubutton_pixel
);
2464 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2465 frame
.maximize_button
, frame
.pbutton
);
2467 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2468 frame
.pbutton_pixel
);
2470 XClearWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
2472 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2473 screen
->getWindowStyle()->b_pic_unfocus
);
2474 XDrawRectangle(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2475 2, 2, (frame
.button_w
- 5), (frame
.button_w
- 5));
2476 XDrawLine(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2477 2, 3, (frame
.button_w
- 3), 3);
2481 void BlackboxWindow::redrawCloseButton(bool pressed
) const {
2483 if (flags
.focused
) {
2485 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2488 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2489 frame
.fbutton_pixel
);
2492 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2495 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2496 frame
.ubutton_pixel
);
2500 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2501 frame
.close_button
, frame
.pbutton
);
2503 XSetWindowBackground(blackbox
->getXDisplay(),
2504 frame
.close_button
, frame
.pbutton_pixel
);
2506 XClearWindow(blackbox
->getXDisplay(), frame
.close_button
);
2508 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2509 screen
->getWindowStyle()->b_pic_unfocus
);
2510 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2511 2, 2, (frame
.button_w
- 3), (frame
.button_w
- 3));
2512 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2513 2, (frame
.button_w
- 3), (frame
.button_w
- 3), 2);
2517 void BlackboxWindow::mapRequestEvent(const XMapRequestEvent
*re
) {
2518 if (re
->window
!= client
.window
)
2522 fprintf(stderr
, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2526 switch (current_state
) {
2531 case WithdrawnState
:
2540 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2541 if (! blackbox
->isStartup() && (isTransient() || screen
->doFocusNew())) {
2542 XSync(blackbox
->getXDisplay(), False
); // make sure the frame is mapped..
2550 void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent
*ue
) {
2551 if (ue
->window
!= client
.window
)
2555 fprintf(stderr
, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2559 screen
->unmanageWindow(this, False
);
2563 void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent
*de
) {
2564 if (de
->window
!= client
.window
)
2568 fprintf(stderr
, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2572 screen
->unmanageWindow(this, False
);
2576 void BlackboxWindow::reparentNotifyEvent(const XReparentEvent
*re
) {
2577 if (re
->window
!= client
.window
|| re
->parent
== frame
.plate
)
2581 fprintf(stderr
, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2582 "0x%lx.\n", client
.window
, re
->parent
);
2587 XPutBackEvent(blackbox
->getXDisplay(), &ev
);
2588 screen
->unmanageWindow(this, True
);
2592 void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent
*pe
) {
2593 if (pe
->state
== PropertyDelete
)
2597 fprintf(stderr
, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n",
2603 case XA_WM_CLIENT_MACHINE
:
2607 case XA_WM_TRANSIENT_FOR
: {
2608 // determine if this is a transient window
2611 // adjust the window decorations based on transience
2612 if (isTransient()) {
2613 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2614 functions
&= ~Func_Maximize
;
2615 setAllowedActions();
2626 case XA_WM_ICON_NAME
:
2628 if (flags
.iconic
) screen
->propagateWindowName(this);
2631 case XAtom::net_wm_name
:
2635 if (decorations
& Decor_Titlebar
)
2638 screen
->propagateWindowName(this);
2641 case XA_WM_NORMAL_HINTS
: {
2644 if ((client
.normal_hint_flags
& PMinSize
) &&
2645 (client
.normal_hint_flags
& PMaxSize
)) {
2646 // the window now can/can't resize itself, so the buttons need to be
2649 if (client
.max_width
<= client
.min_width
&&
2650 client
.max_height
<= client
.min_height
) {
2651 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2652 functions
&= ~(Func_Resize
| Func_Maximize
);
2654 if (! isTransient()) {
2655 decorations
|= Decor_Maximize
| Decor_Handle
;
2656 functions
|= Func_Maximize
;
2658 functions
|= Func_Resize
;
2661 setAllowedActions();
2664 Rect old_rect
= frame
.rect
;
2668 if (old_rect
!= frame
.rect
)
2675 if (pe
->atom
== xatom
->getAtom(XAtom::wm_protocols
)) {
2678 if ((decorations
& Decor_Close
) && (! frame
.close_button
)) {
2679 createCloseButton();
2680 if (decorations
& Decor_Titlebar
) {
2681 positionButtons(True
);
2682 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
2684 if (windowmenu
) windowmenu
->reconfigure();
2686 } else if (pe
->atom
== xatom
->getAtom(XAtom::net_wm_strut
)) {
2695 void BlackboxWindow::exposeEvent(const XExposeEvent
*ee
) {
2697 fprintf(stderr
, "BlackboxWindow::exposeEvent() for 0x%lx\n", client
.window
);
2700 if (frame
.label
== ee
->window
&& (decorations
& Decor_Titlebar
))
2702 else if (frame
.close_button
== ee
->window
)
2703 redrawCloseButton(False
);
2704 else if (frame
.maximize_button
== ee
->window
)
2705 redrawMaximizeButton(flags
.maximized
);
2706 else if (frame
.iconify_button
== ee
->window
)
2707 redrawIconifyButton(False
);
2711 void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent
*cr
) {
2712 if (cr
->window
!= client
.window
|| flags
.iconic
)
2715 if (cr
->value_mask
& CWBorderWidth
)
2716 client
.old_bw
= cr
->border_width
;
2718 if (cr
->value_mask
& (CWX
| CWY
| CWWidth
| CWHeight
)) {
2719 Rect req
= frame
.rect
;
2721 if (cr
->value_mask
& (CWX
| CWY
)) {
2722 if (cr
->value_mask
& CWX
)
2723 client
.rect
.setX(cr
->x
);
2724 if (cr
->value_mask
& CWY
)
2725 client
.rect
.setY(cr
->y
);
2730 if (cr
->value_mask
& CWWidth
)
2731 req
.setWidth(cr
->width
+ frame
.margin
.left
+ frame
.margin
.right
);
2733 if (cr
->value_mask
& CWHeight
)
2734 req
.setHeight(cr
->height
+ frame
.margin
.top
+ frame
.margin
.bottom
);
2736 configure(req
.x(), req
.y(), req
.width(), req
.height());
2739 if (cr
->value_mask
& CWStackMode
) {
2740 switch (cr
->detail
) {
2743 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2749 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2756 void BlackboxWindow::buttonPressEvent(const XButtonEvent
*be
) {
2758 fprintf(stderr
, "BlackboxWindow::buttonPressEvent() for 0x%lx\n",
2762 if (frame
.maximize_button
== be
->window
&& be
->button
<= 3) {
2763 redrawMaximizeButton(True
);
2764 } else if (be
->button
== 1 || (be
->button
== 3 && be
->state
== Mod1Mask
)) {
2765 if (! flags
.focused
)
2768 if (frame
.iconify_button
== be
->window
) {
2769 redrawIconifyButton(True
);
2770 } else if (frame
.close_button
== be
->window
) {
2771 redrawCloseButton(True
);
2772 } else if (frame
.plate
== be
->window
) {
2773 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2775 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2777 XAllowEvents(blackbox
->getXDisplay(), ReplayPointer
, be
->time
);
2779 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
2780 if (((be
->time
- lastButtonPressTime
) <=
2781 blackbox
->getDoubleClickInterval()) ||
2782 (be
->state
== ControlMask
)) {
2783 lastButtonPressTime
= 0;
2786 lastButtonPressTime
= be
->time
;
2790 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2792 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2794 } else if (be
->button
== 2 && (be
->window
!= frame
.iconify_button
) &&
2795 (be
->window
!= frame
.close_button
)) {
2796 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2797 } else if (windowmenu
&& be
->button
== 3 &&
2798 (frame
.title
== be
->window
|| frame
.label
== be
->window
||
2799 frame
.handle
== be
->window
|| frame
.window
== be
->window
)) {
2800 if (windowmenu
->isVisible()) {
2803 int mx
= be
->x_root
- windowmenu
->getWidth() / 2,
2804 my
= be
->y_root
- windowmenu
->getHeight() / 2;
2806 // snap the window menu into a corner/side if necessary
2807 int left_edge
, right_edge
, top_edge
, bottom_edge
;
2810 the " + (frame.border_w * 2) - 1" bits are to get the proper width
2811 and height of the menu, as the sizes returned by it do not include
2814 left_edge
= frame
.rect
.x();
2815 right_edge
= frame
.rect
.right() -
2816 (windowmenu
->getWidth() + (frame
.border_w
* 2) - 1);
2817 top_edge
= client
.rect
.top() - (frame
.border_w
+ frame
.mwm_border_w
);
2818 bottom_edge
= client
.rect
.bottom() -
2819 (windowmenu
->getHeight() + (frame
.border_w
* 2) - 1) +
2820 (frame
.border_w
+ frame
.mwm_border_w
);
2824 if (mx
> right_edge
)
2828 if (my
> bottom_edge
)
2831 windowmenu
->move(mx
, my
);
2833 XRaiseWindow(blackbox
->getXDisplay(), windowmenu
->getWindowID());
2834 XRaiseWindow(blackbox
->getXDisplay(),
2835 windowmenu
->getSendToMenu()->getWindowID());
2838 } else if (be
->button
== 4) {
2839 if ((be
->window
== frame
.label
||
2840 be
->window
== frame
.title
||
2841 be
->window
== frame
.maximize_button
||
2842 be
->window
== frame
.iconify_button
||
2843 be
->window
== frame
.close_button
) &&
2847 } else if (be
->button
== 5) {
2848 if ((be
->window
== frame
.label
||
2849 be
->window
== frame
.title
||
2850 be
->window
== frame
.maximize_button
||
2851 be
->window
== frame
.iconify_button
||
2852 be
->window
== frame
.close_button
) &&
2859 void BlackboxWindow::buttonReleaseEvent(const XButtonEvent
*re
) {
2861 fprintf(stderr
, "BlackboxWindow::buttonReleaseEvent() for 0x%lx\n",
2865 if (re
->window
== frame
.maximize_button
&&
2866 re
->button
>= 1 && re
->button
<= 3) {
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
))) {
2869 maximize(re
->button
);
2871 redrawMaximizeButton(flags
.maximized
);
2873 } else if (re
->window
== frame
.iconify_button
&& re
->button
== 1) {
2874 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2875 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2878 redrawIconifyButton(False
);
2880 } else if (re
->window
== frame
.close_button
& re
->button
== 1) {
2881 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2882 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
)))
2884 redrawCloseButton(False
);
2885 } else if (flags
.moving
) {
2887 } else if (flags
.resizing
) {
2889 } else if (re
->window
== frame
.window
) {
2890 if (re
->button
== 2 && re
->state
== Mod1Mask
)
2891 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
2897 void BlackboxWindow::beginMove(int x_root
, int y_root
) {
2898 assert(! (flags
.resizing
|| flags
.moving
));
2901 Only one window can be moved/resized at a time. If another window is already
2902 being moved or resized, then stop it before whating to work with this one.
2904 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
2905 if (changing
&& changing
!= this) {
2906 if (changing
->flags
.moving
)
2907 changing
->endMove();
2908 else // if (changing->flags.resizing)
2909 changing
->endResize();
2912 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
2913 PointerMotionMask
| ButtonReleaseMask
,
2914 GrabModeAsync
, GrabModeAsync
,
2915 None
, blackbox
->getMoveCursor(), CurrentTime
);
2917 if (windowmenu
&& windowmenu
->isVisible())
2920 flags
.moving
= True
;
2921 blackbox
->setChangingWindow(this);
2923 if (! screen
->doOpaqueMove()) {
2924 XGrabServer(blackbox
->getXDisplay());
2926 frame
.changing
= frame
.rect
;
2927 screen
->showPosition(frame
.changing
.x(), frame
.changing
.y());
2929 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2933 frame
.changing
.width() - 1,
2934 frame
.changing
.height() - 1);
2937 frame
.grab_x
= x_root
- frame
.rect
.x() - frame
.border_w
;
2938 frame
.grab_y
= y_root
- frame
.rect
.y() - frame
.border_w
;
2942 void BlackboxWindow::doMove(int x_root
, int y_root
) {
2943 assert(flags
.moving
);
2944 assert(blackbox
->getChangingWindow() == this);
2946 int dx
= x_root
- frame
.grab_x
, dy
= y_root
- frame
.grab_y
;
2947 dx
-= frame
.border_w
;
2948 dy
-= frame
.border_w
;
2950 const int snap_distance
= screen
->getEdgeSnapThreshold();
2952 if (snap_distance
) {
2954 const int wleft
= dx
,
2955 wright
= dx
+ frame
.rect
.width() - 1,
2957 wbottom
= dy
+ frame
.rect
.height() - 1;
2959 if (screen
->getWindowToWindowSnap()) {
2960 Workspace
*w
= screen
->getWorkspace(getWorkspaceNumber());
2963 // try snap to another window
2964 for (unsigned int i
= 0, c
= w
->getCount(); i
< c
; ++i
) {
2965 BlackboxWindow
*snapwin
= w
->getWindow(i
);
2966 if (snapwin
== this)
2967 continue; // don't snap to self
2969 bool snapped
= False
;
2971 const Rect
&winrect
= snapwin
->frameRect();
2972 int dleft
= std::abs(wright
- winrect
.left()),
2973 dright
= std::abs(wleft
- winrect
.right()),
2974 dtop
= std::abs(wbottom
- winrect
.top()),
2975 dbottom
= std::abs(wtop
- winrect
.bottom());
2977 if (wtop
>= (signed)(winrect
.y() - frame
.rect
.height() + 1) &&
2978 wtop
< (signed)(winrect
.y() + winrect
.height() - 1)) {
2980 // snap left of other window?
2981 if (dleft
< snap_distance
&& dleft
<= dright
) {
2982 dx
= winrect
.left() - frame
.rect
.width();
2985 // snap right of other window?
2986 else if (dright
< snap_distance
) {
2987 dx
= winrect
.right() + 1;
2992 if (screen
->getWindowCornerSnap()) {
2993 // try corner-snap to its other sides
2994 dtop
= std::abs(wtop
- winrect
.top());
2995 dbottom
= std::abs(wbottom
- winrect
.bottom());
2996 if (dtop
< snap_distance
&& dtop
<= dbottom
)
2998 else if (dbottom
< snap_distance
)
2999 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
3006 if (wleft
>= (signed)(winrect
.x() - frame
.rect
.width() + 1) &&
3007 wleft
< (signed)(winrect
.x() + winrect
.width() - 1)) {
3009 // snap top of other window?
3010 if (dtop
< snap_distance
&& dtop
<= dbottom
) {
3011 dy
= winrect
.top() - frame
.rect
.height();
3014 // snap bottom of other window?
3015 else if (dbottom
< snap_distance
) {
3016 dy
= winrect
.bottom() + 1;
3021 if (screen
->getWindowCornerSnap()) {
3022 // try corner-snap to its other sides
3023 dleft
= std::abs(wleft
- winrect
.left());
3024 dright
= std::abs(wright
- winrect
.right());
3025 if (dleft
< snap_distance
&& dleft
<= dright
)
3026 dx
= winrect
.left();
3027 else if (dright
< snap_distance
)
3028 dx
= winrect
.right() - frame
.rect
.width() + 1;
3037 // try snap to the screen's available area
3038 Rect srect
= screen
->availableArea();
3040 int dleft
= std::abs(wleft
- srect
.left()),
3041 dright
= std::abs(wright
- srect
.right()),
3042 dtop
= std::abs(wtop
- srect
.top()),
3043 dbottom
= std::abs(wbottom
- srect
.bottom());
3046 if (dleft
< snap_distance
&& dleft
<= dright
)
3049 else if (dright
< snap_distance
)
3050 dx
= srect
.right() - frame
.rect
.width() + 1;
3053 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3056 else if (dbottom
< snap_distance
)
3057 dy
= srect
.bottom() - frame
.rect
.height() + 1;
3059 srect
= screen
->getRect(); // now get the full screen
3061 dleft
= std::abs(wleft
- srect
.left()),
3062 dright
= std::abs(wright
- srect
.right()),
3063 dtop
= std::abs(wtop
- srect
.top()),
3064 dbottom
= std::abs(wbottom
- srect
.bottom());
3067 if (dleft
< snap_distance
&& dleft
<= dright
)
3070 else if (dright
< snap_distance
)
3071 dx
= srect
.right() - frame
.rect
.width() + 1;
3074 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3077 else if (dbottom
< snap_distance
)
3078 dy
= srect
.bottom() - frame
.rect
.height() + 1;
3081 if (screen
->doOpaqueMove()) {
3082 configure(dx
, dy
, frame
.rect
.width(), frame
.rect
.height());
3084 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3088 frame
.changing
.width() - 1,
3089 frame
.changing
.height() - 1);
3091 frame
.changing
.setPos(dx
, dy
);
3093 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3097 frame
.changing
.width() - 1,
3098 frame
.changing
.height() - 1);
3101 screen
->showPosition(dx
, dy
);
3105 void BlackboxWindow::endMove(void) {
3106 assert(flags
.moving
);
3107 assert(blackbox
->getChangingWindow() == this);
3109 flags
.moving
= False
;
3110 blackbox
->setChangingWindow(0);
3112 if (! screen
->doOpaqueMove()) {
3113 /* when drawing the rubber band, we need to make sure we only draw inside
3114 * the frame... frame.changing_* contain the new coords for the window,
3115 * so we need to subtract 1 from changing_w/changing_h every where we
3116 * draw the rubber band (for both moving and resizing)
3118 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3119 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3120 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3121 XUngrabServer(blackbox
->getXDisplay());
3123 configure(frame
.changing
.x(), frame
.changing
.y(),
3124 frame
.changing
.width(), frame
.changing
.height());
3126 configure(frame
.rect
.x(), frame
.rect
.y(),
3127 frame
.rect
.width(), frame
.rect
.height());
3129 screen
->hideGeometry();
3131 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3133 // if there are any left over motions from the move, drop them now
3134 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3136 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3141 void BlackboxWindow::beginResize(int x_root
, int y_root
, Corner dir
) {
3142 assert(! (flags
.resizing
|| flags
.moving
));
3145 Only one window can be moved/resized at a time. If another window is already
3146 being moved or resized, then stop it before whating to work with this one.
3148 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3149 if (changing
&& changing
!= this) {
3150 if (changing
->flags
.moving
)
3151 changing
->endMove();
3152 else // if (changing->flags.resizing)
3153 changing
->endResize();
3161 switch (resize_dir
) {
3164 cursor
= blackbox
->getLowerLeftAngleCursor();
3169 cursor
= blackbox
->getLowerRightAngleCursor();
3173 anchor
= BottomRight
;
3174 cursor
= blackbox
->getUpperLeftAngleCursor();
3178 anchor
= BottomLeft
;
3179 cursor
= blackbox
->getUpperRightAngleCursor();
3183 assert(false); // unhandled Corner
3184 return; // unreachable, for the compiler
3187 XGrabServer(blackbox
->getXDisplay());
3188 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3189 PointerMotionMask
| ButtonReleaseMask
,
3190 GrabModeAsync
, GrabModeAsync
, None
, cursor
, CurrentTime
);
3192 flags
.resizing
= True
;
3193 blackbox
->setChangingWindow(this);
3196 frame
.changing
= frame
.rect
;
3198 constrain(anchor
, &gw
, &gh
);
3200 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3201 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3202 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3204 screen
->showGeometry(gw
, gh
);
3206 frame
.grab_x
= x_root
;
3207 frame
.grab_y
= y_root
;
3211 void BlackboxWindow::doResize(int x_root
, int y_root
) {
3212 assert(flags
.resizing
);
3213 assert(blackbox
->getChangingWindow() == this);
3215 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3216 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3217 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3222 switch (resize_dir
) {
3225 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3226 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3230 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3231 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3234 anchor
= BottomRight
;
3235 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3236 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3239 anchor
= BottomLeft
;
3240 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3241 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3245 assert(false); // unhandled Corner
3246 return; // unreachable, for the compiler
3249 constrain(anchor
, &gw
, &gh
);
3251 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3252 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3253 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3255 screen
->showGeometry(gw
, gh
);
3259 void BlackboxWindow::endResize(void) {
3260 assert(flags
.resizing
);
3261 assert(blackbox
->getChangingWindow() == this);
3263 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3264 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3265 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3266 XUngrabServer(blackbox
->getXDisplay());
3268 // unset maximized state after resized when fully maximized
3269 if (flags
.maximized
== 1)
3272 flags
.resizing
= False
;
3273 blackbox
->setChangingWindow(0);
3275 configure(frame
.changing
.x(), frame
.changing
.y(),
3276 frame
.changing
.width(), frame
.changing
.height());
3277 screen
->hideGeometry();
3279 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3281 // if there are any left over motions from the resize, drop them now
3282 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3284 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3289 void BlackboxWindow::motionNotifyEvent(const XMotionEvent
*me
) {
3291 fprintf(stderr
, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n",
3296 doMove(me
->x_root
, me
->y_root
);
3297 } else if (flags
.resizing
) {
3298 doResize(me
->x_root
, me
->y_root
);
3300 if (!flags
.resizing
&& me
->state
& Button1Mask
&& (functions
& Func_Move
) &&
3301 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3302 frame
.handle
== me
->window
|| frame
.window
== me
->window
)) {
3303 beginMove(me
->x_root
, me
->y_root
);
3304 } else if ((functions
& Func_Resize
) &&
3305 (me
->state
& Button1Mask
&& (me
->window
== frame
.right_grip
||
3306 me
->window
== frame
.left_grip
)) ||
3307 (me
->state
& Button3Mask
&& me
->state
& Mod1Mask
&&
3308 me
->window
== frame
.window
)) {
3309 unsigned int zones
= screen
->getResizeZones();
3312 if (me
->window
== frame
.left_grip
) {
3313 corner
= BottomLeft
;
3314 } else if (me
->window
== frame
.right_grip
|| zones
== 1) {
3315 corner
= BottomRight
;
3318 bool left
= (me
->x_root
- frame
.rect
.x() <=
3319 static_cast<signed>(frame
.rect
.width() / 2));
3322 else // (zones == 4)
3323 top
= (me
->y_root
- frame
.rect
.y() <=
3324 static_cast<signed>(frame
.rect
.height() / 2));
3325 corner
= (top
? (left
? TopLeft
: TopRight
) :
3326 (left
? BottomLeft
: BottomRight
));
3329 beginResize(me
->x_root
, me
->y_root
, corner
);
3336 void BlackboxWindow::shapeEvent(XShapeEvent
*) {
3337 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
3344 bool BlackboxWindow::validateClient(void) const {
3345 XSync(blackbox
->getXDisplay(), False
);
3348 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3349 DestroyNotify
, &e
) ||
3350 XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3352 XPutBackEvent(blackbox
->getXDisplay(), &e
);
3361 void BlackboxWindow::restore(bool remap
) {
3362 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeDelete
);
3363 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
3364 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, NoEventMask
);
3366 // do not leave a shaded window as an icon unless it was an icon
3367 if (flags
.shaded
&& ! flags
.iconic
) setState(NormalState
);
3369 restoreGravity(client
.rect
);
3371 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
3372 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
3374 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, client
.old_bw
);
3377 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3378 ReparentNotify
, &ev
)) {
3381 // according to the ICCCM - if the client doesn't reparent to
3382 // root, then we have to do it for them
3383 XReparentWindow(blackbox
->getXDisplay(), client
.window
,
3384 screen
->getRootWindow(),
3385 client
.rect
.x(), client
.rect
.y());
3388 if (remap
) XMapWindow(blackbox
->getXDisplay(), client
.window
);
3392 // timer for autoraise
3393 void BlackboxWindow::timeout(void) {
3394 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3398 void BlackboxWindow::changeBlackboxHints(BlackboxHints
*net
) {
3399 if ((net
->flags
& AttribShaded
) &&
3400 ((blackbox_attrib
.attrib
& AttribShaded
) !=
3401 (net
->attrib
& AttribShaded
)))
3404 if (flags
.visible
&& // watch out for requests when we can not be seen
3405 (net
->flags
& (AttribMaxVert
| AttribMaxHoriz
)) &&
3406 ((blackbox_attrib
.attrib
& (AttribMaxVert
| AttribMaxHoriz
)) !=
3407 (net
->attrib
& (AttribMaxVert
| AttribMaxHoriz
)))) {
3408 if (flags
.maximized
) {
3413 if ((net
->flags
& AttribMaxHoriz
) && (net
->flags
& AttribMaxVert
))
3414 button
= ((net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0);
3415 else if (net
->flags
& AttribMaxVert
)
3416 button
= ((net
->attrib
& AttribMaxVert
) ? 2 : 0);
3417 else if (net
->flags
& AttribMaxHoriz
)
3418 button
= ((net
->attrib
& AttribMaxHoriz
) ? 3 : 0);
3424 if ((net
->flags
& AttribOmnipresent
) &&
3425 ((blackbox_attrib
.attrib
& AttribOmnipresent
) !=
3426 (net
->attrib
& AttribOmnipresent
)))
3429 if ((net
->flags
& AttribWorkspace
) &&
3430 (blackbox_attrib
.workspace
!= net
->workspace
)) {
3431 screen
->reassociateWindow(this, net
->workspace
, True
);
3433 if (screen
->getCurrentWorkspaceID() != net
->workspace
) {
3437 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3441 if (net
->flags
& AttribDecoration
) {
3442 switch (net
->decoration
) {
3444 // clear all decorations except close
3445 decorations
&= Decor_Close
;
3451 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Iconify
;
3453 decorations
= ((functions
& Func_Resize
) && !isTransient() ?
3454 decorations
| Decor_Handle
:
3455 decorations
&= ~Decor_Handle
);
3456 decorations
= (functions
& Func_Maximize
?
3457 decorations
| Decor_Maximize
:
3458 decorations
&= ~Decor_Maximize
);
3463 decorations
|= Decor_Titlebar
| Decor_Iconify
;
3464 decorations
&= ~(Decor_Border
| Decor_Handle
);
3466 decorations
= (functions
& Func_Maximize
?
3467 decorations
| Decor_Maximize
:
3468 decorations
&= ~Decor_Maximize
);
3473 decorations
|= Decor_Titlebar
;
3474 decorations
&= ~(Decor_Iconify
| Decor_Border
);
3476 decorations
= ((functions
& Func_Resize
) && !isTransient() ?
3477 decorations
| Decor_Handle
:
3478 decorations
&= ~Decor_Handle
);
3479 decorations
= (functions
& Func_Maximize
?
3480 decorations
| Decor_Maximize
:
3481 decorations
&= ~Decor_Maximize
);
3486 // we can not be shaded if we lack a titlebar
3487 if (flags
.shaded
&& ! (decorations
& Decor_Titlebar
))
3490 if (flags
.visible
&& frame
.window
) {
3491 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
3492 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
3496 setState(current_state
);
3502 * Set the sizes of all components of the window frame
3503 * (the window decorations).
3504 * These values are based upon the current style settings and the client
3505 * window's dimensions.
3507 void BlackboxWindow::upsize(void) {
3508 frame
.bevel_w
= screen
->getBevelWidth();
3510 if (decorations
& Decor_Border
) {
3511 frame
.border_w
= screen
->getBorderWidth();
3512 if (! isTransient())
3513 frame
.mwm_border_w
= screen
->getFrameWidth();
3515 frame
.mwm_border_w
= 0;
3517 frame
.mwm_border_w
= frame
.border_w
= 0;
3520 if (decorations
& Decor_Titlebar
) {
3521 // the height of the titlebar is based upon the height of the font being
3522 // used to display the window's title
3523 WindowStyle
*style
= screen
->getWindowStyle();
3524 frame
.title_h
= style
->font
->height() + (frame
.bevel_w
* 2) + 2;
3526 frame
.label_h
= frame
.title_h
- (frame
.bevel_w
* 2);
3527 frame
.button_w
= (frame
.label_h
- 2);
3529 // set the top frame margin
3530 frame
.margin
.top
= frame
.border_w
+ frame
.title_h
+
3531 frame
.border_w
+ frame
.mwm_border_w
;
3537 // set the top frame margin
3538 frame
.margin
.top
= frame
.border_w
+ frame
.mwm_border_w
;
3541 // set the left/right frame margin
3542 frame
.margin
.left
= frame
.margin
.right
= frame
.border_w
+ frame
.mwm_border_w
;
3544 if (decorations
& Decor_Handle
) {
3545 frame
.grip_w
= frame
.button_w
* 2;
3546 frame
.handle_h
= screen
->getHandleWidth();
3548 // set the bottom frame margin
3549 frame
.margin
.bottom
= frame
.border_w
+ frame
.handle_h
+
3550 frame
.border_w
+ frame
.mwm_border_w
;
3555 // set the bottom frame margin
3556 frame
.margin
.bottom
= frame
.border_w
+ frame
.mwm_border_w
;
3560 We first get the normal dimensions and use this to define the inside_w/h
3561 then we modify the height if shading is in effect.
3562 If the shade state is not considered then frame.rect gets reset to the
3563 normal window size on a reconfigure() call resulting in improper
3564 dimensions appearing in move/resize and other events.
3567 height
= client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
,
3568 width
= client
.rect
.width() + frame
.margin
.left
+ frame
.margin
.right
;
3570 frame
.inside_w
= width
- (frame
.border_w
* 2);
3571 frame
.inside_h
= height
- (frame
.border_w
* 2);
3574 height
= frame
.title_h
+ (frame
.border_w
* 2);
3575 frame
.rect
.setSize(width
, height
);
3580 * Calculate the size of the client window and constrain it to the
3581 * size specified by the size hints of the client window.
3583 * The logical width and height are placed into pw and ph, if they
3584 * are non-zero. Logical size refers to the users perception of
3585 * the window size (for example an xterm resizes in cells, not in pixels).
3587 * The physical geometry is placed into frame.changing_{x,y,width,height}.
3588 * Physical geometry refers to the geometry of the window in pixels.
3590 void BlackboxWindow::constrain(Corner anchor
, int *pw
, int *ph
) {
3591 // frame.changing represents the requested frame size, we need to
3592 // strip the frame margin off and constrain the client size
3593 frame
.changing
.setCoords(frame
.changing
.left() + frame
.margin
.left
,
3594 frame
.changing
.top() + frame
.margin
.top
,
3595 frame
.changing
.right() - frame
.margin
.right
,
3596 frame
.changing
.bottom() - frame
.margin
.bottom
);
3598 int dw
= frame
.changing
.width(), dh
= frame
.changing
.height(),
3599 base_width
= (client
.base_width
) ? client
.base_width
: client
.min_width
,
3600 base_height
= (client
.base_height
) ? client
.base_height
:
3604 if (dw
< static_cast<signed>(client
.min_width
)) dw
= client
.min_width
;
3605 if (dh
< static_cast<signed>(client
.min_height
)) dh
= client
.min_height
;
3606 if (dw
> static_cast<signed>(client
.max_width
)) dw
= client
.max_width
;
3607 if (dh
> static_cast<signed>(client
.max_height
)) dh
= client
.max_height
;
3610 dw
/= client
.width_inc
;
3612 dh
/= client
.height_inc
;
3615 if (client
.width_inc
== 1)
3616 *pw
= dw
+ base_width
;
3621 if (client
.height_inc
== 1)
3622 *ph
= dh
+ base_height
;
3627 dw
*= client
.width_inc
;
3629 dh
*= client
.height_inc
;
3632 frame
.changing
.setSize(dw
, dh
);
3634 // add the frame margin back onto frame.changing
3635 frame
.changing
.setCoords(frame
.changing
.left() - frame
.margin
.left
,
3636 frame
.changing
.top() - frame
.margin
.top
,
3637 frame
.changing
.right() + frame
.margin
.right
,
3638 frame
.changing
.bottom() + frame
.margin
.bottom
);
3640 // move frame.changing to the specified anchor
3648 dx
= frame
.rect
.right() - frame
.changing
.right();
3652 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3656 dx
= frame
.rect
.right() - frame
.changing
.right();
3657 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3661 assert(false); // unhandled corner
3663 frame
.changing
.setPos(frame
.changing
.x() + dx
, frame
.changing
.y() + dy
);
3667 void WindowStyle::doJustify(const std::string
&text
, int &start_pos
,
3668 unsigned int max_length
,
3669 unsigned int modifier
) const {
3670 size_t text_len
= text
.size();
3671 unsigned int length
;
3674 length
= font
->measureString(string(text
, 0, text_len
)) + modifier
;
3675 } while (length
> max_length
&& text_len
-- > 0);
3679 start_pos
+= max_length
- length
;
3683 start_pos
+= (max_length
- length
) / 2;
3693 BWindowGroup::BWindowGroup(Blackbox
*b
, Window _group
)
3694 : blackbox(b
), group(_group
) {
3695 XWindowAttributes wattrib
;
3696 if (! XGetWindowAttributes(blackbox
->getXDisplay(), group
, &wattrib
)) {
3697 // group window doesn't seem to exist anymore
3702 XSelectInput(blackbox
->getXDisplay(), group
,
3703 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
3705 blackbox
->saveGroupSearch(group
, this);
3709 BWindowGroup::~BWindowGroup(void) {
3710 blackbox
->removeGroupSearch(group
);
3715 BWindowGroup::find(BScreen
*screen
, bool allow_transients
) const {
3716 BlackboxWindow
*ret
= blackbox
->getFocusedWindow();
3718 // does the focus window match (or any transient_fors)?
3720 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3721 if (ret
->isTransient() && allow_transients
) break;
3722 else if (! ret
->isTransient()) break;
3725 ret
= ret
->getTransientFor();
3728 if (ret
) return ret
;
3730 // the focus window didn't match, look in the group's window list
3731 BlackboxWindowList::const_iterator it
, end
= windowList
.end();
3732 for (it
= windowList
.begin(); it
!= end
; ++it
) {
3734 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3735 if (ret
->isTransient() && allow_transients
) break;
3736 else if (! ret
->isTransient()) break;