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
207 // docks (such as kicker) cannot be moved, and appear on all workspaces
208 functions
&= ~(Func_Move
);
213 // these windows have minimal decorations, only a titlebar, and cannot
214 // be resized or iconified
215 decorations
&= ~(Decor_Maximize
| Decor_Handle
| Decor_Border
|
217 functions
&= ~(Func_Resize
| Func_Maximize
| Func_Iconify
);
221 // splash screens have no functionality or decorations, they are left up
222 // to the application which created them
228 // dialogs cannot be maximized, and don't display a handle
229 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
230 functions
&= ~Func_Maximize
;
234 // normal windows retain all of the possible decorations and functionality
238 // further adjeust the window's decorations/behavior based on window sizes
239 if ((client
.normal_hint_flags
& PMinSize
) &&
240 (client
.normal_hint_flags
& PMaxSize
) &&
241 client
.max_width
<= client
.min_width
&&
242 client
.max_height
<= client
.min_height
) {
243 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
244 functions
&= ~(Func_Resize
| Func_Maximize
);
250 bool place_window
= True
;
251 if (blackbox
->isStartup() || isTransient() ||
252 client
.normal_hint_flags
& (PPosition
|USPosition
)) {
253 applyGravity(frame
.rect
);
255 if (blackbox
->isStartup() || client
.rect
.intersects(screen
->getRect()))
256 place_window
= False
;
259 // add the window's strut. note this is done *after* placing the window.
260 screen
->addStrut(&client
.strut
);
263 if (decorations
& Decor_Titlebar
)
266 if (decorations
& Decor_Handle
)
270 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
275 windowmenu
= new Windowmenu(this);
277 if (blackbox_attrib
.workspace
>= screen
->getWorkspaceCount())
278 screen
->getCurrentWorkspace()->addWindow(this, place_window
);
280 screen
->getWorkspace(blackbox_attrib
.workspace
)->
281 addWindow(this, place_window
);
283 if (! place_window
) {
284 // don't need to call configure if we are letting the workspace
286 configure(frame
.rect
.x(), frame
.rect
.y(),
287 frame
.rect
.width(), frame
.rect
.height());
290 // preserve the window's initial state on first map, and its current state
293 if (client
.wm_hint_flags
& StateHint
)
294 current_state
= client
.initial_state
;
296 current_state
= NormalState
;
299 // get sticky state from our parent window if we've got one
300 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
301 client
.transient_for
->isStuck() != flags
.stuck
)
305 flags
.shaded
= False
;
306 unsigned long orig_state
= current_state
;
310 At this point in the life of a window, current_state should only be set
311 to IconicState if the window was an *icon*, not if it was shaded.
313 if (orig_state
!= IconicState
)
314 current_state
= NormalState
;
322 if (flags
.maximized
&& (functions
& Func_Maximize
)) {
327 When the window is mapped (and also when its attributes are restored), the
328 current_state that was set here will be used.
329 It is set to Normal if the window is to be mapped or it is set to Iconic
330 if the window is to be iconified.
331 *Note* that for sticky windows, the same rules apply here, they are in
332 fact never set to Iconic since there is no way for us to tell if a sticky
333 window was iconified previously.
340 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
346 BlackboxWindow::~BlackboxWindow(void) {
348 fprintf(stderr
, "BlackboxWindow::~BlackboxWindow: destroying 0x%lx\n",
352 if (! timer
) // window not managed...
355 screen
->removeStrut(&client
.strut
);
356 screen
->updateAvailableArea();
358 // We don't need to worry about resizing because resizing always grabs the X
359 // server. This should only ever happen if using opaque moving.
367 if (client
.window_group
) {
368 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
369 if (group
) group
->removeWindow(this);
372 // remove ourselves from our transient_for
374 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
375 client
.transient_for
->client
.transientList
.remove(this);
377 client
.transient_for
= (BlackboxWindow
*) 0;
380 if (client
.transientList
.size() > 0) {
381 // reset transient_for for all transients
382 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
383 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
384 (*it
)->client
.transient_for
= (BlackboxWindow
*) 0;
395 blackbox
->removeWindowSearch(frame
.plate
);
396 XDestroyWindow(blackbox
->getXDisplay(), frame
.plate
);
400 blackbox
->removeWindowSearch(frame
.window
);
401 XDestroyWindow(blackbox
->getXDisplay(), frame
.window
);
404 blackbox
->removeWindowSearch(client
.window
);
409 * Creates a new top level window, with a given location, size, and border
411 * Returns: the newly created window
413 Window
BlackboxWindow::createToplevelWindow(void) {
414 XSetWindowAttributes attrib_create
;
415 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
| CWColormap
|
416 CWOverrideRedirect
| CWEventMask
;
418 attrib_create
.background_pixmap
= None
;
419 attrib_create
.colormap
= screen
->getColormap();
420 attrib_create
.override_redirect
= True
;
421 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
422 ButtonMotionMask
| EnterWindowMask
;
424 return XCreateWindow(blackbox
->getXDisplay(), screen
->getRootWindow(),
425 -1, -1, 1, 1, frame
.border_w
, screen
->getDepth(),
426 InputOutput
, screen
->getVisual(), create_mask
,
432 * Creates a child window, and optionally associates a given cursor with
435 Window
BlackboxWindow::createChildWindow(Window parent
, Cursor cursor
) {
436 XSetWindowAttributes attrib_create
;
437 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
|
440 attrib_create
.background_pixmap
= None
;
441 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
442 ButtonMotionMask
| ExposureMask
;
445 create_mask
|= CWCursor
;
446 attrib_create
.cursor
= cursor
;
449 return XCreateWindow(blackbox
->getXDisplay(), parent
, 0, 0, 1, 1, 0,
450 screen
->getDepth(), InputOutput
, screen
->getVisual(),
451 create_mask
, &attrib_create
);
455 void BlackboxWindow::associateClientWindow(void) {
456 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, 0);
460 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeInsert
);
462 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, SubstructureRedirectMask
);
464 XGrabServer(blackbox
->getXDisplay());
465 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
466 XReparentWindow(blackbox
->getXDisplay(), client
.window
, frame
.plate
, 0, 0);
467 XSelectInput(blackbox
->getXDisplay(), client
.window
,
468 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
469 XUngrabServer(blackbox
->getXDisplay());
471 XRaiseWindow(blackbox
->getXDisplay(), frame
.plate
);
472 XMapSubwindows(blackbox
->getXDisplay(), frame
.plate
);
476 if (blackbox
->hasShapeExtensions()) {
477 XShapeSelectInput(blackbox
->getXDisplay(), client
.window
,
484 XShapeQueryExtents(blackbox
->getXDisplay(), client
.window
, &shaped
,
485 &foo
, &foo
, &ufoo
, &ufoo
, &foo
, &foo
, &foo
,
487 flags
.shaped
= shaped
;
493 void BlackboxWindow::decorate(void) {
496 texture
= &(screen
->getWindowStyle()->b_focus
);
497 frame
.fbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
500 frame
.fbutton_pixel
= texture
->color().pixel();
502 texture
= &(screen
->getWindowStyle()->b_unfocus
);
503 frame
.ubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
506 frame
.ubutton_pixel
= texture
->color().pixel();
508 texture
= &(screen
->getWindowStyle()->b_pressed
);
509 frame
.pbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
512 frame
.pbutton_pixel
= texture
->color().pixel();
514 if (decorations
& Decor_Titlebar
) {
515 texture
= &(screen
->getWindowStyle()->t_focus
);
516 frame
.ftitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
519 frame
.ftitle_pixel
= texture
->color().pixel();
521 texture
= &(screen
->getWindowStyle()->t_unfocus
);
522 frame
.utitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
525 frame
.utitle_pixel
= texture
->color().pixel();
527 XSetWindowBorder(blackbox
->getXDisplay(), frame
.title
,
528 screen
->getBorderColor()->pixel());
533 if (decorations
& Decor_Border
) {
534 frame
.fborder_pixel
= screen
->getWindowStyle()->f_focus
.pixel();
535 frame
.uborder_pixel
= screen
->getWindowStyle()->f_unfocus
.pixel();
536 blackbox_attrib
.flags
|= AttribDecoration
;
537 blackbox_attrib
.decoration
= DecorNormal
;
539 blackbox_attrib
.flags
|= AttribDecoration
;
540 blackbox_attrib
.decoration
= DecorNone
;
543 if (decorations
& Decor_Handle
) {
544 texture
= &(screen
->getWindowStyle()->h_focus
);
545 frame
.fhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
548 frame
.fhandle_pixel
= texture
->color().pixel();
550 texture
= &(screen
->getWindowStyle()->h_unfocus
);
551 frame
.uhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
554 frame
.uhandle_pixel
= texture
->color().pixel();
556 texture
= &(screen
->getWindowStyle()->g_focus
);
557 frame
.fgrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.fgrip
);
559 frame
.fgrip_pixel
= texture
->color().pixel();
561 texture
= &(screen
->getWindowStyle()->g_unfocus
);
562 frame
.ugrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.ugrip
);
564 frame
.ugrip_pixel
= texture
->color().pixel();
566 XSetWindowBorder(blackbox
->getXDisplay(), frame
.handle
,
567 screen
->getBorderColor()->pixel());
568 XSetWindowBorder(blackbox
->getXDisplay(), frame
.left_grip
,
569 screen
->getBorderColor()->pixel());
570 XSetWindowBorder(blackbox
->getXDisplay(), frame
.right_grip
,
571 screen
->getBorderColor()->pixel());
574 XSetWindowBorder(blackbox
->getXDisplay(), frame
.window
,
575 screen
->getBorderColor()->pixel());
579 void BlackboxWindow::decorateLabel(void) {
582 texture
= &(screen
->getWindowStyle()->l_focus
);
583 frame
.flabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.flabel
);
585 frame
.flabel_pixel
= texture
->color().pixel();
587 texture
= &(screen
->getWindowStyle()->l_unfocus
);
588 frame
.ulabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.ulabel
);
590 frame
.ulabel_pixel
= texture
->color().pixel();
594 void BlackboxWindow::createHandle(void) {
595 frame
.handle
= createChildWindow(frame
.window
);
596 blackbox
->saveWindowSearch(frame
.handle
, this);
599 createChildWindow(frame
.handle
, blackbox
->getLowerLeftAngleCursor());
600 blackbox
->saveWindowSearch(frame
.left_grip
, this);
603 createChildWindow(frame
.handle
, blackbox
->getLowerRightAngleCursor());
604 blackbox
->saveWindowSearch(frame
.right_grip
, this);
608 void BlackboxWindow::destroyHandle(void) {
610 screen
->getImageControl()->removeImage(frame
.fhandle
);
613 screen
->getImageControl()->removeImage(frame
.uhandle
);
616 screen
->getImageControl()->removeImage(frame
.fgrip
);
619 screen
->getImageControl()->removeImage(frame
.ugrip
);
621 blackbox
->removeWindowSearch(frame
.left_grip
);
622 blackbox
->removeWindowSearch(frame
.right_grip
);
624 XDestroyWindow(blackbox
->getXDisplay(), frame
.left_grip
);
625 XDestroyWindow(blackbox
->getXDisplay(), frame
.right_grip
);
626 frame
.left_grip
= frame
.right_grip
= None
;
628 blackbox
->removeWindowSearch(frame
.handle
);
629 XDestroyWindow(blackbox
->getXDisplay(), frame
.handle
);
634 void BlackboxWindow::createTitlebar(void) {
635 frame
.title
= createChildWindow(frame
.window
);
636 frame
.label
= createChildWindow(frame
.title
);
637 blackbox
->saveWindowSearch(frame
.title
, this);
638 blackbox
->saveWindowSearch(frame
.label
, this);
640 if (decorations
& Decor_Iconify
) createIconifyButton();
641 if (decorations
& Decor_Maximize
) createMaximizeButton();
642 if (decorations
& Decor_Close
) createCloseButton();
646 void BlackboxWindow::destroyTitlebar(void) {
647 if (frame
.close_button
)
648 destroyCloseButton();
650 if (frame
.iconify_button
)
651 destroyIconifyButton();
653 if (frame
.maximize_button
)
654 destroyMaximizeButton();
657 screen
->getImageControl()->removeImage(frame
.ftitle
);
660 screen
->getImageControl()->removeImage(frame
.utitle
);
663 screen
->getImageControl()->removeImage(frame
.flabel
);
666 screen
->getImageControl()->removeImage(frame
.ulabel
);
669 screen
->getImageControl()->removeImage(frame
.fbutton
);
672 screen
->getImageControl()->removeImage(frame
.ubutton
);
675 screen
->getImageControl()->removeImage(frame
.pbutton
);
677 blackbox
->removeWindowSearch(frame
.title
);
678 blackbox
->removeWindowSearch(frame
.label
);
680 XDestroyWindow(blackbox
->getXDisplay(), frame
.label
);
681 XDestroyWindow(blackbox
->getXDisplay(), frame
.title
);
682 frame
.title
= frame
.label
= None
;
686 void BlackboxWindow::createCloseButton(void) {
687 if (frame
.title
!= None
) {
688 frame
.close_button
= createChildWindow(frame
.title
);
689 blackbox
->saveWindowSearch(frame
.close_button
, this);
694 void BlackboxWindow::destroyCloseButton(void) {
695 blackbox
->removeWindowSearch(frame
.close_button
);
696 XDestroyWindow(blackbox
->getXDisplay(), frame
.close_button
);
697 frame
.close_button
= None
;
701 void BlackboxWindow::createIconifyButton(void) {
702 if (frame
.title
!= None
) {
703 frame
.iconify_button
= createChildWindow(frame
.title
);
704 blackbox
->saveWindowSearch(frame
.iconify_button
, this);
709 void BlackboxWindow::destroyIconifyButton(void) {
710 blackbox
->removeWindowSearch(frame
.iconify_button
);
711 XDestroyWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
712 frame
.iconify_button
= None
;
716 void BlackboxWindow::createMaximizeButton(void) {
717 if (frame
.title
!= None
) {
718 frame
.maximize_button
= createChildWindow(frame
.title
);
719 blackbox
->saveWindowSearch(frame
.maximize_button
, this);
724 void BlackboxWindow::destroyMaximizeButton(void) {
725 blackbox
->removeWindowSearch(frame
.maximize_button
);
726 XDestroyWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
727 frame
.maximize_button
= None
;
731 void BlackboxWindow::positionButtons(bool redecorate_label
) {
732 string layout
= blackbox
->getTitlebarLayout();
735 bool hasclose
, hasiconify
, hasmaximize
, haslabel
;
736 hasclose
= hasiconify
= hasmaximize
= haslabel
= false;
738 string::const_iterator it
, end
;
739 for (it
= layout
.begin(), end
= layout
.end(); it
!= end
; ++it
) {
742 if (! hasclose
&& (decorations
& Decor_Close
)) {
748 if (! hasiconify
&& (decorations
& Decor_Iconify
)) {
754 if (! hasmaximize
&& (decorations
& Decor_Maximize
)) {
766 if (! hasclose
&& frame
.close_button
)
767 destroyCloseButton();
768 if (! hasiconify
&& frame
.iconify_button
)
769 destroyIconifyButton();
770 if (! hasmaximize
&& frame
.maximize_button
)
771 destroyMaximizeButton();
773 parsed
+= 'L'; // require that the label be in the layout
775 const unsigned int bsep
= frame
.bevel_w
+ 1; // separation between elements
776 const unsigned int by
= frame
.bevel_w
+ 1;
777 const unsigned int ty
= frame
.bevel_w
;
779 frame
.label_w
= frame
.inside_w
- bsep
* 2 -
780 (frame
.button_w
+ bsep
) * (parsed
.size() - 1);
782 unsigned int x
= bsep
;
783 for (it
= parsed
.begin(), end
= parsed
.end(); it
!= end
; ++it
) {
786 if (! frame
.close_button
) createCloseButton();
787 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.close_button
, x
, by
,
788 frame
.button_w
, frame
.button_w
);
789 x
+= frame
.button_w
+ bsep
;
792 if (! frame
.iconify_button
) createIconifyButton();
793 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.iconify_button
, x
, by
,
794 frame
.button_w
, frame
.button_w
);
795 x
+= frame
.button_w
+ bsep
;
798 if (! frame
.maximize_button
) createMaximizeButton();
799 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.maximize_button
, x
, by
,
800 frame
.button_w
, frame
.button_w
);
801 x
+= frame
.button_w
+ bsep
;
804 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.label
, x
, ty
,
805 frame
.label_w
, frame
.label_h
);
806 x
+= frame
.label_w
+ bsep
;
811 if (redecorate_label
) decorateLabel();
817 void BlackboxWindow::reconfigure(void) {
818 restoreGravity(client
.rect
);
820 applyGravity(frame
.rect
);
829 windowmenu
->move(windowmenu
->getX(), frame
.rect
.y() + frame
.title_h
);
830 windowmenu
->reconfigure();
835 void BlackboxWindow::grabButtons(void) {
836 if ((! screen
->isSloppyFocus()) || screen
->doClickRaise())
837 // grab button 1 for changing focus/raising
838 blackbox
->grabButton(Button1
, 0, frame
.plate
, True
, ButtonPressMask
,
839 GrabModeSync
, GrabModeSync
, frame
.plate
, None
);
841 if (functions
& Func_Move
)
842 blackbox
->grabButton(Button1
, Mod1Mask
, frame
.window
, True
,
843 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
844 GrabModeAsync
, frame
.window
,
845 blackbox
->getMoveCursor());
846 if (functions
& Func_Resize
)
847 blackbox
->grabButton(Button3
, Mod1Mask
, frame
.window
, True
,
848 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
849 GrabModeAsync
, frame
.window
, None
);
850 // alt+middle lowers the window
851 blackbox
->grabButton(Button2
, Mod1Mask
, frame
.window
, True
,
852 ButtonReleaseMask
, GrabModeAsync
, GrabModeAsync
,
857 void BlackboxWindow::ungrabButtons(void) {
858 if ((! screen
->isSloppyFocus()) || screen
->doClickRaise())
859 blackbox
->ungrabButton(Button1
, 0, frame
.plate
);
861 blackbox
->ungrabButton(Button1
, Mod1Mask
, frame
.window
);
862 blackbox
->ungrabButton(Button2
, Mod1Mask
, frame
.window
);
863 blackbox
->ungrabButton(Button3
, Mod1Mask
, frame
.window
);
867 void BlackboxWindow::positionWindows(void) {
868 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.window
,
869 frame
.rect
.x(), frame
.rect
.y(), frame
.inside_w
,
870 (flags
.shaded
) ? frame
.title_h
: frame
.inside_h
);
871 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.window
,
873 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.plate
,
875 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.plate
,
876 frame
.margin
.left
- frame
.mwm_border_w
- frame
.border_w
,
877 frame
.margin
.top
- frame
.mwm_border_w
- frame
.border_w
,
878 client
.rect
.width(), client
.rect
.height());
879 XMoveResizeWindow(blackbox
->getXDisplay(), client
.window
,
880 0, 0, client
.rect
.width(), client
.rect
.height());
881 // ensure client.rect contains the real location
882 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
883 frame
.rect
.top() + frame
.margin
.top
);
885 if (decorations
& Decor_Titlebar
) {
886 if (frame
.title
== None
) createTitlebar();
888 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.title
,
890 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.title
, -frame
.border_w
,
891 -frame
.border_w
, frame
.inside_w
, frame
.title_h
);
894 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
895 XMapWindow(blackbox
->getXDisplay(), frame
.title
);
896 } else if (frame
.title
) {
899 if (decorations
& Decor_Handle
) {
900 if (frame
.handle
== None
) createHandle();
901 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.handle
,
903 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.left_grip
,
905 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.right_grip
,
908 // use client.rect here so the value is correct even if shaded
909 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.handle
,
911 client
.rect
.height() + frame
.margin
.top
+
912 frame
.mwm_border_w
- frame
.border_w
,
913 frame
.inside_w
, frame
.handle_h
);
914 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.left_grip
,
915 -frame
.border_w
, -frame
.border_w
,
916 frame
.grip_w
, frame
.handle_h
);
917 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.right_grip
,
918 frame
.inside_w
- frame
.grip_w
- frame
.border_w
,
919 -frame
.border_w
, frame
.grip_w
, frame
.handle_h
);
921 XMapSubwindows(blackbox
->getXDisplay(), frame
.handle
);
922 XMapWindow(blackbox
->getXDisplay(), frame
.handle
);
923 } else if (frame
.handle
) {
926 XSync(blackbox
->getXDisplay(), False
);
930 void BlackboxWindow::updateStrut(void) {
931 unsigned long num
= 4;
933 if (! xatom
->getValue(client
.window
, XAtom::net_wm_strut
, XAtom::cardinal
,
938 client
.strut
.left
= data
[0];
939 client
.strut
.right
= data
[1];
940 client
.strut
.top
= data
[2];
941 client
.strut
.bottom
= data
[3];
943 screen
->updateAvailableArea();
950 void BlackboxWindow::getWindowType(void) {
952 if (xatom
->getValue(client
.window
, XAtom::net_wm_window_type
, XAtom::atom
,
954 if (val
== xatom
->getAtom(XAtom::net_wm_window_type_desktop
))
955 window_type
= Type_Desktop
;
956 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_dock
))
957 window_type
= Type_Dock
;
958 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_toolbar
))
959 window_type
= Type_Toolbar
;
960 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_menu
))
961 window_type
= Type_Menu
;
962 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_utility
))
963 window_type
= Type_Utility
;
964 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_splash
))
965 window_type
= Type_Splash
;
966 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_dialog
))
967 window_type
= Type_Dialog
;
968 else //if (val[0] == xatom->getAtom(XAtom::net_wm_window_type_normal))
969 window_type
= Type_Normal
;
974 * the window type hint was not set, which means we either classify ourself
975 * as a normal window or a dialog, depending on if we are a transient.
978 window_type
= Type_Dialog
;
980 window_type
= Type_Normal
;
984 void BlackboxWindow::getWMName(void) {
985 if (xatom
->getValue(client
.window
, XAtom::net_wm_name
,
986 XAtom::utf8
, client
.title
) &&
987 !client
.title
.empty()) {
988 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
991 //fall through to using WM_NAME
992 if (xatom
->getValue(client
.window
, XAtom::wm_name
, XAtom::ansi
, client
.title
)
993 && !client
.title
.empty()) {
994 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
997 // fall back to an internal default
998 client
.title
= i18n(WindowSet
, WindowUnnamed
, "Unnamed");
999 xatom
->setValue(client
.window
, XAtom::net_wm_visible_name
, XAtom::utf8
,
1004 void BlackboxWindow::getWMIconName(void) {
1005 if (xatom
->getValue(client
.window
, XAtom::net_wm_icon_name
,
1006 XAtom::utf8
, client
.icon_title
) &&
1007 !client
.icon_title
.empty()) {
1008 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1011 //fall through to using WM_ICON_NAME
1012 if (xatom
->getValue(client
.window
, XAtom::wm_icon_name
, XAtom::ansi
,
1013 client
.icon_title
) &&
1014 !client
.icon_title
.empty()) {
1015 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1018 // fall back to using the main name
1019 client
.icon_title
= client
.title
;
1020 xatom
->setValue(client
.window
, XAtom::net_wm_visible_icon_name
, XAtom::utf8
,
1026 * Retrieve which WM Protocols are supported by the client window.
1027 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
1028 * window's decorations and allow the close behavior.
1029 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
1032 void BlackboxWindow::getWMProtocols(void) {
1036 if (XGetWMProtocols(blackbox
->getXDisplay(), client
.window
,
1037 &proto
, &num_return
)) {
1038 for (int i
= 0; i
< num_return
; ++i
) {
1039 if (proto
[i
] == xatom
->getAtom(XAtom::wm_delete_window
)) {
1040 decorations
|= Decor_Close
;
1041 functions
|= Func_Close
;
1042 } else if (proto
[i
] == xatom
->getAtom(XAtom::wm_take_focus
))
1043 flags
.send_focus_message
= True
;
1044 else if (proto
[i
] == xatom
->getAtom(XAtom::blackbox_structure_messages
))
1045 screen
->addNetizen(new Netizen(screen
, client
.window
));
1054 * Gets the value of the WM_HINTS property.
1055 * If the property is not set, then use a set of default values.
1057 void BlackboxWindow::getWMHints(void) {
1058 focus_mode
= F_Passive
;
1059 client
.initial_state
= NormalState
;
1061 // remove from current window group
1062 if (client
.window_group
) {
1063 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1064 if (group
) group
->removeWindow(this);
1066 client
.window_group
= None
;
1068 XWMHints
*wmhint
= XGetWMHints(blackbox
->getXDisplay(), client
.window
);
1073 if (wmhint
->flags
& InputHint
) {
1074 if (wmhint
->input
== True
) {
1075 if (flags
.send_focus_message
)
1076 focus_mode
= F_LocallyActive
;
1078 if (flags
.send_focus_message
)
1079 focus_mode
= F_GloballyActive
;
1081 focus_mode
= F_NoInput
;
1085 if (wmhint
->flags
& StateHint
)
1086 client
.initial_state
= wmhint
->initial_state
;
1088 if (wmhint
->flags
& WindowGroupHint
) {
1089 client
.window_group
= wmhint
->window_group
;
1091 // add window to the appropriate group
1092 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1093 if (! group
) // no group found, create it!
1094 group
= new BWindowGroup(blackbox
, client
.window_group
);
1095 group
->addWindow(this);
1098 client
.wm_hint_flags
= wmhint
->flags
;
1104 * Gets the value of the WM_NORMAL_HINTS property.
1105 * If the property is not set, then use a set of default values.
1107 void BlackboxWindow::getWMNormalHints(void) {
1109 XSizeHints sizehint
;
1111 client
.min_width
= client
.min_height
=
1112 client
.width_inc
= client
.height_inc
= 1;
1113 client
.base_width
= client
.base_height
= 0;
1114 client
.win_gravity
= NorthWestGravity
;
1116 client
.min_aspect_x
= client
.min_aspect_y
=
1117 client
.max_aspect_x
= client
.max_aspect_y
= 1;
1121 use the full screen, not the strut modified size. otherwise when the
1122 availableArea changes max_width/height will be incorrect and lead to odd
1125 const Rect
& screen_area
= screen
->getRect();
1126 client
.max_width
= screen_area
.width();
1127 client
.max_height
= screen_area
.height();
1129 if (! XGetWMNormalHints(blackbox
->getXDisplay(), client
.window
,
1130 &sizehint
, &icccm_mask
))
1133 client
.normal_hint_flags
= sizehint
.flags
;
1135 if (sizehint
.flags
& PMinSize
) {
1136 if (sizehint
.min_width
>= 0)
1137 client
.min_width
= sizehint
.min_width
;
1138 if (sizehint
.min_height
>= 0)
1139 client
.min_height
= sizehint
.min_height
;
1142 if (sizehint
.flags
& PMaxSize
) {
1143 if (sizehint
.max_width
> static_cast<signed>(client
.min_width
))
1144 client
.max_width
= sizehint
.max_width
;
1146 client
.max_width
= client
.min_width
;
1148 if (sizehint
.max_height
> static_cast<signed>(client
.min_height
))
1149 client
.max_height
= sizehint
.max_height
;
1151 client
.max_height
= client
.min_height
;
1154 if (sizehint
.flags
& PResizeInc
) {
1155 client
.width_inc
= sizehint
.width_inc
;
1156 client
.height_inc
= sizehint
.height_inc
;
1159 #if 0 // we do not support this at the moment
1160 if (sizehint
.flags
& PAspect
) {
1161 client
.min_aspect_x
= sizehint
.min_aspect
.x
;
1162 client
.min_aspect_y
= sizehint
.min_aspect
.y
;
1163 client
.max_aspect_x
= sizehint
.max_aspect
.x
;
1164 client
.max_aspect_y
= sizehint
.max_aspect
.y
;
1168 if (sizehint
.flags
& PBaseSize
) {
1169 client
.base_width
= sizehint
.base_width
;
1170 client
.base_height
= sizehint
.base_height
;
1173 if (sizehint
.flags
& PWinGravity
)
1174 client
.win_gravity
= sizehint
.win_gravity
;
1179 * Gets the NETWM hints for the class' contained window.
1181 void BlackboxWindow::getNetWMHints(void) {
1182 unsigned long workspace
;
1184 if (xatom
->getValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1186 if (workspace
== 0xffffffff)
1189 blackbox_attrib
.workspace
= workspace
;
1192 unsigned long *state
;
1193 unsigned long num
= (unsigned) -1;
1194 if (xatom
->getValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
1198 for (unsigned long i
= 0; i
< num
; ++i
) {
1199 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
))
1201 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_shaded
))
1202 flags
.shaded
= True
;
1203 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
))
1204 flags
.skip_taskbar
= True
;
1205 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_pager
))
1206 flags
.skip_pager
= True
;
1207 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_fullscreen
))
1208 flags
.fullscreen
= True
;
1209 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_hidden
))
1210 setState(IconicState
);
1211 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_vert
))
1213 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_horz
))
1217 flags
.maximized
= 1;
1219 flags
.maximized
= 2;
1221 flags
.maximized
= 3;
1229 * Gets the MWM hints for the class' contained window.
1230 * This is used while initializing the window to its first state, and not
1232 * Returns: true if the MWM hints are successfully retreived and applied;
1233 * false if they are not.
1235 void BlackboxWindow::getMWMHints(void) {
1239 num
= PropMwmHintsElements
;
1240 if (! xatom
->getValue(client
.window
, XAtom::motif_wm_hints
,
1241 XAtom::motif_wm_hints
, num
,
1242 (unsigned long **)&mwm_hint
))
1244 if (num
< PropMwmHintsElements
) {
1249 if (mwm_hint
->flags
& MwmHintsDecorations
) {
1250 if (mwm_hint
->decorations
& MwmDecorAll
) {
1251 decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
1252 Decor_Iconify
| Decor_Maximize
| Decor_Close
;
1256 if (mwm_hint
->decorations
& MwmDecorBorder
)
1257 decorations
|= Decor_Border
;
1258 if (mwm_hint
->decorations
& MwmDecorHandle
)
1259 decorations
|= Decor_Handle
;
1260 if (mwm_hint
->decorations
& MwmDecorTitle
)
1261 decorations
|= Decor_Titlebar
;
1262 if (mwm_hint
->decorations
& MwmDecorIconify
)
1263 decorations
|= Decor_Iconify
;
1264 if (mwm_hint
->decorations
& MwmDecorMaximize
)
1265 decorations
|= Decor_Maximize
;
1269 if (mwm_hint
->flags
& MwmHintsFunctions
) {
1270 if (mwm_hint
->functions
& MwmFuncAll
) {
1271 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
|
1276 if (mwm_hint
->functions
& MwmFuncResize
)
1277 functions
|= Func_Resize
;
1278 if (mwm_hint
->functions
& MwmFuncMove
)
1279 functions
|= Func_Move
;
1280 if (mwm_hint
->functions
& MwmFuncIconify
)
1281 functions
|= Func_Iconify
;
1282 if (mwm_hint
->functions
& MwmFuncMaximize
)
1283 functions
|= Func_Maximize
;
1284 if (mwm_hint
->functions
& MwmFuncClose
)
1285 functions
|= Func_Close
;
1293 * Gets the blackbox hints from the class' contained window.
1294 * This is used while initializing the window to its first state, and not
1296 * Returns: true if the hints are successfully retreived and applied; false if
1299 bool BlackboxWindow::getBlackboxHints(void) {
1301 BlackboxHints
*blackbox_hint
;
1303 num
= PropBlackboxHintsElements
;
1304 if (! xatom
->getValue(client
.window
, XAtom::blackbox_hints
,
1305 XAtom::blackbox_hints
, num
,
1306 (unsigned long **)&blackbox_hint
))
1308 if (num
< PropBlackboxHintsElements
) {
1309 delete [] blackbox_hint
;
1313 if (blackbox_hint
->flags
& AttribShaded
)
1314 flags
.shaded
= (blackbox_hint
->attrib
& AttribShaded
);
1316 if ((blackbox_hint
->flags
& AttribMaxHoriz
) &&
1317 (blackbox_hint
->flags
& AttribMaxVert
))
1318 flags
.maximized
= (blackbox_hint
->attrib
&
1319 (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1320 else if (blackbox_hint
->flags
& AttribMaxVert
)
1321 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxVert
) ? 2 : 0;
1322 else if (blackbox_hint
->flags
& AttribMaxHoriz
)
1323 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1325 if (blackbox_hint
->flags
& AttribOmnipresent
)
1326 flags
.stuck
= (blackbox_hint
->attrib
& AttribOmnipresent
);
1328 if (blackbox_hint
->flags
& AttribWorkspace
)
1329 blackbox_attrib
.workspace
= blackbox_hint
->workspace
;
1331 // if (blackbox_hint->flags & AttribStack)
1332 // don't yet have always on top/bottom for blackbox yet... working
1335 if (blackbox_hint
->flags
& AttribDecoration
) {
1336 switch (blackbox_hint
->decoration
) {
1338 // clear all decorations except close
1339 decorations
&= Decor_Close
;
1340 // clear all functions except close
1341 functions
&= Func_Close
;
1346 decorations
|= Decor_Titlebar
| Decor_Iconify
;
1347 decorations
&= ~(Decor_Border
| Decor_Handle
| Decor_Maximize
);
1348 functions
|= Func_Move
| Func_Iconify
;
1349 functions
&= ~(Func_Resize
| Func_Maximize
);
1354 decorations
|= Decor_Titlebar
;
1355 decorations
&= ~(Decor_Iconify
| Decor_Border
| Decor_Handle
);
1356 functions
|= Func_Move
;
1357 functions
&= ~(Func_Resize
| Func_Maximize
| Func_Iconify
);
1363 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Handle
|
1364 Decor_Iconify
| Decor_Maximize
;
1365 functions
|= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
1373 delete [] blackbox_hint
;
1379 void BlackboxWindow::getTransientInfo(void) {
1380 if (client
.transient_for
&&
1381 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1382 // the transient for hint was removed, so we need to tell our
1383 // previous transient_for that we are going away
1384 client
.transient_for
->client
.transientList
.remove(this);
1387 // we have no transient_for until we find a new one
1388 client
.transient_for
= 0;
1391 if (! XGetTransientForHint(blackbox
->getXDisplay(), client
.window
,
1393 // transient_for hint not set
1397 if (trans_for
== client
.window
) {
1398 // wierd client... treat this window as a normal window
1402 if (trans_for
== None
|| trans_for
== screen
->getRootWindow()) {
1403 // this is an undocumented interpretation of the ICCCM. a transient
1404 // associated with None/Root/itself is assumed to be a modal root
1405 // transient. we don't support the concept of a global transient,
1406 // so we just associate this transient with nothing, and perhaps
1407 // we will add support later for global modality.
1408 client
.transient_for
= (BlackboxWindow
*) ~0ul;
1413 client
.transient_for
= blackbox
->searchWindow(trans_for
);
1414 if (! client
.transient_for
&&
1415 client
.window_group
&& trans_for
== client
.window_group
) {
1416 // no direct transient_for, perhaps this is a group transient?
1417 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1418 if (group
) client
.transient_for
= group
->find(screen
);
1421 if (! client
.transient_for
|| client
.transient_for
== this) {
1422 // no transient_for found, or we have a wierd client that wants to be
1423 // a transient for itself, so we treat this window as a normal window
1424 client
.transient_for
= (BlackboxWindow
*) 0;
1428 // register ourselves with our new transient_for
1429 client
.transient_for
->client
.transientList
.push_back(this);
1430 flags
.stuck
= client
.transient_for
->flags
.stuck
;
1434 bool BlackboxWindow::isKDESystrayWindow(void) {
1436 if (xatom
->getValue(client
.window
, XAtom::kde_net_wm_system_tray_window_for
,
1437 XAtom::window
, systray
) && systray
)
1443 BlackboxWindow
*BlackboxWindow::getTransientFor(void) const {
1444 if (client
.transient_for
&&
1445 client
.transient_for
!= (BlackboxWindow
*) ~0ul)
1446 return client
.transient_for
;
1452 * This function is responsible for updating both the client and the frame
1454 * According to the ICCCM a client message is not sent for a resize, only a
1457 void BlackboxWindow::configure(int dx
, int dy
,
1458 unsigned int dw
, unsigned int dh
) {
1459 bool send_event
= ((frame
.rect
.x() != dx
|| frame
.rect
.y() != dy
) &&
1462 if (dw
!= frame
.rect
.width() || dh
!= frame
.rect
.height()) {
1463 frame
.rect
.setRect(dx
, dy
, dw
, dh
);
1464 frame
.inside_w
= frame
.rect
.width() - (frame
.border_w
* 2);
1465 frame
.inside_h
= frame
.rect
.height() - (frame
.border_w
* 2);
1467 if (frame
.rect
.right() <= 0 || frame
.rect
.bottom() <= 0)
1468 frame
.rect
.setPos(0, 0);
1470 client
.rect
.setCoords(frame
.rect
.left() + frame
.margin
.left
,
1471 frame
.rect
.top() + frame
.margin
.top
,
1472 frame
.rect
.right() - frame
.margin
.right
,
1473 frame
.rect
.bottom() - frame
.margin
.bottom
);
1476 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
1483 redrawWindowFrame();
1485 frame
.rect
.setPos(dx
, dy
);
1487 XMoveWindow(blackbox
->getXDisplay(), frame
.window
,
1488 frame
.rect
.x(), frame
.rect
.y());
1490 we may have been called just after an opaque window move, so even though
1491 the old coords match the new ones no ConfigureNotify has been sent yet.
1492 There are likely other times when this will be relevant as well.
1494 if (! flags
.moving
) send_event
= True
;
1498 // if moving, the update and event will occur when the move finishes
1499 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1500 frame
.rect
.top() + frame
.margin
.top
);
1503 event
.type
= ConfigureNotify
;
1505 event
.xconfigure
.display
= blackbox
->getXDisplay();
1506 event
.xconfigure
.event
= client
.window
;
1507 event
.xconfigure
.window
= client
.window
;
1508 event
.xconfigure
.x
= client
.rect
.x();
1509 event
.xconfigure
.y
= client
.rect
.y();
1510 event
.xconfigure
.width
= client
.rect
.width();
1511 event
.xconfigure
.height
= client
.rect
.height();
1512 event
.xconfigure
.border_width
= client
.old_bw
;
1513 event
.xconfigure
.above
= frame
.window
;
1514 event
.xconfigure
.override_redirect
= False
;
1516 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1517 StructureNotifyMask
, &event
);
1518 screen
->updateNetizenConfigNotify(&event
);
1519 XFlush(blackbox
->getXDisplay());
1525 void BlackboxWindow::configureShape(void) {
1526 XShapeCombineShape(blackbox
->getXDisplay(), frame
.window
, ShapeBounding
,
1527 frame
.margin
.left
- frame
.border_w
,
1528 frame
.margin
.top
- frame
.border_w
,
1529 client
.window
, ShapeBounding
, ShapeSet
);
1532 XRectangle xrect
[2];
1534 if (decorations
& Decor_Titlebar
) {
1535 xrect
[0].x
= xrect
[0].y
= -frame
.border_w
;
1536 xrect
[0].width
= frame
.rect
.width();
1537 xrect
[0].height
= frame
.title_h
+ (frame
.border_w
* 2);
1541 if (decorations
& Decor_Handle
) {
1542 xrect
[1].x
= -frame
.border_w
;
1543 xrect
[1].y
= frame
.rect
.height() - frame
.margin
.bottom
+
1544 frame
.mwm_border_w
- frame
.border_w
;
1545 xrect
[1].width
= frame
.rect
.width();
1546 xrect
[1].height
= frame
.handle_h
+ (frame
.border_w
* 2);
1550 XShapeCombineRectangles(blackbox
->getXDisplay(), frame
.window
,
1551 ShapeBounding
, 0, 0, xrect
, num
,
1552 ShapeUnion
, Unsorted
);
1557 bool BlackboxWindow::setInputFocus(void) {
1558 if (flags
.focused
) return True
;
1560 assert(! flags
.iconic
&&
1561 (flags
.stuck
|| // window must be on the current workspace or sticky
1562 blackbox_attrib
.workspace
== screen
->getCurrentWorkspaceID()));
1564 // if the window is not visible, mark the window as wanting focus rather
1565 // than give it focus.
1566 if (! flags
.visible
) {
1567 Workspace
*wkspc
= screen
->getWorkspace(blackbox_attrib
.workspace
);
1568 wkspc
->setLastFocusedWindow(this);
1572 if (! frame
.rect
.intersects(screen
->getRect())) {
1573 // client is outside the screen, move it to the center
1574 configure((screen
->getWidth() - frame
.rect
.width()) / 2,
1575 (screen
->getHeight() - frame
.rect
.height()) / 2,
1576 frame
.rect
.width(), frame
.rect
.height());
1579 if (client
.transientList
.size() > 0) {
1580 // transfer focus to any modal transients
1581 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1582 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1583 if ((*it
)->flags
.modal
) return (*it
)->setInputFocus();
1588 if (focus_mode
== F_LocallyActive
|| focus_mode
== F_Passive
) {
1589 XSetInputFocus(blackbox
->getXDisplay(), client
.window
,
1590 RevertToPointerRoot
, CurrentTime
);
1592 blackbox
->setFocusedWindow(this);
1594 /* we could set the focus to none, since the window doesn't accept focus,
1595 * but we shouldn't set focus to nothing since this would surely make
1601 if (flags
.send_focus_message
) {
1603 ce
.xclient
.type
= ClientMessage
;
1604 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1605 ce
.xclient
.display
= blackbox
->getXDisplay();
1606 ce
.xclient
.window
= client
.window
;
1607 ce
.xclient
.format
= 32;
1608 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_take_focus
);
1609 ce
.xclient
.data
.l
[1] = blackbox
->getLastTime();
1610 ce
.xclient
.data
.l
[2] = 0l;
1611 ce
.xclient
.data
.l
[3] = 0l;
1612 ce
.xclient
.data
.l
[4] = 0l;
1613 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1615 XFlush(blackbox
->getXDisplay());
1622 void BlackboxWindow::iconify(void) {
1623 if (flags
.iconic
) return;
1625 // We don't need to worry about resizing because resizing always grabs the X
1626 // server. This should only ever happen if using opaque moving.
1630 if (windowmenu
) windowmenu
->hide();
1633 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1634 * we need to clear the event mask on client.window for a split second.
1635 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1636 * split second, leaving us with a ghost window... so, we need to do this
1637 * while the X server is grabbed
1639 XGrabServer(blackbox
->getXDisplay());
1640 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
1641 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1642 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1643 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
1644 XUngrabServer(blackbox
->getXDisplay());
1646 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1647 flags
.visible
= False
;
1648 flags
.iconic
= True
;
1650 setState(IconicState
);
1652 screen
->getWorkspace(blackbox_attrib
.workspace
)->removeWindow(this);
1654 if (isTransient()) {
1655 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1656 ! client
.transient_for
->flags
.iconic
) {
1657 // iconify our transient_for
1658 client
.transient_for
->iconify();
1662 screen
->addIcon(this);
1664 if (client
.transientList
.size() > 0) {
1665 // iconify all transients
1666 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1667 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1668 if (! (*it
)->flags
.iconic
) (*it
)->iconify();
1671 screen
->updateStackingList();
1675 void BlackboxWindow::show(void) {
1676 flags
.visible
= True
;
1677 flags
.iconic
= False
;
1679 current_state
= (flags
.shaded
) ? IconicState
: NormalState
;
1680 setState(current_state
);
1682 XMapWindow(blackbox
->getXDisplay(), client
.window
);
1683 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
1684 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
1689 XTranslateCoordinates(blackbox
->getXDisplay(), client
.window
,
1690 screen
->getRootWindow(),
1691 0, 0, &real_x
, &real_y
, &child
);
1692 fprintf(stderr
, "%s -- assumed: (%d, %d), real: (%d, %d)\n", getTitle(),
1693 client
.rect
.left(), client
.rect
.top(), real_x
, real_y
);
1694 assert(client
.rect
.left() == real_x
&& client
.rect
.top() == real_y
);
1699 void BlackboxWindow::deiconify(bool reassoc
, bool raise
) {
1700 if (flags
.iconic
|| reassoc
)
1701 screen
->reassociateWindow(this, BSENTINEL
, False
);
1702 else if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID())
1707 // reassociate and deiconify all transients
1708 if (reassoc
&& client
.transientList
.size() > 0) {
1709 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1710 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1711 (*it
)->deiconify(True
, False
);
1716 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1720 void BlackboxWindow::close(void) {
1722 ce
.xclient
.type
= ClientMessage
;
1723 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1724 ce
.xclient
.display
= blackbox
->getXDisplay();
1725 ce
.xclient
.window
= client
.window
;
1726 ce
.xclient
.format
= 32;
1727 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_delete_window
);
1728 ce
.xclient
.data
.l
[1] = CurrentTime
;
1729 ce
.xclient
.data
.l
[2] = 0l;
1730 ce
.xclient
.data
.l
[3] = 0l;
1731 ce
.xclient
.data
.l
[4] = 0l;
1732 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
, NoEventMask
, &ce
);
1733 XFlush(blackbox
->getXDisplay());
1737 void BlackboxWindow::withdraw(void) {
1738 // We don't need to worry about resizing because resizing always grabs the X
1739 // server. This should only ever happen if using opaque moving.
1743 flags
.visible
= False
;
1744 flags
.iconic
= False
;
1746 setState(current_state
);
1748 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1750 XGrabServer(blackbox
->getXDisplay());
1752 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
1753 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1754 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1755 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
1757 XUngrabServer(blackbox
->getXDisplay());
1759 if (windowmenu
) windowmenu
->hide();
1763 void BlackboxWindow::maximize(unsigned int button
) {
1764 // We don't need to worry about resizing because resizing always grabs the X
1765 // server. This should only ever happen if using opaque moving.
1769 // handle case where menu is open then the max button is used instead
1770 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
1772 if (flags
.maximized
) {
1773 flags
.maximized
= 0;
1775 blackbox_attrib
.flags
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1776 blackbox_attrib
.attrib
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1779 when a resize finishes, maximize(0) is called to clear any maximization
1780 flags currently set. Otherwise it still thinks it is maximized.
1781 so we do not need to call configure() because resizing will handle it
1783 if (! flags
.resizing
)
1784 configure(blackbox_attrib
.premax_x
, blackbox_attrib
.premax_y
,
1785 blackbox_attrib
.premax_w
, blackbox_attrib
.premax_h
);
1787 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
1788 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
1790 redrawAllButtons(); // in case it is not called in configure()
1791 setState(current_state
);
1795 blackbox_attrib
.premax_x
= frame
.rect
.x();
1796 blackbox_attrib
.premax_y
= frame
.rect
.y();
1797 blackbox_attrib
.premax_w
= frame
.rect
.width();
1798 // use client.rect so that clients can be restored even if shaded
1799 blackbox_attrib
.premax_h
=
1800 client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
;
1802 const Rect
&screen_area
= screen
->availableArea();
1803 frame
.changing
= screen_area
;
1807 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1808 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1812 blackbox_attrib
.flags
|= AttribMaxVert
;
1813 blackbox_attrib
.attrib
|= AttribMaxVert
;
1815 frame
.changing
.setX(frame
.rect
.x());
1816 frame
.changing
.setWidth(frame
.rect
.width());
1820 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1821 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1823 frame
.changing
.setY(frame
.rect
.y());
1824 frame
.changing
.setHeight(frame
.rect
.height());
1831 blackbox_attrib
.flags
^= AttribShaded
;
1832 blackbox_attrib
.attrib
^= AttribShaded
;
1833 flags
.shaded
= False
;
1836 flags
.maximized
= button
;
1838 configure(frame
.changing
.x(), frame
.changing
.y(),
1839 frame
.changing
.width(), frame
.changing
.height());
1841 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1842 redrawAllButtons(); // in case it is not called in configure()
1843 setState(current_state
);
1847 // re-maximizes the window to take into account availableArea changes
1848 void BlackboxWindow::remaximize(void) {
1849 // save the original dimensions because maximize will wipe them out
1850 int premax_x
= blackbox_attrib
.premax_x
,
1851 premax_y
= blackbox_attrib
.premax_y
,
1852 premax_w
= blackbox_attrib
.premax_w
,
1853 premax_h
= blackbox_attrib
.premax_h
;
1855 unsigned int button
= flags
.maximized
;
1856 flags
.maximized
= 0; // trick maximize() into working
1859 // restore saved values
1860 blackbox_attrib
.premax_x
= premax_x
;
1861 blackbox_attrib
.premax_y
= premax_y
;
1862 blackbox_attrib
.premax_w
= premax_w
;
1863 blackbox_attrib
.premax_h
= premax_h
;
1867 void BlackboxWindow::setWorkspace(unsigned int n
) {
1868 blackbox_attrib
.flags
|= AttribWorkspace
;
1869 blackbox_attrib
.workspace
= n
;
1870 if (n
== BSENTINEL
) { // iconified window
1872 we set the workspace to 'all workspaces' so that taskbars will show the
1873 window. otherwise, it made uniconifying a window imposible without the
1874 blackbox workspace menu
1878 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
, n
);
1882 void BlackboxWindow::shade(void) {
1884 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1885 frame
.inside_w
, frame
.inside_h
);
1886 flags
.shaded
= False
;
1887 blackbox_attrib
.flags
^= AttribShaded
;
1888 blackbox_attrib
.attrib
^= AttribShaded
;
1890 setState(NormalState
);
1892 // set the frame rect to the normal size
1893 frame
.rect
.setHeight(client
.rect
.height() + frame
.margin
.top
+
1894 frame
.margin
.bottom
);
1896 if (! (decorations
& Decor_Titlebar
))
1897 return; // can't shade it without a titlebar!
1899 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1900 frame
.inside_w
, frame
.title_h
);
1901 flags
.shaded
= True
;
1902 blackbox_attrib
.flags
|= AttribShaded
;
1903 blackbox_attrib
.attrib
|= AttribShaded
;
1905 setState(IconicState
);
1907 // set the frame rect to the shaded size
1908 frame
.rect
.setHeight(frame
.title_h
+ (frame
.border_w
* 2));
1914 * (Un)Sticks a window and its relatives.
1916 void BlackboxWindow::stick(void) {
1918 blackbox_attrib
.flags
^= AttribOmnipresent
;
1919 blackbox_attrib
.attrib
^= AttribOmnipresent
;
1921 flags
.stuck
= False
;
1924 screen
->reassociateWindow(this, BSENTINEL
, True
);
1926 // temporary fix since sticky windows suck. set the hint to what we
1927 // actually hold in our data.
1928 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1929 blackbox_attrib
.workspace
);
1931 setState(current_state
);
1935 blackbox_attrib
.flags
|= AttribOmnipresent
;
1936 blackbox_attrib
.attrib
|= AttribOmnipresent
;
1938 // temporary fix since sticky windows suck. set the hint to a different
1939 // value than that contained in the class' data.
1940 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1943 setState(current_state
);
1946 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1947 client
.transient_for
->isStuck() != flags
.stuck
)
1948 client
.transient_for
->stick();
1949 // go down the chain
1950 BlackboxWindowList::iterator it
;
1951 const BlackboxWindowList::iterator end
= client
.transientList
.end();
1952 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1953 if ((*it
)->isStuck() != flags
.stuck
)
1958 void BlackboxWindow::redrawWindowFrame(void) const {
1959 if (decorations
& Decor_Titlebar
) {
1960 if (flags
.focused
) {
1962 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1963 frame
.title
, frame
.ftitle
);
1965 XSetWindowBackground(blackbox
->getXDisplay(),
1966 frame
.title
, frame
.ftitle_pixel
);
1969 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1970 frame
.title
, frame
.utitle
);
1972 XSetWindowBackground(blackbox
->getXDisplay(),
1973 frame
.title
, frame
.utitle_pixel
);
1975 XClearWindow(blackbox
->getXDisplay(), frame
.title
);
1981 if (decorations
& Decor_Handle
) {
1982 if (flags
.focused
) {
1984 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1985 frame
.handle
, frame
.fhandle
);
1987 XSetWindowBackground(blackbox
->getXDisplay(),
1988 frame
.handle
, frame
.fhandle_pixel
);
1991 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1992 frame
.left_grip
, frame
.fgrip
);
1993 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1994 frame
.right_grip
, frame
.fgrip
);
1996 XSetWindowBackground(blackbox
->getXDisplay(),
1997 frame
.left_grip
, frame
.fgrip_pixel
);
1998 XSetWindowBackground(blackbox
->getXDisplay(),
1999 frame
.right_grip
, frame
.fgrip_pixel
);
2003 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2004 frame
.handle
, frame
.uhandle
);
2006 XSetWindowBackground(blackbox
->getXDisplay(),
2007 frame
.handle
, frame
.uhandle_pixel
);
2010 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2011 frame
.left_grip
, frame
.ugrip
);
2012 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2013 frame
.right_grip
, frame
.ugrip
);
2015 XSetWindowBackground(blackbox
->getXDisplay(),
2016 frame
.left_grip
, frame
.ugrip_pixel
);
2017 XSetWindowBackground(blackbox
->getXDisplay(),
2018 frame
.right_grip
, frame
.ugrip_pixel
);
2021 XClearWindow(blackbox
->getXDisplay(), frame
.handle
);
2022 XClearWindow(blackbox
->getXDisplay(), frame
.left_grip
);
2023 XClearWindow(blackbox
->getXDisplay(), frame
.right_grip
);
2026 if (decorations
& Decor_Border
) {
2028 XSetWindowBorder(blackbox
->getXDisplay(),
2029 frame
.plate
, frame
.fborder_pixel
);
2031 XSetWindowBorder(blackbox
->getXDisplay(),
2032 frame
.plate
, frame
.uborder_pixel
);
2037 void BlackboxWindow::setFocusFlag(bool focus
) {
2038 // only focus a window if it is visible
2039 if (focus
&& !flags
.visible
)
2042 flags
.focused
= focus
;
2044 redrawWindowFrame();
2046 if (screen
->isSloppyFocus() && screen
->doAutoRaise()) {
2047 if (isFocused()) timer
->start();
2052 blackbox
->setFocusedWindow(this);
2056 void BlackboxWindow::installColormap(bool install
) {
2057 int i
= 0, ncmap
= 0;
2058 Colormap
*cmaps
= XListInstalledColormaps(blackbox
->getXDisplay(),
2059 client
.window
, &ncmap
);
2061 XWindowAttributes wattrib
;
2062 if (XGetWindowAttributes(blackbox
->getXDisplay(),
2063 client
.window
, &wattrib
)) {
2065 // install the window's colormap
2066 for (i
= 0; i
< ncmap
; i
++) {
2067 if (*(cmaps
+ i
) == wattrib
.colormap
)
2068 // this window is using an installed color map... do not install
2071 // otherwise, install the window's colormap
2073 XInstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2075 // uninstall the window's colormap
2076 for (i
= 0; i
< ncmap
; i
++) {
2077 if (*(cmaps
+ i
) == wattrib
.colormap
)
2078 // we found the colormap to uninstall
2079 XUninstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2089 void BlackboxWindow::setAllowedActions(void) {
2093 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_shade
);
2094 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_change_desktop
);
2095 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_close
);
2097 if (functions
& Func_Move
)
2098 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_move
);
2099 if (functions
& Func_Resize
)
2100 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_resize
);
2101 if (functions
& Func_Maximize
) {
2102 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_horz
);
2103 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_vert
);
2106 xatom
->setValue(client
.window
, XAtom::net_wm_allowed_actions
, XAtom::atom
,
2111 void BlackboxWindow::setState(unsigned long new_state
) {
2112 current_state
= new_state
;
2114 unsigned long state
[2];
2115 state
[0] = current_state
;
2117 xatom
->setValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
, state
, 2);
2119 xatom
->setValue(client
.window
, XAtom::blackbox_attributes
,
2120 XAtom::blackbox_attributes
, (unsigned long *)&blackbox_attrib
,
2121 PropBlackboxAttributesElements
);
2126 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_modal
);
2128 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_shaded
);
2130 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_hidden
);
2131 if (flags
.skip_taskbar
)
2132 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
);
2133 if (flags
.skip_pager
)
2134 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_pager
);
2135 if (flags
.fullscreen
)
2136 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_fullscreen
);
2137 if (flags
.maximized
== 1 || flags
.maximized
== 2)
2138 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_vert
);
2139 if (flags
.maximized
== 1 || flags
.maximized
== 3)
2140 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_horz
);
2141 xatom
->setValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
2146 bool BlackboxWindow::getState(void) {
2147 bool ret
= xatom
->getValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
,
2149 if (! ret
) current_state
= 0;
2154 void BlackboxWindow::restoreAttributes(void) {
2155 unsigned long num
= PropBlackboxAttributesElements
;
2156 BlackboxAttributes
*net
;
2157 if (! xatom
->getValue(client
.window
, XAtom::blackbox_attributes
,
2158 XAtom::blackbox_attributes
, num
,
2159 (unsigned long **)&net
))
2161 if (num
< PropBlackboxAttributesElements
) {
2166 if (net
->flags
& AttribShaded
&& net
->attrib
& AttribShaded
) {
2167 flags
.shaded
= False
;
2168 unsigned long orig_state
= current_state
;
2172 At this point in the life of a window, current_state should only be set
2173 to IconicState if the window was an *icon*, not if it was shaded.
2175 if (orig_state
!= IconicState
)
2176 current_state
= WithdrawnState
;
2179 if (net
->workspace
!= screen
->getCurrentWorkspaceID() &&
2180 net
->workspace
< screen
->getWorkspaceCount())
2181 screen
->reassociateWindow(this, net
->workspace
, True
);
2183 if ((blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID()) &&
2184 (blackbox_attrib
.workspace
< screen
->getWorkspaceCount())) {
2185 // set to WithdrawnState so it will be mapped on the new workspace
2186 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2187 } else if (current_state
== WithdrawnState
) {
2188 // the window is on this workspace and is Withdrawn, so it is waiting to
2190 current_state
= NormalState
;
2193 if (net
->flags
& AttribOmnipresent
&& net
->attrib
& AttribOmnipresent
) {
2194 flags
.stuck
= False
;
2197 // if the window was on another workspace, it was going to be hidden. this
2198 // specifies that the window should be mapped since it is sticky.
2199 if (current_state
== WithdrawnState
) current_state
= NormalState
;
2202 if (net
->flags
& AttribMaxHoriz
|| net
->flags
& AttribMaxVert
) {
2203 int x
= net
->premax_x
, y
= net
->premax_y
;
2204 unsigned int w
= net
->premax_w
, h
= net
->premax_h
;
2205 flags
.maximized
= 0;
2208 if ((net
->flags
& AttribMaxHoriz
) &&
2209 (net
->flags
& AttribMaxVert
))
2210 m
= (net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
2211 else if (net
->flags
& AttribMaxVert
)
2212 m
= (net
->attrib
& AttribMaxVert
) ? 2 : 0;
2213 else if (net
->flags
& AttribMaxHoriz
)
2214 m
= (net
->attrib
& AttribMaxHoriz
) ? 3 : 0;
2218 blackbox_attrib
.premax_x
= x
;
2219 blackbox_attrib
.premax_y
= y
;
2220 blackbox_attrib
.premax_w
= w
;
2221 blackbox_attrib
.premax_h
= h
;
2224 // with the state set it will then be the map event's job to read the
2225 // window's state and behave accordingly
2232 * Positions the Rect r according the the client window position and
2235 void BlackboxWindow::applyGravity(Rect
&r
) {
2236 // apply horizontal window gravity
2237 switch (client
.win_gravity
) {
2239 case NorthWestGravity
:
2240 case SouthWestGravity
:
2242 r
.setX(client
.rect
.x());
2248 r
.setX(client
.rect
.x() - (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2251 case NorthEastGravity
:
2252 case SouthEastGravity
:
2254 r
.setX(client
.rect
.x() - frame
.margin
.left
- frame
.margin
.right
+ 2);
2259 r
.setX(client
.rect
.x() - frame
.margin
.left
);
2263 // apply vertical window gravity
2264 switch (client
.win_gravity
) {
2266 case NorthWestGravity
:
2267 case NorthEastGravity
:
2269 r
.setY(client
.rect
.y());
2275 r
.setY(client
.rect
.y() - (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2278 case SouthWestGravity
:
2279 case SouthEastGravity
:
2281 r
.setY(client
.rect
.y() - frame
.margin
.top
- frame
.margin
.bottom
+ 2);
2286 r
.setY(client
.rect
.y() - frame
.margin
.top
);
2293 * The reverse of the applyGravity function.
2295 * Positions the Rect r according to the frame window position and
2298 void BlackboxWindow::restoreGravity(Rect
&r
) {
2299 // restore horizontal window gravity
2300 switch (client
.win_gravity
) {
2302 case NorthWestGravity
:
2303 case SouthWestGravity
:
2305 r
.setX(frame
.rect
.x());
2311 r
.setX(frame
.rect
.x() + (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2314 case NorthEastGravity
:
2315 case SouthEastGravity
:
2317 r
.setX(frame
.rect
.x() + frame
.margin
.left
+ frame
.margin
.right
- 2);
2322 r
.setX(frame
.rect
.x() + frame
.margin
.left
);
2326 // restore vertical window gravity
2327 switch (client
.win_gravity
) {
2329 case NorthWestGravity
:
2330 case NorthEastGravity
:
2332 r
.setY(frame
.rect
.y());
2338 r
.setY(frame
.rect
.y() + (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2341 case SouthWestGravity
:
2342 case SouthEastGravity
:
2344 r
.setY(frame
.rect
.y() + frame
.margin
.top
+ frame
.margin
.bottom
- 2);
2349 r
.setY(frame
.rect
.y() + frame
.margin
.top
);
2355 void BlackboxWindow::redrawLabel(void) const {
2356 if (flags
.focused
) {
2358 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2359 frame
.label
, frame
.flabel
);
2361 XSetWindowBackground(blackbox
->getXDisplay(),
2362 frame
.label
, frame
.flabel_pixel
);
2365 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2366 frame
.label
, frame
.ulabel
);
2368 XSetWindowBackground(blackbox
->getXDisplay(),
2369 frame
.label
, frame
.ulabel_pixel
);
2371 XClearWindow(blackbox
->getXDisplay(), frame
.label
);
2373 WindowStyle
*style
= screen
->getWindowStyle();
2375 int pos
= frame
.bevel_w
* 2;
2376 style
->doJustify(client
.title
.c_str(), pos
, frame
.label_w
, frame
.bevel_w
* 4);
2377 style
->font
->drawString(frame
.label
, pos
, 1,
2378 (flags
.focused
? style
->l_text_focus
:
2379 style
->l_text_unfocus
),
2384 void BlackboxWindow::redrawAllButtons(void) const {
2385 if (frame
.iconify_button
) redrawIconifyButton(False
);
2386 if (frame
.maximize_button
) redrawMaximizeButton(flags
.maximized
);
2387 if (frame
.close_button
) redrawCloseButton(False
);
2391 void BlackboxWindow::redrawIconifyButton(bool pressed
) const {
2393 if (flags
.focused
) {
2395 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2396 frame
.iconify_button
, frame
.fbutton
);
2398 XSetWindowBackground(blackbox
->getXDisplay(),
2399 frame
.iconify_button
, frame
.fbutton_pixel
);
2402 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2403 frame
.iconify_button
, frame
.ubutton
);
2405 XSetWindowBackground(blackbox
->getXDisplay(), frame
.iconify_button
,
2406 frame
.ubutton_pixel
);
2410 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2411 frame
.iconify_button
, frame
.pbutton
);
2413 XSetWindowBackground(blackbox
->getXDisplay(),
2414 frame
.iconify_button
, frame
.pbutton_pixel
);
2416 XClearWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
2418 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2419 screen
->getWindowStyle()->b_pic_unfocus
);
2420 XDrawRectangle(blackbox
->getXDisplay(), frame
.iconify_button
, pen
.gc(),
2421 2, (frame
.button_w
- 5), (frame
.button_w
- 5), 2);
2425 void BlackboxWindow::redrawMaximizeButton(bool pressed
) const {
2427 if (flags
.focused
) {
2429 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2430 frame
.maximize_button
, frame
.fbutton
);
2432 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2433 frame
.fbutton_pixel
);
2436 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2437 frame
.maximize_button
, frame
.ubutton
);
2439 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2440 frame
.ubutton_pixel
);
2444 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2445 frame
.maximize_button
, frame
.pbutton
);
2447 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2448 frame
.pbutton_pixel
);
2450 XClearWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
2452 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2453 screen
->getWindowStyle()->b_pic_unfocus
);
2454 XDrawRectangle(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2455 2, 2, (frame
.button_w
- 5), (frame
.button_w
- 5));
2456 XDrawLine(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2457 2, 3, (frame
.button_w
- 3), 3);
2461 void BlackboxWindow::redrawCloseButton(bool pressed
) const {
2463 if (flags
.focused
) {
2465 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2468 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2469 frame
.fbutton_pixel
);
2472 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2475 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2476 frame
.ubutton_pixel
);
2480 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2481 frame
.close_button
, frame
.pbutton
);
2483 XSetWindowBackground(blackbox
->getXDisplay(),
2484 frame
.close_button
, frame
.pbutton_pixel
);
2486 XClearWindow(blackbox
->getXDisplay(), frame
.close_button
);
2488 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2489 screen
->getWindowStyle()->b_pic_unfocus
);
2490 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2491 2, 2, (frame
.button_w
- 3), (frame
.button_w
- 3));
2492 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2493 2, (frame
.button_w
- 3), (frame
.button_w
- 3), 2);
2497 void BlackboxWindow::mapRequestEvent(const XMapRequestEvent
*re
) {
2498 if (re
->window
!= client
.window
)
2502 fprintf(stderr
, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2506 switch (current_state
) {
2511 case WithdrawnState
:
2520 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2521 if (! blackbox
->isStartup() && (isTransient() || screen
->doFocusNew())) {
2522 XSync(blackbox
->getXDisplay(), False
); // make sure the frame is mapped..
2530 void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent
*ue
) {
2531 if (ue
->window
!= client
.window
)
2535 fprintf(stderr
, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2539 screen
->unmanageWindow(this, False
);
2543 void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent
*de
) {
2544 if (de
->window
!= client
.window
)
2548 fprintf(stderr
, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2552 screen
->unmanageWindow(this, False
);
2556 void BlackboxWindow::reparentNotifyEvent(const XReparentEvent
*re
) {
2557 if (re
->window
!= client
.window
|| re
->parent
== frame
.plate
)
2561 fprintf(stderr
, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2562 "0x%lx.\n", client
.window
, re
->parent
);
2567 XPutBackEvent(blackbox
->getXDisplay(), &ev
);
2568 screen
->unmanageWindow(this, True
);
2572 void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent
*pe
) {
2573 if (pe
->state
== PropertyDelete
)
2577 fprintf(stderr
, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n",
2583 case XA_WM_CLIENT_MACHINE
:
2587 case XA_WM_TRANSIENT_FOR
: {
2588 // determine if this is a transient window
2591 // adjust the window decorations based on transience
2592 if (isTransient()) {
2593 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2594 functions
&= ~Func_Maximize
;
2595 setAllowedActions();
2606 case XA_WM_ICON_NAME
:
2608 if (flags
.iconic
) screen
->propagateWindowName(this);
2611 case XAtom::net_wm_name
:
2615 if (decorations
& Decor_Titlebar
)
2618 screen
->propagateWindowName(this);
2621 case XA_WM_NORMAL_HINTS
: {
2624 if ((client
.normal_hint_flags
& PMinSize
) &&
2625 (client
.normal_hint_flags
& PMaxSize
)) {
2626 // the window now can/can't resize itself, so the buttons need to be
2629 if (client
.max_width
<= client
.min_width
&&
2630 client
.max_height
<= client
.min_height
) {
2631 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2632 functions
&= ~(Func_Resize
| Func_Maximize
);
2634 if (! isTransient()) {
2635 decorations
|= Decor_Maximize
| Decor_Handle
;
2636 functions
|= Func_Maximize
;
2638 functions
|= Func_Resize
;
2641 setAllowedActions();
2644 Rect old_rect
= frame
.rect
;
2648 if (old_rect
!= frame
.rect
)
2655 if (pe
->atom
== xatom
->getAtom(XAtom::wm_protocols
)) {
2658 if ((decorations
& Decor_Close
) && (! frame
.close_button
)) {
2659 createCloseButton();
2660 if (decorations
& Decor_Titlebar
) {
2661 positionButtons(True
);
2662 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
2664 if (windowmenu
) windowmenu
->reconfigure();
2666 } else if (pe
->atom
== xatom
->getAtom(XAtom::net_wm_strut
)) {
2675 void BlackboxWindow::exposeEvent(const XExposeEvent
*ee
) {
2677 fprintf(stderr
, "BlackboxWindow::exposeEvent() for 0x%lx\n", client
.window
);
2680 if (frame
.label
== ee
->window
&& (decorations
& Decor_Titlebar
))
2682 else if (frame
.close_button
== ee
->window
)
2683 redrawCloseButton(False
);
2684 else if (frame
.maximize_button
== ee
->window
)
2685 redrawMaximizeButton(flags
.maximized
);
2686 else if (frame
.iconify_button
== ee
->window
)
2687 redrawIconifyButton(False
);
2691 void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent
*cr
) {
2692 if (cr
->window
!= client
.window
|| flags
.iconic
)
2695 if (cr
->value_mask
& CWBorderWidth
)
2696 client
.old_bw
= cr
->border_width
;
2698 if (cr
->value_mask
& (CWX
| CWY
| CWWidth
| CWHeight
)) {
2699 Rect req
= frame
.rect
;
2701 if (cr
->value_mask
& (CWX
| CWY
)) {
2702 if (cr
->value_mask
& CWX
)
2703 client
.rect
.setX(cr
->x
);
2704 if (cr
->value_mask
& CWY
)
2705 client
.rect
.setY(cr
->y
);
2710 if (cr
->value_mask
& CWWidth
)
2711 req
.setWidth(cr
->width
+ frame
.margin
.left
+ frame
.margin
.right
);
2713 if (cr
->value_mask
& CWHeight
)
2714 req
.setHeight(cr
->height
+ frame
.margin
.top
+ frame
.margin
.bottom
);
2716 configure(req
.x(), req
.y(), req
.width(), req
.height());
2719 if (cr
->value_mask
& CWStackMode
) {
2720 switch (cr
->detail
) {
2723 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2729 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2736 void BlackboxWindow::buttonPressEvent(const XButtonEvent
*be
) {
2738 fprintf(stderr
, "BlackboxWindow::buttonPressEvent() for 0x%lx\n",
2742 if (frame
.maximize_button
== be
->window
&& be
->button
<= 3) {
2743 redrawMaximizeButton(True
);
2744 } else if (be
->button
== 1 || (be
->button
== 3 && be
->state
== Mod1Mask
)) {
2745 if (! flags
.focused
)
2748 if (frame
.iconify_button
== be
->window
) {
2749 redrawIconifyButton(True
);
2750 } else if (frame
.close_button
== be
->window
) {
2751 redrawCloseButton(True
);
2752 } else if (frame
.plate
== be
->window
) {
2753 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2755 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2757 XAllowEvents(blackbox
->getXDisplay(), ReplayPointer
, be
->time
);
2759 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
2760 if (((be
->time
- lastButtonPressTime
) <=
2761 blackbox
->getDoubleClickInterval()) ||
2762 (be
->state
== ControlMask
)) {
2763 lastButtonPressTime
= 0;
2766 lastButtonPressTime
= be
->time
;
2770 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2772 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2774 } else if (be
->button
== 2 && (be
->window
!= frame
.iconify_button
) &&
2775 (be
->window
!= frame
.close_button
)) {
2776 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2777 } else if (windowmenu
&& be
->button
== 3 &&
2778 (frame
.title
== be
->window
|| frame
.label
== be
->window
||
2779 frame
.handle
== be
->window
|| frame
.window
== be
->window
)) {
2780 if (windowmenu
->isVisible()) {
2783 int mx
= be
->x_root
- windowmenu
->getWidth() / 2,
2784 my
= be
->y_root
- windowmenu
->getHeight() / 2;
2786 // snap the window menu into a corner/side if necessary
2787 int left_edge
, right_edge
, top_edge
, bottom_edge
;
2790 the " + (frame.border_w * 2) - 1" bits are to get the proper width
2791 and height of the menu, as the sizes returned by it do not include
2794 left_edge
= frame
.rect
.x();
2795 right_edge
= frame
.rect
.right() -
2796 (windowmenu
->getWidth() + (frame
.border_w
* 2) - 1);
2797 top_edge
= client
.rect
.top() - (frame
.border_w
+ frame
.mwm_border_w
);
2798 bottom_edge
= client
.rect
.bottom() -
2799 (windowmenu
->getHeight() + (frame
.border_w
* 2) - 1) +
2800 (frame
.border_w
+ frame
.mwm_border_w
);
2804 if (mx
> right_edge
)
2808 if (my
> bottom_edge
)
2811 windowmenu
->move(mx
, my
);
2813 XRaiseWindow(blackbox
->getXDisplay(), windowmenu
->getWindowID());
2814 XRaiseWindow(blackbox
->getXDisplay(),
2815 windowmenu
->getSendToMenu()->getWindowID());
2818 } else if (be
->button
== 4) {
2819 if ((be
->window
== frame
.label
||
2820 be
->window
== frame
.title
||
2821 be
->window
== frame
.maximize_button
||
2822 be
->window
== frame
.iconify_button
||
2823 be
->window
== frame
.close_button
) &&
2827 } else if (be
->button
== 5) {
2828 if ((be
->window
== frame
.label
||
2829 be
->window
== frame
.title
||
2830 be
->window
== frame
.maximize_button
||
2831 be
->window
== frame
.iconify_button
||
2832 be
->window
== frame
.close_button
) &&
2839 void BlackboxWindow::buttonReleaseEvent(const XButtonEvent
*re
) {
2841 fprintf(stderr
, "BlackboxWindow::buttonReleaseEvent() for 0x%lx\n",
2845 if (re
->window
== frame
.maximize_button
&&
2846 re
->button
>= 1 && re
->button
<= 3) {
2847 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2848 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2849 maximize(re
->button
);
2851 redrawMaximizeButton(flags
.maximized
);
2853 } else if (re
->window
== frame
.iconify_button
&& re
->button
== 1) {
2854 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2855 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2858 redrawIconifyButton(False
);
2860 } else if (re
->window
== frame
.close_button
& re
->button
== 1) {
2861 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2862 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
)))
2864 redrawCloseButton(False
);
2865 } else if (flags
.moving
) {
2867 } else if (flags
.resizing
) {
2869 } else if (re
->window
== frame
.window
) {
2870 if (re
->button
== 2 && re
->state
== Mod1Mask
)
2871 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
2877 void BlackboxWindow::beginMove(int x_root
, int y_root
) {
2878 assert(! (flags
.resizing
|| flags
.moving
));
2881 Only one window can be moved/resized at a time. If another window is already
2882 being moved or resized, then stop it before whating to work with this one.
2884 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
2885 if (changing
&& changing
!= this) {
2886 if (changing
->flags
.moving
)
2887 changing
->endMove();
2888 else // if (changing->flags.resizing)
2889 changing
->endResize();
2892 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
2893 PointerMotionMask
| ButtonReleaseMask
,
2894 GrabModeAsync
, GrabModeAsync
,
2895 None
, blackbox
->getMoveCursor(), CurrentTime
);
2897 if (windowmenu
&& windowmenu
->isVisible())
2900 flags
.moving
= True
;
2901 blackbox
->setChangingWindow(this);
2903 if (! screen
->doOpaqueMove()) {
2904 XGrabServer(blackbox
->getXDisplay());
2906 frame
.changing
= frame
.rect
;
2907 screen
->showPosition(frame
.changing
.x(), frame
.changing
.y());
2909 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2913 frame
.changing
.width() - 1,
2914 frame
.changing
.height() - 1);
2917 frame
.grab_x
= x_root
- frame
.rect
.x() - frame
.border_w
;
2918 frame
.grab_y
= y_root
- frame
.rect
.y() - frame
.border_w
;
2922 void BlackboxWindow::doMove(int x_root
, int y_root
) {
2923 assert(flags
.moving
);
2924 assert(blackbox
->getChangingWindow() == this);
2926 int dx
= x_root
- frame
.grab_x
, dy
= y_root
- frame
.grab_y
;
2927 dx
-= frame
.border_w
;
2928 dy
-= frame
.border_w
;
2930 const int snap_distance
= screen
->getEdgeSnapThreshold();
2932 if (snap_distance
) {
2934 const int wleft
= dx
,
2935 wright
= dx
+ frame
.rect
.width() - 1,
2937 wbottom
= dy
+ frame
.rect
.height() - 1;
2939 if (screen
->getWindowToWindowSnap()) {
2940 Workspace
*w
= screen
->getWorkspace(getWorkspaceNumber());
2943 // try snap to another window
2944 for (unsigned int i
= 0, c
= w
->getCount(); i
< c
; ++i
) {
2945 BlackboxWindow
*snapwin
= w
->getWindow(i
);
2946 if (snapwin
== this)
2947 continue; // don't snap to self
2949 bool snapped
= False
;
2951 const Rect
&winrect
= snapwin
->frameRect();
2952 int dleft
= std::abs(wright
- winrect
.left()),
2953 dright
= std::abs(wleft
- winrect
.right()),
2954 dtop
= std::abs(wbottom
- winrect
.top()),
2955 dbottom
= std::abs(wtop
- winrect
.bottom());
2957 if (wtop
>= (signed)(winrect
.y() - frame
.rect
.height() + 1) &&
2958 wtop
< (signed)(winrect
.y() + winrect
.height() - 1)) {
2960 // snap left of other window?
2961 if (dleft
< snap_distance
&& dleft
<= dright
) {
2962 dx
= winrect
.left() - frame
.rect
.width();
2965 // snap right of other window?
2966 else if (dright
< snap_distance
) {
2967 dx
= winrect
.right() + 1;
2972 if (screen
->getWindowCornerSnap()) {
2973 // try corner-snap to its other sides
2974 dtop
= std::abs(wtop
- winrect
.top());
2975 dbottom
= std::abs(wbottom
- winrect
.bottom());
2976 if (dtop
< snap_distance
&& dtop
<= dbottom
)
2978 else if (dbottom
< snap_distance
)
2979 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
2986 if (wleft
>= (signed)(winrect
.x() - frame
.rect
.width() + 1) &&
2987 wleft
< (signed)(winrect
.x() + winrect
.width() - 1)) {
2989 // snap top of other window?
2990 if (dtop
< snap_distance
&& dtop
<= dbottom
) {
2991 dy
= winrect
.top() - frame
.rect
.height();
2994 // snap bottom of other window?
2995 else if (dbottom
< snap_distance
) {
2996 dy
= winrect
.bottom() + 1;
3001 if (screen
->getWindowCornerSnap()) {
3002 // try corner-snap to its other sides
3003 dleft
= std::abs(wleft
- winrect
.left());
3004 dright
= std::abs(wright
- winrect
.right());
3005 if (dleft
< snap_distance
&& dleft
<= dright
)
3006 dx
= winrect
.left();
3007 else if (dright
< snap_distance
)
3008 dx
= winrect
.right() - frame
.rect
.width() + 1;
3017 // try snap to the screen's available area
3018 Rect srect
= screen
->availableArea();
3020 int dleft
= std::abs(wleft
- srect
.left()),
3021 dright
= std::abs(wright
- srect
.right()),
3022 dtop
= std::abs(wtop
- srect
.top()),
3023 dbottom
= std::abs(wbottom
- srect
.bottom());
3026 if (dleft
< snap_distance
&& dleft
<= dright
)
3029 else if (dright
< snap_distance
)
3030 dx
= srect
.right() - frame
.rect
.width() + 1;
3033 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3036 else if (dbottom
< snap_distance
)
3037 dy
= srect
.bottom() - frame
.rect
.height() + 1;
3039 srect
= screen
->getRect(); // now get the full screen
3041 dleft
= std::abs(wleft
- srect
.left()),
3042 dright
= std::abs(wright
- srect
.right()),
3043 dtop
= std::abs(wtop
- srect
.top()),
3044 dbottom
= std::abs(wbottom
- srect
.bottom());
3047 if (dleft
< snap_distance
&& dleft
<= dright
)
3050 else if (dright
< snap_distance
)
3051 dx
= srect
.right() - frame
.rect
.width() + 1;
3054 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3057 else if (dbottom
< snap_distance
)
3058 dy
= srect
.bottom() - frame
.rect
.height() + 1;
3061 if (screen
->doOpaqueMove()) {
3062 configure(dx
, dy
, frame
.rect
.width(), frame
.rect
.height());
3064 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3068 frame
.changing
.width() - 1,
3069 frame
.changing
.height() - 1);
3071 frame
.changing
.setPos(dx
, dy
);
3073 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3077 frame
.changing
.width() - 1,
3078 frame
.changing
.height() - 1);
3081 screen
->showPosition(dx
, dy
);
3085 void BlackboxWindow::endMove(void) {
3086 assert(flags
.moving
);
3087 assert(blackbox
->getChangingWindow() == this);
3089 flags
.moving
= False
;
3090 blackbox
->setChangingWindow(0);
3092 if (! screen
->doOpaqueMove()) {
3093 /* when drawing the rubber band, we need to make sure we only draw inside
3094 * the frame... frame.changing_* contain the new coords for the window,
3095 * so we need to subtract 1 from changing_w/changing_h every where we
3096 * draw the rubber band (for both moving and resizing)
3098 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3099 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3100 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3101 XUngrabServer(blackbox
->getXDisplay());
3103 configure(frame
.changing
.x(), frame
.changing
.y(),
3104 frame
.changing
.width(), frame
.changing
.height());
3106 configure(frame
.rect
.x(), frame
.rect
.y(),
3107 frame
.rect
.width(), frame
.rect
.height());
3109 screen
->hideGeometry();
3111 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3113 // if there are any left over motions from the move, drop them now
3114 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3116 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3121 void BlackboxWindow::beginResize(int x_root
, int y_root
, Corner dir
) {
3122 assert(! (flags
.resizing
|| flags
.moving
));
3125 Only one window can be moved/resized at a time. If another window is already
3126 being moved or resized, then stop it before whating to work with this one.
3128 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3129 if (changing
&& changing
!= this) {
3130 if (changing
->flags
.moving
)
3131 changing
->endMove();
3132 else // if (changing->flags.resizing)
3133 changing
->endResize();
3141 switch (resize_dir
) {
3144 cursor
= blackbox
->getLowerLeftAngleCursor();
3149 cursor
= blackbox
->getLowerRightAngleCursor();
3153 anchor
= BottomRight
;
3154 cursor
= blackbox
->getUpperLeftAngleCursor();
3158 anchor
= BottomLeft
;
3159 cursor
= blackbox
->getUpperRightAngleCursor();
3163 assert(false); // unhandled Corner
3164 return; // unreachable, for the compiler
3167 XGrabServer(blackbox
->getXDisplay());
3168 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3169 PointerMotionMask
| ButtonReleaseMask
,
3170 GrabModeAsync
, GrabModeAsync
, None
, cursor
, CurrentTime
);
3172 flags
.resizing
= True
;
3173 blackbox
->setChangingWindow(this);
3176 frame
.changing
= frame
.rect
;
3178 constrain(anchor
, &gw
, &gh
);
3180 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3181 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3182 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3184 screen
->showGeometry(gw
, gh
);
3186 frame
.grab_x
= x_root
;
3187 frame
.grab_y
= y_root
;
3191 void BlackboxWindow::doResize(int x_root
, int y_root
) {
3192 assert(flags
.resizing
);
3193 assert(blackbox
->getChangingWindow() == this);
3195 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3196 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3197 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3202 switch (resize_dir
) {
3205 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3206 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3210 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3211 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3214 anchor
= BottomRight
;
3215 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3216 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3219 anchor
= BottomLeft
;
3220 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3221 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3225 assert(false); // unhandled Corner
3226 return; // unreachable, for the compiler
3229 constrain(anchor
, &gw
, &gh
);
3231 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3232 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3233 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3235 screen
->showGeometry(gw
, gh
);
3239 void BlackboxWindow::endResize(void) {
3240 assert(flags
.resizing
);
3241 assert(blackbox
->getChangingWindow() == this);
3243 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3244 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3245 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3246 XUngrabServer(blackbox
->getXDisplay());
3248 // unset maximized state after resized when fully maximized
3249 if (flags
.maximized
== 1)
3252 flags
.resizing
= False
;
3253 blackbox
->setChangingWindow(0);
3255 configure(frame
.changing
.x(), frame
.changing
.y(),
3256 frame
.changing
.width(), frame
.changing
.height());
3257 screen
->hideGeometry();
3259 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3261 // if there are any left over motions from the resize, drop them now
3262 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3264 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3269 void BlackboxWindow::motionNotifyEvent(const XMotionEvent
*me
) {
3271 fprintf(stderr
, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n",
3276 doMove(me
->x_root
, me
->y_root
);
3277 } else if (flags
.resizing
) {
3278 doResize(me
->x_root
, me
->y_root
);
3280 if (!flags
.resizing
&& me
->state
& Button1Mask
&& (functions
& Func_Move
) &&
3281 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3282 frame
.handle
== me
->window
|| frame
.window
== me
->window
)) {
3283 beginMove(me
->x_root
, me
->y_root
);
3284 } else if ((functions
& Func_Resize
) &&
3285 (me
->state
& Button1Mask
&& (me
->window
== frame
.right_grip
||
3286 me
->window
== frame
.left_grip
)) ||
3287 (me
->state
& Button3Mask
&& me
->state
& Mod1Mask
&&
3288 me
->window
== frame
.window
)) {
3289 unsigned int zones
= screen
->getResizeZones();
3292 if (me
->window
== frame
.left_grip
) {
3293 corner
= BottomLeft
;
3294 } else if (me
->window
== frame
.right_grip
|| zones
== 1) {
3295 corner
= BottomRight
;
3298 bool left
= (me
->x_root
- frame
.rect
.x() <=
3299 static_cast<signed>(frame
.rect
.width() / 2));
3302 else // (zones == 4)
3303 top
= (me
->y_root
- frame
.rect
.y() <=
3304 static_cast<signed>(frame
.rect
.height() / 2));
3305 corner
= (top
? (left
? TopLeft
: TopRight
) :
3306 (left
? BottomLeft
: BottomRight
));
3309 beginResize(me
->x_root
, me
->y_root
, corner
);
3316 void BlackboxWindow::shapeEvent(XShapeEvent
*) {
3317 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
3324 bool BlackboxWindow::validateClient(void) const {
3325 XSync(blackbox
->getXDisplay(), False
);
3328 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3329 DestroyNotify
, &e
) ||
3330 XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3332 XPutBackEvent(blackbox
->getXDisplay(), &e
);
3341 void BlackboxWindow::restore(bool remap
) {
3342 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeDelete
);
3343 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
3344 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, NoEventMask
);
3346 // do not leave a shaded window as an icon unless it was an icon
3347 if (flags
.shaded
&& ! flags
.iconic
) setState(NormalState
);
3349 restoreGravity(client
.rect
);
3351 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
3352 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
3354 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, client
.old_bw
);
3357 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3358 ReparentNotify
, &ev
)) {
3361 // according to the ICCCM - if the client doesn't reparent to
3362 // root, then we have to do it for them
3363 XReparentWindow(blackbox
->getXDisplay(), client
.window
,
3364 screen
->getRootWindow(),
3365 client
.rect
.x(), client
.rect
.y());
3368 if (remap
) XMapWindow(blackbox
->getXDisplay(), client
.window
);
3372 // timer for autoraise
3373 void BlackboxWindow::timeout(void) {
3374 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3378 void BlackboxWindow::changeBlackboxHints(BlackboxHints
*net
) {
3379 if ((net
->flags
& AttribShaded
) &&
3380 ((blackbox_attrib
.attrib
& AttribShaded
) !=
3381 (net
->attrib
& AttribShaded
)))
3384 if (flags
.visible
&& // watch out for requests when we can not be seen
3385 (net
->flags
& (AttribMaxVert
| AttribMaxHoriz
)) &&
3386 ((blackbox_attrib
.attrib
& (AttribMaxVert
| AttribMaxHoriz
)) !=
3387 (net
->attrib
& (AttribMaxVert
| AttribMaxHoriz
)))) {
3388 if (flags
.maximized
) {
3393 if ((net
->flags
& AttribMaxHoriz
) && (net
->flags
& AttribMaxVert
))
3394 button
= ((net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0);
3395 else if (net
->flags
& AttribMaxVert
)
3396 button
= ((net
->attrib
& AttribMaxVert
) ? 2 : 0);
3397 else if (net
->flags
& AttribMaxHoriz
)
3398 button
= ((net
->attrib
& AttribMaxHoriz
) ? 3 : 0);
3404 if ((net
->flags
& AttribOmnipresent
) &&
3405 ((blackbox_attrib
.attrib
& AttribOmnipresent
) !=
3406 (net
->attrib
& AttribOmnipresent
)))
3409 if ((net
->flags
& AttribWorkspace
) &&
3410 (blackbox_attrib
.workspace
!= net
->workspace
)) {
3411 screen
->reassociateWindow(this, net
->workspace
, True
);
3413 if (screen
->getCurrentWorkspaceID() != net
->workspace
) {
3417 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3421 if (net
->flags
& AttribDecoration
) {
3422 switch (net
->decoration
) {
3424 // clear all decorations except close
3425 decorations
&= Decor_Close
;
3431 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Iconify
;
3433 decorations
= ((functions
& Func_Resize
) && !isTransient() ?
3434 decorations
| Decor_Handle
:
3435 decorations
&= ~Decor_Handle
);
3436 decorations
= (functions
& Func_Maximize
?
3437 decorations
| Decor_Maximize
:
3438 decorations
&= ~Decor_Maximize
);
3443 decorations
|= Decor_Titlebar
| Decor_Iconify
;
3444 decorations
&= ~(Decor_Border
| Decor_Handle
);
3446 decorations
= (functions
& Func_Maximize
?
3447 decorations
| Decor_Maximize
:
3448 decorations
&= ~Decor_Maximize
);
3453 decorations
|= Decor_Titlebar
;
3454 decorations
&= ~(Decor_Iconify
| Decor_Border
);
3456 decorations
= ((functions
& Func_Resize
) && !isTransient() ?
3457 decorations
| Decor_Handle
:
3458 decorations
&= ~Decor_Handle
);
3459 decorations
= (functions
& Func_Maximize
?
3460 decorations
| Decor_Maximize
:
3461 decorations
&= ~Decor_Maximize
);
3466 // we can not be shaded if we lack a titlebar
3467 if (flags
.shaded
&& ! (decorations
& Decor_Titlebar
))
3470 if (flags
.visible
&& frame
.window
) {
3471 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
3472 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
3476 setState(current_state
);
3482 * Set the sizes of all components of the window frame
3483 * (the window decorations).
3484 * These values are based upon the current style settings and the client
3485 * window's dimensions.
3487 void BlackboxWindow::upsize(void) {
3488 frame
.bevel_w
= screen
->getBevelWidth();
3490 if (decorations
& Decor_Border
) {
3491 frame
.border_w
= screen
->getBorderWidth();
3492 if (! isTransient())
3493 frame
.mwm_border_w
= screen
->getFrameWidth();
3495 frame
.mwm_border_w
= 0;
3497 frame
.mwm_border_w
= frame
.border_w
= 0;
3500 if (decorations
& Decor_Titlebar
) {
3501 // the height of the titlebar is based upon the height of the font being
3502 // used to display the window's title
3503 WindowStyle
*style
= screen
->getWindowStyle();
3504 frame
.title_h
= style
->font
->height() + (frame
.bevel_w
* 2) + 2;
3506 frame
.label_h
= frame
.title_h
- (frame
.bevel_w
* 2);
3507 frame
.button_w
= (frame
.label_h
- 2);
3509 // set the top frame margin
3510 frame
.margin
.top
= frame
.border_w
+ frame
.title_h
+
3511 frame
.border_w
+ frame
.mwm_border_w
;
3517 // set the top frame margin
3518 frame
.margin
.top
= frame
.border_w
+ frame
.mwm_border_w
;
3521 // set the left/right frame margin
3522 frame
.margin
.left
= frame
.margin
.right
= frame
.border_w
+ frame
.mwm_border_w
;
3524 if (decorations
& Decor_Handle
) {
3525 frame
.grip_w
= frame
.button_w
* 2;
3526 frame
.handle_h
= screen
->getHandleWidth();
3528 // set the bottom frame margin
3529 frame
.margin
.bottom
= frame
.border_w
+ frame
.handle_h
+
3530 frame
.border_w
+ frame
.mwm_border_w
;
3535 // set the bottom frame margin
3536 frame
.margin
.bottom
= frame
.border_w
+ frame
.mwm_border_w
;
3540 We first get the normal dimensions and use this to define the inside_w/h
3541 then we modify the height if shading is in effect.
3542 If the shade state is not considered then frame.rect gets reset to the
3543 normal window size on a reconfigure() call resulting in improper
3544 dimensions appearing in move/resize and other events.
3547 height
= client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
,
3548 width
= client
.rect
.width() + frame
.margin
.left
+ frame
.margin
.right
;
3550 frame
.inside_w
= width
- (frame
.border_w
* 2);
3551 frame
.inside_h
= height
- (frame
.border_w
* 2);
3554 height
= frame
.title_h
+ (frame
.border_w
* 2);
3555 frame
.rect
.setSize(width
, height
);
3560 * Calculate the size of the client window and constrain it to the
3561 * size specified by the size hints of the client window.
3563 * The logical width and height are placed into pw and ph, if they
3564 * are non-zero. Logical size refers to the users perception of
3565 * the window size (for example an xterm resizes in cells, not in pixels).
3567 * The physical geometry is placed into frame.changing_{x,y,width,height}.
3568 * Physical geometry refers to the geometry of the window in pixels.
3570 void BlackboxWindow::constrain(Corner anchor
, int *pw
, int *ph
) {
3571 // frame.changing represents the requested frame size, we need to
3572 // strip the frame margin off and constrain the client size
3573 frame
.changing
.setCoords(frame
.changing
.left() + frame
.margin
.left
,
3574 frame
.changing
.top() + frame
.margin
.top
,
3575 frame
.changing
.right() - frame
.margin
.right
,
3576 frame
.changing
.bottom() - frame
.margin
.bottom
);
3578 int dw
= frame
.changing
.width(), dh
= frame
.changing
.height(),
3579 base_width
= (client
.base_width
) ? client
.base_width
: client
.min_width
,
3580 base_height
= (client
.base_height
) ? client
.base_height
:
3584 if (dw
< static_cast<signed>(client
.min_width
)) dw
= client
.min_width
;
3585 if (dh
< static_cast<signed>(client
.min_height
)) dh
= client
.min_height
;
3586 if (dw
> static_cast<signed>(client
.max_width
)) dw
= client
.max_width
;
3587 if (dh
> static_cast<signed>(client
.max_height
)) dh
= client
.max_height
;
3590 dw
/= client
.width_inc
;
3592 dh
/= client
.height_inc
;
3595 if (client
.width_inc
== 1)
3596 *pw
= dw
+ base_width
;
3601 if (client
.height_inc
== 1)
3602 *ph
= dh
+ base_height
;
3607 dw
*= client
.width_inc
;
3609 dh
*= client
.height_inc
;
3612 frame
.changing
.setSize(dw
, dh
);
3614 // add the frame margin back onto frame.changing
3615 frame
.changing
.setCoords(frame
.changing
.left() - frame
.margin
.left
,
3616 frame
.changing
.top() - frame
.margin
.top
,
3617 frame
.changing
.right() + frame
.margin
.right
,
3618 frame
.changing
.bottom() + frame
.margin
.bottom
);
3620 // move frame.changing to the specified anchor
3628 dx
= frame
.rect
.right() - frame
.changing
.right();
3632 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3636 dx
= frame
.rect
.right() - frame
.changing
.right();
3637 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3641 assert(false); // unhandled corner
3643 frame
.changing
.setPos(frame
.changing
.x() + dx
, frame
.changing
.y() + dy
);
3647 void WindowStyle::doJustify(const std::string
&text
, int &start_pos
,
3648 unsigned int max_length
,
3649 unsigned int modifier
) const {
3650 size_t text_len
= text
.size();
3651 unsigned int length
;
3654 length
= font
->measureString(string(text
, 0, text_len
)) + modifier
;
3655 } while (length
> max_length
&& text_len
-- > 0);
3659 start_pos
+= max_length
- length
;
3663 start_pos
+= (max_length
- length
) / 2;
3673 BWindowGroup::BWindowGroup(Blackbox
*b
, Window _group
)
3674 : blackbox(b
), group(_group
) {
3675 XWindowAttributes wattrib
;
3676 if (! XGetWindowAttributes(blackbox
->getXDisplay(), group
, &wattrib
)) {
3677 // group window doesn't seem to exist anymore
3683 watch for destroy notify on the group window (in addition to
3684 any other events we are looking for)
3686 since some managed windows can also be window group controllers,
3687 we need to make sure that we don't clobber the event mask for the
3690 XSelectInput(blackbox
->getXDisplay(), group
,
3691 wattrib
.your_event_mask
| StructureNotifyMask
);
3693 blackbox
->saveGroupSearch(group
, this);
3697 BWindowGroup::~BWindowGroup(void) {
3698 blackbox
->removeGroupSearch(group
);
3703 BWindowGroup::find(BScreen
*screen
, bool allow_transients
) const {
3704 BlackboxWindow
*ret
= blackbox
->getFocusedWindow();
3706 // does the focus window match (or any transient_fors)?
3708 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3709 if (ret
->isTransient() && allow_transients
) break;
3710 else if (! ret
->isTransient()) break;
3713 ret
= ret
->getTransientFor();
3716 if (ret
) return ret
;
3718 // the focus window didn't match, look in the group's window list
3719 BlackboxWindowList::const_iterator it
, end
= windowList
.end();
3720 for (it
= windowList
.begin(); it
!= end
; ++it
) {
3722 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3723 if (ret
->isTransient() && allow_transients
) break;
3724 else if (! ret
->isTransient()) break;