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
44 #endif // HAVE_STDLIB_H
48 #include "blackbox.hh"
49 #include "Clientmenu.hh"
52 #include "Iconmenu.hh"
58 #include "Windowmenu.hh"
59 #include "Workspace.hh"
65 // change this to change what modifier keys openbox uses for mouse bindings
66 // for example: Mod1Mask | ControlMask
67 // or: ControlMask| ShiftMask
68 const unsigned int ModMask
= Mod1Mask
;
71 * Initializes the class with default values/the window's set initial values.
73 BlackboxWindow::BlackboxWindow(Blackbox
*b
, Window w
, BScreen
*s
) {
74 // fprintf(stderr, "BlackboxWindow size: %d bytes\n",
75 // sizeof(BlackboxWindow));
78 fprintf(stderr
, "BlackboxWindow::BlackboxWindow(): creating 0x%lx\n", w
);
82 set timer to zero... it is initialized properly later, so we check
83 if timer is zero in the destructor, and assume that the window is not
84 fully constructed if timer is zero...
90 xatom
= blackbox
->getXAtom();
92 if (! validateClient()) {
97 // fetch client size and placement
98 XWindowAttributes wattrib
;
99 if (! XGetWindowAttributes(blackbox
->getXDisplay(),
100 client
.window
, &wattrib
) ||
101 ! wattrib
.screen
|| wattrib
.override_redirect
) {
104 "BlackboxWindow::BlackboxWindow(): XGetWindowAttributes failed\n");
111 // set the eventmask early in the game so that we make sure we get
112 // all the events we are interested in
113 XSetWindowAttributes attrib_set
;
114 attrib_set
.event_mask
= PropertyChangeMask
| FocusChangeMask
|
116 attrib_set
.do_not_propagate_mask
= ButtonPressMask
| ButtonReleaseMask
|
118 XChangeWindowAttributes(blackbox
->getXDisplay(), client
.window
,
119 CWEventMask
|CWDontPropagate
, &attrib_set
);
121 flags
.moving
= flags
.resizing
= flags
.shaded
= flags
.visible
=
122 flags
.iconic
= flags
.focused
= flags
.stuck
= flags
.modal
=
123 flags
.send_focus_message
= flags
.shaped
= flags
.skip_taskbar
=
124 flags
.skip_pager
= flags
.fullscreen
= False
;
127 blackbox_attrib
.workspace
= window_number
= BSENTINEL
;
129 blackbox_attrib
.flags
= blackbox_attrib
.attrib
= blackbox_attrib
.stack
130 = blackbox_attrib
.decoration
= 0l;
131 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
132 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
135 frame
.window
= frame
.plate
= frame
.title
= frame
.handle
= None
;
136 frame
.close_button
= frame
.iconify_button
= frame
.maximize_button
= None
;
137 frame
.right_grip
= frame
.left_grip
= None
;
139 frame
.ulabel_pixel
= frame
.flabel_pixel
= frame
.utitle_pixel
=
140 frame
.ftitle_pixel
= frame
.uhandle_pixel
= frame
.fhandle_pixel
=
141 frame
.ubutton_pixel
= frame
.fbutton_pixel
= frame
.pbutton_pixel
=
142 frame
.uborder_pixel
= frame
.fborder_pixel
= frame
.ugrip_pixel
=
143 frame
.fgrip_pixel
= 0;
144 frame
.utitle
= frame
.ftitle
= frame
.uhandle
= frame
.fhandle
= None
;
145 frame
.ulabel
= frame
.flabel
= frame
.ubutton
= frame
.fbutton
= None
;
146 frame
.pbutton
= frame
.ugrip
= frame
.fgrip
= None
;
148 decorations
= Decor_Titlebar
| Decor_Border
| Decor_Handle
|
149 Decor_Iconify
| Decor_Maximize
;
150 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
152 client
.normal_hint_flags
= 0;
153 client
.window_group
= None
;
154 client
.transient_for
= 0;
156 current_state
= NormalState
;
159 get the initial size and location of client window (relative to the
160 _root window_). This position is the reference point used with the
161 window's gravity to find the window's initial position.
163 client
.rect
.setRect(wattrib
.x
, wattrib
.y
, wattrib
.width
, wattrib
.height
);
164 client
.old_bw
= wattrib
.border_width
;
166 lastButtonPressTime
= 0;
168 timer
= new BTimer(blackbox
, this);
169 timer
->setTimeout(blackbox
->getAutoRaiseDelay());
171 windowmenu
= new Windowmenu(this);
173 // get size, aspect, minimum/maximum size and other hints set by the
176 if (! getBlackboxHints()) {
185 frame
.window
= createToplevelWindow();
187 blackbox
->saveWindowSearch(frame
.window
, this);
189 frame
.plate
= createChildWindow(frame
.window
);
190 blackbox
->saveWindowSearch(frame
.plate
, 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
201 switch (window_type
) {
208 // none of these windows are decorated or manipulated by the window manager
211 blackbox_attrib
.workspace
= 0; // we do need to belong to a workspace
212 flags
.stuck
= True
; // we show up on all workspaces
216 // dialogs cannot be maximized, and don't display a handle
217 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
218 functions
&= ~Func_Maximize
;
222 // normal windows retain all of the possible decorations and functionality
228 // further adjeust the window's decorations/behavior based on window sizes
229 if ((client
.normal_hint_flags
& PMinSize
) &&
230 (client
.normal_hint_flags
& PMaxSize
) &&
231 client
.max_width
<= client
.min_width
&&
232 client
.max_height
<= client
.min_height
) {
233 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
234 functions
&= ~(Func_Resize
| Func_Maximize
);
237 if (decorations
& Decor_Titlebar
)
240 if (decorations
& Decor_Handle
)
243 // apply the size and gravity hint to the frame
247 bool place_window
= True
;
248 if (blackbox
->isStartup() || isTransient() ||
249 client
.normal_hint_flags
& (PPosition
|USPosition
)) {
250 applyGravity(frame
.rect
);
252 if (blackbox
->isStartup() || client
.rect
.intersects(screen
->getRect()))
253 place_window
= False
;
256 // add the window's strut. note this is done *after* placing the window.
257 screen
->addStrut(&client
.strut
);
261 if (blackbox
->hasShapeExtensions() && flags
.shaped
)
265 // get the window's title before adding it to the workspace
269 if (blackbox_attrib
.workspace
>= screen
->getWorkspaceCount())
270 screen
->getCurrentWorkspace()->addWindow(this, place_window
);
272 screen
->getWorkspace(blackbox_attrib
.workspace
)->
273 addWindow(this, place_window
);
276 the server needs to be grabbed here to prevent client's from sending
277 events while we are in the process of configuring their window.
278 We hold the grab until after we are done moving the window around.
281 XGrabServer(blackbox
->getXDisplay());
283 associateClientWindow();
285 blackbox
->saveWindowSearch(client
.window
, this);
287 if (! place_window
) {
288 // don't need to call configure if we are letting the workspace
290 configure(frame
.rect
.x(), frame
.rect
.y(),
291 frame
.rect
.width(), frame
.rect
.height());
297 XUngrabServer(blackbox
->getXDisplay());
299 // now that we know where to put the window and what it should look like
300 // we apply the decorations
305 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
307 // this ensures the title, buttons, and other decor are properly displayed
310 // preserve the window's initial state on first map, and its current state
312 unsigned long initial_state
= current_state
;
314 current_state
= initial_state
;
316 // get sticky state from our parent window if we've got one
317 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
318 client
.transient_for
->isStuck() != flags
.stuck
)
322 flags
.shaded
= False
;
323 initial_state
= current_state
;
327 At this point in the life of a window, current_state should only be set
328 to IconicState if the window was an *icon*, not if it was shaded.
330 if (initial_state
!= IconicState
)
331 current_state
= NormalState
;
339 if (flags
.maximized
&& (functions
& Func_Maximize
))
344 BlackboxWindow::~BlackboxWindow(void) {
346 fprintf(stderr
, "BlackboxWindow::~BlackboxWindow: destroying 0x%lx\n",
350 if (! timer
) // window not managed...
353 screen
->removeStrut(&client
.strut
);
354 screen
->updateAvailableArea();
356 // We don't need to worry about resizing because resizing always grabs the X
357 // server. This should only ever happen if using opaque moving.
365 if (client
.window_group
) {
366 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
367 if (group
) group
->removeWindow(this);
370 // remove ourselves from our transient_for
372 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
373 client
.transient_for
->client
.transientList
.remove(this);
375 client
.transient_for
= (BlackboxWindow
*) 0;
378 if (client
.transientList
.size() > 0) {
379 // reset transient_for for all transients
380 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
381 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
382 (*it
)->client
.transient_for
= (BlackboxWindow
*) 0;
393 blackbox
->removeWindowSearch(frame
.plate
);
394 XDestroyWindow(blackbox
->getXDisplay(), frame
.plate
);
398 blackbox
->removeWindowSearch(frame
.window
);
399 XDestroyWindow(blackbox
->getXDisplay(), frame
.window
);
402 blackbox
->removeWindowSearch(client
.window
);
407 * Creates a new top level window, with a given location, size, and border
409 * Returns: the newly created window
411 Window
BlackboxWindow::createToplevelWindow(void) {
412 XSetWindowAttributes attrib_create
;
413 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
| CWColormap
|
414 CWOverrideRedirect
| CWEventMask
;
416 attrib_create
.background_pixmap
= None
;
417 attrib_create
.colormap
= screen
->getColormap();
418 attrib_create
.override_redirect
= True
;
419 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
420 ButtonMotionMask
| EnterWindowMask
;
422 return XCreateWindow(blackbox
->getXDisplay(), screen
->getRootWindow(),
423 0, 0, 1, 1, frame
.border_w
, screen
->getDepth(),
424 InputOutput
, screen
->getVisual(), create_mask
,
430 * Creates a child window, and optionally associates a given cursor with
433 Window
BlackboxWindow::createChildWindow(Window parent
, Cursor cursor
) {
434 XSetWindowAttributes attrib_create
;
435 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
|
438 attrib_create
.background_pixmap
= None
;
439 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
440 ButtonMotionMask
| ExposureMask
;
443 create_mask
|= CWCursor
;
444 attrib_create
.cursor
= cursor
;
447 return XCreateWindow(blackbox
->getXDisplay(), parent
, 0, 0, 1, 1, 0,
448 screen
->getDepth(), InputOutput
, screen
->getVisual(),
449 create_mask
, &attrib_create
);
453 void BlackboxWindow::associateClientWindow(void) {
454 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, 0);
456 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeInsert
);
458 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, SubstructureRedirectMask
);
461 note we used to grab around this call to XReparentWindow however the
462 server is now grabbed before this method is called
464 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
466 XSelectInput(blackbox
->getXDisplay(), client
.window
,
467 event_mask
& ~StructureNotifyMask
);
468 XReparentWindow(blackbox
->getXDisplay(), client
.window
, frame
.plate
, 0, 0);
469 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
471 XRaiseWindow(blackbox
->getXDisplay(), frame
.plate
);
472 XMapSubwindows(blackbox
->getXDisplay(), frame
.plate
);
475 if (blackbox
->hasShapeExtensions()) {
476 XShapeSelectInput(blackbox
->getXDisplay(), client
.window
,
483 XShapeQueryExtents(blackbox
->getXDisplay(), client
.window
, &shaped
,
484 &foo
, &foo
, &ufoo
, &ufoo
, &foo
, &foo
, &foo
,
486 flags
.shaped
= shaped
;
492 void BlackboxWindow::decorate(void) {
495 texture
= &(screen
->getWindowStyle()->b_focus
);
496 frame
.fbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
499 frame
.fbutton_pixel
= texture
->color().pixel();
501 texture
= &(screen
->getWindowStyle()->b_unfocus
);
502 frame
.ubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
505 frame
.ubutton_pixel
= texture
->color().pixel();
507 texture
= &(screen
->getWindowStyle()->b_pressed
);
508 frame
.pbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
511 frame
.pbutton_pixel
= texture
->color().pixel();
513 if (decorations
& Decor_Titlebar
) {
514 texture
= &(screen
->getWindowStyle()->t_focus
);
515 frame
.ftitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
518 frame
.ftitle_pixel
= texture
->color().pixel();
520 texture
= &(screen
->getWindowStyle()->t_unfocus
);
521 frame
.utitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
524 frame
.utitle_pixel
= texture
->color().pixel();
526 XSetWindowBorder(blackbox
->getXDisplay(), frame
.title
,
527 screen
->getBorderColor()->pixel());
532 if (decorations
& Decor_Border
) {
533 frame
.fborder_pixel
= screen
->getWindowStyle()->f_focus
.pixel();
534 frame
.uborder_pixel
= screen
->getWindowStyle()->f_unfocus
.pixel();
535 blackbox_attrib
.flags
|= AttribDecoration
;
536 blackbox_attrib
.decoration
= DecorNormal
;
538 blackbox_attrib
.flags
|= AttribDecoration
;
539 blackbox_attrib
.decoration
= DecorNone
;
542 if (decorations
& Decor_Handle
) {
543 texture
= &(screen
->getWindowStyle()->h_focus
);
544 frame
.fhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
547 frame
.fhandle_pixel
= texture
->color().pixel();
549 texture
= &(screen
->getWindowStyle()->h_unfocus
);
550 frame
.uhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
553 frame
.uhandle_pixel
= texture
->color().pixel();
555 texture
= &(screen
->getWindowStyle()->g_focus
);
556 frame
.fgrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.fgrip
);
558 frame
.fgrip_pixel
= texture
->color().pixel();
560 texture
= &(screen
->getWindowStyle()->g_unfocus
);
561 frame
.ugrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.ugrip
);
563 frame
.ugrip_pixel
= texture
->color().pixel();
565 XSetWindowBorder(blackbox
->getXDisplay(), frame
.handle
,
566 screen
->getBorderColor()->pixel());
567 XSetWindowBorder(blackbox
->getXDisplay(), frame
.left_grip
,
568 screen
->getBorderColor()->pixel());
569 XSetWindowBorder(blackbox
->getXDisplay(), frame
.right_grip
,
570 screen
->getBorderColor()->pixel());
573 XSetWindowBorder(blackbox
->getXDisplay(), frame
.window
,
574 screen
->getBorderColor()->pixel());
578 void BlackboxWindow::decorateLabel(void) {
581 texture
= &(screen
->getWindowStyle()->l_focus
);
582 frame
.flabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.flabel
);
584 frame
.flabel_pixel
= texture
->color().pixel();
586 texture
= &(screen
->getWindowStyle()->l_unfocus
);
587 frame
.ulabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.ulabel
);
589 frame
.ulabel_pixel
= texture
->color().pixel();
593 void BlackboxWindow::createHandle(void) {
594 frame
.handle
= createChildWindow(frame
.window
);
595 blackbox
->saveWindowSearch(frame
.handle
, this);
598 createChildWindow(frame
.handle
, blackbox
->getLowerLeftAngleCursor());
599 blackbox
->saveWindowSearch(frame
.left_grip
, this);
602 createChildWindow(frame
.handle
, blackbox
->getLowerRightAngleCursor());
603 blackbox
->saveWindowSearch(frame
.right_grip
, this);
607 void BlackboxWindow::destroyHandle(void) {
609 screen
->getImageControl()->removeImage(frame
.fhandle
);
612 screen
->getImageControl()->removeImage(frame
.uhandle
);
615 screen
->getImageControl()->removeImage(frame
.fgrip
);
618 screen
->getImageControl()->removeImage(frame
.ugrip
);
620 blackbox
->removeWindowSearch(frame
.left_grip
);
621 blackbox
->removeWindowSearch(frame
.right_grip
);
623 XDestroyWindow(blackbox
->getXDisplay(), frame
.left_grip
);
624 XDestroyWindow(blackbox
->getXDisplay(), frame
.right_grip
);
625 frame
.left_grip
= frame
.right_grip
= None
;
627 blackbox
->removeWindowSearch(frame
.handle
);
628 XDestroyWindow(blackbox
->getXDisplay(), frame
.handle
);
633 void BlackboxWindow::createTitlebar(void) {
634 frame
.title
= createChildWindow(frame
.window
);
635 frame
.label
= createChildWindow(frame
.title
);
636 blackbox
->saveWindowSearch(frame
.title
, this);
637 blackbox
->saveWindowSearch(frame
.label
, this);
639 if (decorations
& Decor_Iconify
) createIconifyButton();
640 if (decorations
& Decor_Maximize
) createMaximizeButton();
641 if (decorations
& Decor_Close
) createCloseButton();
645 void BlackboxWindow::destroyTitlebar(void) {
646 if (frame
.close_button
)
647 destroyCloseButton();
649 if (frame
.iconify_button
)
650 destroyIconifyButton();
652 if (frame
.maximize_button
)
653 destroyMaximizeButton();
656 screen
->getImageControl()->removeImage(frame
.ftitle
);
659 screen
->getImageControl()->removeImage(frame
.utitle
);
662 screen
->getImageControl()->removeImage(frame
.flabel
);
665 screen
->getImageControl()->removeImage(frame
.ulabel
);
668 screen
->getImageControl()->removeImage(frame
.fbutton
);
671 screen
->getImageControl()->removeImage(frame
.ubutton
);
674 screen
->getImageControl()->removeImage(frame
.pbutton
);
676 blackbox
->removeWindowSearch(frame
.title
);
677 blackbox
->removeWindowSearch(frame
.label
);
679 XDestroyWindow(blackbox
->getXDisplay(), frame
.label
);
680 XDestroyWindow(blackbox
->getXDisplay(), frame
.title
);
681 frame
.title
= frame
.label
= None
;
685 void BlackboxWindow::createCloseButton(void) {
686 if (frame
.title
!= None
) {
687 frame
.close_button
= createChildWindow(frame
.title
);
688 blackbox
->saveWindowSearch(frame
.close_button
, this);
693 void BlackboxWindow::destroyCloseButton(void) {
694 blackbox
->removeWindowSearch(frame
.close_button
);
695 XDestroyWindow(blackbox
->getXDisplay(), frame
.close_button
);
696 frame
.close_button
= None
;
700 void BlackboxWindow::createIconifyButton(void) {
701 if (frame
.title
!= None
) {
702 frame
.iconify_button
= createChildWindow(frame
.title
);
703 blackbox
->saveWindowSearch(frame
.iconify_button
, this);
708 void BlackboxWindow::destroyIconifyButton(void) {
709 blackbox
->removeWindowSearch(frame
.iconify_button
);
710 XDestroyWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
711 frame
.iconify_button
= None
;
715 void BlackboxWindow::createMaximizeButton(void) {
716 if (frame
.title
!= None
) {
717 frame
.maximize_button
= createChildWindow(frame
.title
);
718 blackbox
->saveWindowSearch(frame
.maximize_button
, this);
723 void BlackboxWindow::destroyMaximizeButton(void) {
724 blackbox
->removeWindowSearch(frame
.maximize_button
);
725 XDestroyWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
726 frame
.maximize_button
= None
;
730 void BlackboxWindow::positionButtons(bool redecorate_label
) {
731 string layout
= blackbox
->getTitlebarLayout();
734 bool hasclose
, hasiconify
, hasmaximize
, haslabel
;
735 hasclose
= hasiconify
= hasmaximize
= haslabel
= false;
737 string::const_iterator it
, end
;
738 for (it
= layout
.begin(), end
= layout
.end(); it
!= end
; ++it
) {
741 if (! hasclose
&& (decorations
& Decor_Close
)) {
747 if (! hasiconify
&& (decorations
& Decor_Iconify
)) {
753 if (! hasmaximize
&& (decorations
& Decor_Maximize
)) {
765 if (! hasclose
&& frame
.close_button
)
766 destroyCloseButton();
767 if (! hasiconify
&& frame
.iconify_button
)
768 destroyIconifyButton();
769 if (! hasmaximize
&& frame
.maximize_button
)
770 destroyMaximizeButton();
772 parsed
+= 'L'; // require that the label be in the layout
774 const unsigned int bsep
= frame
.bevel_w
+ 1; // separation between elements
775 const unsigned int by
= frame
.bevel_w
+ 1;
776 const unsigned int ty
= frame
.bevel_w
;
778 frame
.label_w
= frame
.inside_w
- bsep
* 2 -
779 (frame
.button_w
+ bsep
) * (parsed
.size() - 1);
781 unsigned int x
= bsep
;
782 for (it
= parsed
.begin(), end
= parsed
.end(); it
!= end
; ++it
) {
785 if (! frame
.close_button
) createCloseButton();
786 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.close_button
, x
, by
,
787 frame
.button_w
, frame
.button_w
);
788 x
+= frame
.button_w
+ bsep
;
791 if (! frame
.iconify_button
) createIconifyButton();
792 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.iconify_button
, x
, by
,
793 frame
.button_w
, frame
.button_w
);
794 x
+= frame
.button_w
+ bsep
;
797 if (! frame
.maximize_button
) createMaximizeButton();
798 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.maximize_button
, x
, by
,
799 frame
.button_w
, frame
.button_w
);
800 x
+= frame
.button_w
+ bsep
;
803 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.label
, x
, ty
,
804 frame
.label_w
, frame
.label_h
);
805 x
+= frame
.label_w
+ bsep
;
810 if (redecorate_label
) decorateLabel();
816 void BlackboxWindow::reconfigure(void) {
817 restoreGravity(client
.rect
);
819 applyGravity(frame
.rect
);
828 windowmenu
->move(windowmenu
->getX(), frame
.rect
.y() + frame
.title_h
);
829 windowmenu
->reconfigure();
834 void BlackboxWindow::grabButtons(void) {
835 if (! screen
->isSloppyFocus() || screen
->doClickRaise())
836 // grab button 1 for changing focus/raising
837 blackbox
->grabButton(Button1
, 0, frame
.plate
, True
, ButtonPressMask
,
838 GrabModeSync
, GrabModeSync
, frame
.plate
, None
,
839 screen
->allowScrollLock());
841 if (functions
& Func_Move
)
842 blackbox
->grabButton(Button1
, ModMask
, frame
.window
, True
,
843 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
844 GrabModeAsync
, frame
.window
, None
,
845 screen
->allowScrollLock());
846 if (functions
& Func_Resize
)
847 blackbox
->grabButton(Button3
, ModMask
, frame
.window
, True
,
848 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
849 GrabModeAsync
, frame
.window
, None
,
850 screen
->allowScrollLock());
851 // alt+middle lowers the window
852 blackbox
->grabButton(Button2
, ModMask
, frame
.window
, True
,
853 ButtonReleaseMask
, GrabModeAsync
, GrabModeAsync
,
855 screen
->allowScrollLock());
859 void BlackboxWindow::ungrabButtons(void) {
860 blackbox
->ungrabButton(Button1
, 0, frame
.plate
);
861 blackbox
->ungrabButton(Button1
, ModMask
, frame
.window
);
862 blackbox
->ungrabButton(Button2
, ModMask
, frame
.window
);
863 blackbox
->ungrabButton(Button3
, ModMask
, 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
;
1060 // remove from current window group
1061 if (client
.window_group
) {
1062 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1063 if (group
) group
->removeWindow(this);
1065 client
.window_group
= None
;
1067 XWMHints
*wmhint
= XGetWMHints(blackbox
->getXDisplay(), client
.window
);
1072 if (wmhint
->flags
& InputHint
) {
1073 if (wmhint
->input
== True
) {
1074 if (flags
.send_focus_message
)
1075 focus_mode
= F_LocallyActive
;
1077 if (flags
.send_focus_message
)
1078 focus_mode
= F_GloballyActive
;
1080 focus_mode
= F_NoInput
;
1084 if (wmhint
->flags
& StateHint
)
1085 current_state
= wmhint
->initial_state
;
1087 if (wmhint
->flags
& WindowGroupHint
) {
1088 client
.window_group
= wmhint
->window_group
;
1090 // add window to the appropriate group
1091 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1092 if (! group
) { // no group found, create it!
1093 new BWindowGroup(blackbox
, client
.window_group
);
1094 group
= blackbox
->searchGroup(client
.window_group
);
1097 group
->addWindow(this);
1105 * Gets the value of the WM_NORMAL_HINTS property.
1106 * If the property is not set, then use a set of default values.
1108 void BlackboxWindow::getWMNormalHints(void) {
1110 XSizeHints sizehint
;
1112 client
.min_width
= client
.min_height
=
1113 client
.width_inc
= client
.height_inc
= 1;
1114 client
.base_width
= client
.base_height
= 0;
1115 client
.win_gravity
= NorthWestGravity
;
1117 client
.min_aspect_x
= client
.min_aspect_y
=
1118 client
.max_aspect_x
= client
.max_aspect_y
= 1;
1122 use the full screen, not the strut modified size. otherwise when the
1123 availableArea changes max_width/height will be incorrect and lead to odd
1126 const Rect
& screen_area
= screen
->getRect();
1127 client
.max_width
= screen_area
.width();
1128 client
.max_height
= screen_area
.height();
1130 if (! XGetWMNormalHints(blackbox
->getXDisplay(), client
.window
,
1131 &sizehint
, &icccm_mask
))
1134 client
.normal_hint_flags
= sizehint
.flags
;
1136 if (sizehint
.flags
& PMinSize
) {
1137 if (sizehint
.min_width
>= 0)
1138 client
.min_width
= sizehint
.min_width
;
1139 if (sizehint
.min_height
>= 0)
1140 client
.min_height
= sizehint
.min_height
;
1143 if (sizehint
.flags
& PMaxSize
) {
1144 if (sizehint
.max_width
> static_cast<signed>(client
.min_width
))
1145 client
.max_width
= sizehint
.max_width
;
1147 client
.max_width
= client
.min_width
;
1149 if (sizehint
.max_height
> static_cast<signed>(client
.min_height
))
1150 client
.max_height
= sizehint
.max_height
;
1152 client
.max_height
= client
.min_height
;
1155 if (sizehint
.flags
& PResizeInc
) {
1156 client
.width_inc
= sizehint
.width_inc
;
1157 client
.height_inc
= sizehint
.height_inc
;
1160 #if 0 // we do not support this at the moment
1161 if (sizehint
.flags
& PAspect
) {
1162 client
.min_aspect_x
= sizehint
.min_aspect
.x
;
1163 client
.min_aspect_y
= sizehint
.min_aspect
.y
;
1164 client
.max_aspect_x
= sizehint
.max_aspect
.x
;
1165 client
.max_aspect_y
= sizehint
.max_aspect
.y
;
1169 if (sizehint
.flags
& PBaseSize
) {
1170 client
.base_width
= sizehint
.base_width
;
1171 client
.base_height
= sizehint
.base_height
;
1174 if (sizehint
.flags
& PWinGravity
)
1175 client
.win_gravity
= sizehint
.win_gravity
;
1180 * Gets the NETWM hints for the class' contained window.
1182 void BlackboxWindow::getNetWMHints(void) {
1183 unsigned long workspace
;
1185 if (xatom
->getValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1187 if (workspace
== 0xffffffff)
1190 blackbox_attrib
.workspace
= workspace
;
1193 unsigned long *state
;
1194 unsigned long num
= (unsigned) -1;
1195 if (xatom
->getValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
1199 for (unsigned long i
= 0; i
< num
; ++i
) {
1200 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
))
1202 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_shaded
))
1203 flags
.shaded
= True
;
1204 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
))
1205 flags
.skip_taskbar
= True
;
1206 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_pager
))
1207 flags
.skip_pager
= True
;
1208 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_fullscreen
))
1209 flags
.fullscreen
= True
;
1210 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_hidden
))
1211 setState(IconicState
);
1212 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_vert
))
1214 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_horz
))
1218 flags
.maximized
= 1;
1220 flags
.maximized
= 2;
1222 flags
.maximized
= 3;
1230 * Gets the MWM hints for the class' contained window.
1231 * This is used while initializing the window to its first state, and not
1233 * Returns: true if the MWM hints are successfully retreived and applied;
1234 * false if they are not.
1236 void BlackboxWindow::getMWMHints(void) {
1240 num
= PropMwmHintsElements
;
1241 if (! xatom
->getValue(client
.window
, XAtom::motif_wm_hints
,
1242 XAtom::motif_wm_hints
, num
,
1243 (unsigned long **)&mwm_hint
))
1245 if (num
< PropMwmHintsElements
) {
1250 if (mwm_hint
->flags
& MwmHintsDecorations
) {
1251 if (mwm_hint
->decorations
& MwmDecorAll
) {
1252 decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
1253 Decor_Iconify
| Decor_Maximize
| Decor_Close
;
1257 if (mwm_hint
->decorations
& MwmDecorBorder
)
1258 decorations
|= Decor_Border
;
1259 if (mwm_hint
->decorations
& MwmDecorHandle
)
1260 decorations
|= Decor_Handle
;
1261 if (mwm_hint
->decorations
& MwmDecorTitle
)
1262 decorations
|= Decor_Titlebar
;
1263 if (mwm_hint
->decorations
& MwmDecorIconify
)
1264 decorations
|= Decor_Iconify
;
1265 if (mwm_hint
->decorations
& MwmDecorMaximize
)
1266 decorations
|= Decor_Maximize
;
1270 if (mwm_hint
->flags
& MwmHintsFunctions
) {
1271 if (mwm_hint
->functions
& MwmFuncAll
) {
1272 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
|
1277 if (mwm_hint
->functions
& MwmFuncResize
)
1278 functions
|= Func_Resize
;
1279 if (mwm_hint
->functions
& MwmFuncMove
)
1280 functions
|= Func_Move
;
1281 if (mwm_hint
->functions
& MwmFuncIconify
)
1282 functions
|= Func_Iconify
;
1283 if (mwm_hint
->functions
& MwmFuncMaximize
)
1284 functions
|= Func_Maximize
;
1285 if (mwm_hint
->functions
& MwmFuncClose
)
1286 functions
|= Func_Close
;
1294 * Gets the blackbox hints from the class' contained window.
1295 * This is used while initializing the window to its first state, and not
1297 * Returns: true if the hints are successfully retreived and applied; false if
1300 bool BlackboxWindow::getBlackboxHints(void) {
1302 BlackboxHints
*blackbox_hint
;
1304 num
= PropBlackboxHintsElements
;
1305 if (! xatom
->getValue(client
.window
, XAtom::blackbox_hints
,
1306 XAtom::blackbox_hints
, num
,
1307 (unsigned long **)&blackbox_hint
))
1309 if (num
< PropBlackboxHintsElements
) {
1310 delete [] blackbox_hint
;
1314 if (blackbox_hint
->flags
& AttribShaded
)
1315 flags
.shaded
= (blackbox_hint
->attrib
& AttribShaded
);
1317 if ((blackbox_hint
->flags
& AttribMaxHoriz
) &&
1318 (blackbox_hint
->flags
& AttribMaxVert
))
1319 flags
.maximized
= (blackbox_hint
->attrib
&
1320 (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1321 else if (blackbox_hint
->flags
& AttribMaxVert
)
1322 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxVert
) ? 2 : 0;
1323 else if (blackbox_hint
->flags
& AttribMaxHoriz
)
1324 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1326 if (blackbox_hint
->flags
& AttribOmnipresent
)
1327 flags
.stuck
= (blackbox_hint
->attrib
& AttribOmnipresent
);
1329 if (blackbox_hint
->flags
& AttribWorkspace
)
1330 blackbox_attrib
.workspace
= blackbox_hint
->workspace
;
1332 // if (blackbox_hint->flags & AttribStack)
1333 // don't yet have always on top/bottom for blackbox yet... working
1336 if (blackbox_hint
->flags
& AttribDecoration
) {
1337 switch (blackbox_hint
->decoration
) {
1343 decorations
|= Decor_Titlebar
| Decor_Iconify
;
1344 decorations
&= ~(Decor_Border
| Decor_Handle
| Decor_Maximize
);
1345 functions
&= ~(Func_Resize
| Func_Maximize
);
1350 decorations
|= Decor_Titlebar
;
1351 decorations
&= ~(Decor_Iconify
| Decor_Border
| Decor_Handle
);
1352 functions
&= ~(Func_Resize
| Func_Maximize
| Func_Iconify
);
1358 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Handle
|
1359 Decor_Iconify
| Decor_Maximize
;
1366 delete [] blackbox_hint
;
1372 void BlackboxWindow::getTransientInfo(void) {
1373 if (client
.transient_for
&&
1374 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1375 // reset transient_for in preparation of looking for a new owner
1376 client
.transient_for
->client
.transientList
.remove(this);
1379 // we have no transient_for until we find a new one
1380 client
.transient_for
= 0;
1383 if (! XGetTransientForHint(blackbox
->getXDisplay(), client
.window
,
1385 // transient_for hint not set
1389 if (trans_for
== client
.window
) {
1390 // wierd client... treat this window as a normal window
1394 if (trans_for
== None
|| trans_for
== screen
->getRootWindow()) {
1395 // this is an undocumented interpretation of the ICCCM. a transient
1396 // associated with None/Root/itself is assumed to be a modal root
1397 // transient. we don't support the concept of a global transient,
1398 // so we just associate this transient with nothing, and perhaps
1399 // we will add support later for global modality.
1400 client
.transient_for
= (BlackboxWindow
*) ~0ul;
1405 client
.transient_for
= blackbox
->searchWindow(trans_for
);
1406 if (! client
.transient_for
&&
1407 client
.window_group
&& trans_for
== client
.window_group
) {
1408 // no direct transient_for, perhaps this is a group transient?
1409 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1410 if (group
) client
.transient_for
= group
->find(screen
);
1413 if (! client
.transient_for
|| client
.transient_for
== this) {
1414 // no transient_for found, or we have a wierd client that wants to be
1415 // a transient for itself, so we treat this window as a normal window
1416 client
.transient_for
= (BlackboxWindow
*) 0;
1420 // register ourselves with our new transient_for
1421 client
.transient_for
->client
.transientList
.push_back(this);
1422 flags
.stuck
= client
.transient_for
->flags
.stuck
;
1426 BlackboxWindow
*BlackboxWindow::getTransientFor(void) const {
1427 if (client
.transient_for
&&
1428 client
.transient_for
!= (BlackboxWindow
*) ~0ul)
1429 return client
.transient_for
;
1435 * This function is responsible for updating both the client and the frame
1437 * According to the ICCCM a client message is not sent for a resize, only a
1440 void BlackboxWindow::configure(int dx
, int dy
,
1441 unsigned int dw
, unsigned int dh
) {
1442 bool send_event
= ((frame
.rect
.x() != dx
|| frame
.rect
.y() != dy
) &&
1445 if (dw
!= frame
.rect
.width() || dh
!= frame
.rect
.height()) {
1446 frame
.rect
.setRect(dx
, dy
, dw
, dh
);
1447 frame
.inside_w
= frame
.rect
.width() - (frame
.border_w
* 2);
1448 frame
.inside_h
= frame
.rect
.height() - (frame
.border_w
* 2);
1450 if (frame
.rect
.right() <= 0 || frame
.rect
.bottom() <= 0)
1451 frame
.rect
.setPos(0, 0);
1453 client
.rect
.setCoords(frame
.rect
.left() + frame
.margin
.left
,
1454 frame
.rect
.top() + frame
.margin
.top
,
1455 frame
.rect
.right() - frame
.margin
.right
,
1456 frame
.rect
.bottom() - frame
.margin
.bottom
);
1459 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
1466 redrawWindowFrame();
1468 frame
.rect
.setPos(dx
, dy
);
1470 XMoveWindow(blackbox
->getXDisplay(), frame
.window
,
1471 frame
.rect
.x(), frame
.rect
.y());
1473 we may have been called just after an opaque window move, so even though
1474 the old coords match the new ones no ConfigureNotify has been sent yet.
1475 There are likely other times when this will be relevant as well.
1477 if (! flags
.moving
) send_event
= True
;
1481 // if moving, the update and event will occur when the move finishes
1482 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1483 frame
.rect
.top() + frame
.margin
.top
);
1486 event
.type
= ConfigureNotify
;
1488 event
.xconfigure
.display
= blackbox
->getXDisplay();
1489 event
.xconfigure
.event
= client
.window
;
1490 event
.xconfigure
.window
= client
.window
;
1491 event
.xconfigure
.x
= client
.rect
.x();
1492 event
.xconfigure
.y
= client
.rect
.y();
1493 event
.xconfigure
.width
= client
.rect
.width();
1494 event
.xconfigure
.height
= client
.rect
.height();
1495 event
.xconfigure
.border_width
= client
.old_bw
;
1496 event
.xconfigure
.above
= frame
.window
;
1497 event
.xconfigure
.override_redirect
= False
;
1499 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1500 StructureNotifyMask
, &event
);
1501 screen
->updateNetizenConfigNotify(&event
);
1502 XFlush(blackbox
->getXDisplay());
1508 void BlackboxWindow::configureShape(void) {
1509 XShapeCombineShape(blackbox
->getXDisplay(), frame
.window
, ShapeBounding
,
1510 frame
.margin
.left
- frame
.border_w
,
1511 frame
.margin
.top
- frame
.border_w
,
1512 client
.window
, ShapeBounding
, ShapeSet
);
1515 XRectangle xrect
[2];
1517 if (decorations
& Decor_Titlebar
) {
1518 xrect
[0].x
= xrect
[0].y
= -frame
.border_w
;
1519 xrect
[0].width
= frame
.rect
.width();
1520 xrect
[0].height
= frame
.title_h
+ (frame
.border_w
* 2);
1524 if (decorations
& Decor_Handle
) {
1525 xrect
[1].x
= -frame
.border_w
;
1526 xrect
[1].y
= frame
.rect
.height() - frame
.margin
.bottom
+
1527 frame
.mwm_border_w
- frame
.border_w
;
1528 xrect
[1].width
= frame
.rect
.width();
1529 xrect
[1].height
= frame
.handle_h
+ (frame
.border_w
* 2);
1533 XShapeCombineRectangles(blackbox
->getXDisplay(), frame
.window
,
1534 ShapeBounding
, 0, 0, xrect
, num
,
1535 ShapeUnion
, Unsorted
);
1540 bool BlackboxWindow::setInputFocus(void) {
1541 if (flags
.focused
) return True
;
1543 assert(flags
.stuck
|| // window must be on the current workspace or sticky
1544 blackbox_attrib
.workspace
== screen
->getCurrentWorkspaceID());
1547 We only do this check for normal windows and dialogs because other windows
1548 do this on purpose, such as kde's kicker, and we don't want to go moving
1551 if (window_type
== Type_Normal
|| window_type
== Type_Dialog
)
1552 if (! frame
.rect
.intersects(screen
->getRect())) {
1553 // client is outside the screen, move it to the center
1554 configure((screen
->getWidth() - frame
.rect
.width()) / 2,
1555 (screen
->getHeight() - frame
.rect
.height()) / 2,
1556 frame
.rect
.width(), frame
.rect
.height());
1559 if (client
.transientList
.size() > 0) {
1560 // transfer focus to any modal transients
1561 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1562 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1563 if ((*it
)->flags
.modal
) return (*it
)->setInputFocus();
1568 if (focus_mode
== F_LocallyActive
|| focus_mode
== F_Passive
) {
1569 XSetInputFocus(blackbox
->getXDisplay(), client
.window
,
1570 RevertToPointerRoot
, CurrentTime
);
1572 /* we could set the focus to none, since the window doesn't accept focus,
1573 * but we shouldn't set focus to nothing since this would surely make
1579 if (flags
.send_focus_message
) {
1581 ce
.xclient
.type
= ClientMessage
;
1582 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1583 ce
.xclient
.display
= blackbox
->getXDisplay();
1584 ce
.xclient
.window
= client
.window
;
1585 ce
.xclient
.format
= 32;
1586 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_take_focus
);
1587 ce
.xclient
.data
.l
[1] = blackbox
->getLastTime();
1588 ce
.xclient
.data
.l
[2] = 0l;
1589 ce
.xclient
.data
.l
[3] = 0l;
1590 ce
.xclient
.data
.l
[4] = 0l;
1591 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1593 XFlush(blackbox
->getXDisplay());
1600 void BlackboxWindow::iconify(void) {
1601 if (flags
.iconic
) return;
1603 // We don't need to worry about resizing because resizing always grabs the X
1604 // server. This should only ever happen if using opaque moving.
1608 if (windowmenu
) windowmenu
->hide();
1611 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1612 * we need to clear the event mask on client.window for a split second.
1613 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1614 * split second, leaving us with a ghost window... so, we need to do this
1615 * while the X server is grabbed
1617 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1618 StructureNotifyMask
;
1619 XGrabServer(blackbox
->getXDisplay());
1620 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1621 event_mask
& ~StructureNotifyMask
);
1622 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1623 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1624 XUngrabServer(blackbox
->getXDisplay());
1626 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1627 flags
.visible
= False
;
1628 flags
.iconic
= True
;
1630 setState(IconicState
);
1632 screen
->getWorkspace(blackbox_attrib
.workspace
)->removeWindow(this);
1634 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
1635 if (i
!= blackbox_attrib
.workspace
)
1636 screen
->getWorkspace(i
)->removeWindow(this, True
);
1639 if (isTransient()) {
1640 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1641 ! client
.transient_for
->flags
.iconic
) {
1642 // iconify our transient_for
1643 client
.transient_for
->iconify();
1647 screen
->addIcon(this);
1649 if (client
.transientList
.size() > 0) {
1650 // iconify all transients
1651 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1652 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1653 if (! (*it
)->flags
.iconic
) (*it
)->iconify();
1656 screen
->updateStackingList();
1660 void BlackboxWindow::show(void) {
1661 flags
.visible
= True
;
1662 flags
.iconic
= False
;
1664 current_state
= (flags
.shaded
) ? IconicState
: NormalState
;
1665 setState(current_state
);
1667 XMapWindow(blackbox
->getXDisplay(), client
.window
);
1668 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
1669 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
1674 XTranslateCoordinates(blackbox
->getXDisplay(), client
.window
,
1675 screen
->getRootWindow(),
1676 0, 0, &real_x
, &real_y
, &child
);
1677 fprintf(stderr
, "%s -- assumed: (%d, %d), real: (%d, %d)\n", getTitle(),
1678 client
.rect
.left(), client
.rect
.top(), real_x
, real_y
);
1679 assert(client
.rect
.left() == real_x
&& client
.rect
.top() == real_y
);
1684 void BlackboxWindow::deiconify(bool reassoc
, bool raise
) {
1685 if (flags
.iconic
|| reassoc
)
1686 screen
->reassociateWindow(this, BSENTINEL
, False
);
1687 else if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID())
1692 // reassociate and deiconify all transients
1693 if (reassoc
&& client
.transientList
.size() > 0) {
1694 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1695 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1696 (*it
)->deiconify(True
, False
);
1701 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1705 void BlackboxWindow::close(void) {
1707 ce
.xclient
.type
= ClientMessage
;
1708 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1709 ce
.xclient
.display
= blackbox
->getXDisplay();
1710 ce
.xclient
.window
= client
.window
;
1711 ce
.xclient
.format
= 32;
1712 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_delete_window
);
1713 ce
.xclient
.data
.l
[1] = CurrentTime
;
1714 ce
.xclient
.data
.l
[2] = 0l;
1715 ce
.xclient
.data
.l
[3] = 0l;
1716 ce
.xclient
.data
.l
[4] = 0l;
1717 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
, NoEventMask
, &ce
);
1718 XFlush(blackbox
->getXDisplay());
1722 void BlackboxWindow::withdraw(void) {
1723 // We don't need to worry about resizing because resizing always grabs the X
1724 // server. This should only ever happen if using opaque moving.
1728 flags
.visible
= False
;
1729 flags
.iconic
= False
;
1731 setState(current_state
);
1733 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1735 XGrabServer(blackbox
->getXDisplay());
1737 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1738 StructureNotifyMask
;
1739 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1740 event_mask
& ~StructureNotifyMask
);
1741 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1742 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1744 XUngrabServer(blackbox
->getXDisplay());
1746 if (windowmenu
) windowmenu
->hide();
1750 void BlackboxWindow::maximize(unsigned int button
) {
1751 // We don't need to worry about resizing because resizing always grabs the X
1752 // server. This should only ever happen if using opaque moving.
1756 // handle case where menu is open then the max button is used instead
1757 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
1759 if (flags
.maximized
) {
1760 flags
.maximized
= 0;
1762 blackbox_attrib
.flags
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1763 blackbox_attrib
.attrib
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1766 when a resize finishes, maximize(0) is called to clear any maximization
1767 flags currently set. Otherwise it still thinks it is maximized.
1768 so we do not need to call configure() because resizing will handle it
1770 if (! flags
.resizing
)
1771 configure(blackbox_attrib
.premax_x
, blackbox_attrib
.premax_y
,
1772 blackbox_attrib
.premax_w
, blackbox_attrib
.premax_h
);
1774 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
1775 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
1777 redrawAllButtons(); // in case it is not called in configure()
1778 setState(current_state
);
1782 blackbox_attrib
.premax_x
= frame
.rect
.x();
1783 blackbox_attrib
.premax_y
= frame
.rect
.y();
1784 blackbox_attrib
.premax_w
= frame
.rect
.width();
1785 // use client.rect so that clients can be restored even if shaded
1786 blackbox_attrib
.premax_h
=
1787 client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
;
1790 if (screen
->isXineramaActive() && blackbox
->doXineramaMaximizing()) {
1791 // find the area to use
1792 RectList availableAreas
= screen
->allAvailableAreas();
1793 RectList::iterator it
, end
= availableAreas
.end();
1795 for (it
= availableAreas
.begin(); it
!= end
; ++it
)
1796 if (it
->intersects(frame
.rect
)) break;
1797 if (it
== end
) // the window isn't inside an area
1798 it
= availableAreas
.begin(); // so just default to the first one
1800 frame
.changing
= *it
;
1803 frame
.changing
= screen
->availableArea();
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) {
1850 // we only update the window's attributes otherwise we lose the shade bit
1851 switch(flags
.maximized
) {
1853 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1854 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1858 blackbox_attrib
.flags
|= AttribMaxVert
;
1859 blackbox_attrib
.attrib
|= AttribMaxVert
;
1863 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1864 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1870 // save the original dimensions because maximize will wipe them out
1871 int premax_x
= blackbox_attrib
.premax_x
,
1872 premax_y
= blackbox_attrib
.premax_y
,
1873 premax_w
= blackbox_attrib
.premax_w
,
1874 premax_h
= blackbox_attrib
.premax_h
;
1876 unsigned int button
= flags
.maximized
;
1877 flags
.maximized
= 0; // trick maximize() into working
1880 // restore saved values
1881 blackbox_attrib
.premax_x
= premax_x
;
1882 blackbox_attrib
.premax_y
= premax_y
;
1883 blackbox_attrib
.premax_w
= premax_w
;
1884 blackbox_attrib
.premax_h
= premax_h
;
1888 void BlackboxWindow::setWorkspace(unsigned int n
) {
1889 blackbox_attrib
.flags
|= AttribWorkspace
;
1890 blackbox_attrib
.workspace
= n
;
1891 if (n
== BSENTINEL
) { // iconified window
1893 we set the workspace to 'all workspaces' so that taskbars will show the
1894 window. otherwise, it made uniconifying a window imposible without the
1895 blackbox workspace menu
1899 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
, n
);
1903 void BlackboxWindow::shade(void) {
1905 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1906 frame
.inside_w
, frame
.inside_h
);
1907 flags
.shaded
= False
;
1908 blackbox_attrib
.flags
^= AttribShaded
;
1909 blackbox_attrib
.attrib
^= AttribShaded
;
1911 setState(NormalState
);
1913 // set the frame rect to the normal size
1914 frame
.rect
.setHeight(client
.rect
.height() + frame
.margin
.top
+
1915 frame
.margin
.bottom
);
1917 if (! (decorations
& Decor_Titlebar
))
1918 return; // can't shade it without a titlebar!
1920 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1921 frame
.inside_w
, frame
.title_h
);
1922 flags
.shaded
= True
;
1923 blackbox_attrib
.flags
|= AttribShaded
;
1924 blackbox_attrib
.attrib
|= AttribShaded
;
1926 setState(IconicState
);
1928 // set the frame rect to the shaded size
1929 frame
.rect
.setHeight(frame
.title_h
+ (frame
.border_w
* 2));
1935 * (Un)Sticks a window and its relatives.
1937 void BlackboxWindow::stick(void) {
1939 blackbox_attrib
.flags
^= AttribOmnipresent
;
1940 blackbox_attrib
.attrib
^= AttribOmnipresent
;
1942 flags
.stuck
= False
;
1944 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
1945 if (i
!= blackbox_attrib
.workspace
)
1946 screen
->getWorkspace(i
)->removeWindow(this, True
);
1949 screen
->reassociateWindow(this, BSENTINEL
, True
);
1950 // temporary fix since sticky windows suck. set the hint to what we
1951 // actually hold in our data.
1952 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1953 blackbox_attrib
.workspace
);
1955 setState(current_state
);
1959 blackbox_attrib
.flags
|= AttribOmnipresent
;
1960 blackbox_attrib
.attrib
|= AttribOmnipresent
;
1962 // temporary fix since sticky windows suck. set the hint to a different
1963 // value than that contained in the class' data.
1964 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1967 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
1968 if (i
!= blackbox_attrib
.workspace
)
1969 screen
->getWorkspace(i
)->addWindow(this, False
, True
);
1971 setState(current_state
);
1974 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1975 client
.transient_for
->isStuck() != flags
.stuck
)
1976 client
.transient_for
->stick();
1977 // go down the chain
1978 BlackboxWindowList::iterator it
;
1979 const BlackboxWindowList::iterator end
= client
.transientList
.end();
1980 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1981 if ((*it
)->isStuck() != flags
.stuck
)
1986 void BlackboxWindow::redrawWindowFrame(void) const {
1987 if (decorations
& Decor_Titlebar
) {
1988 if (flags
.focused
) {
1990 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1991 frame
.title
, frame
.ftitle
);
1993 XSetWindowBackground(blackbox
->getXDisplay(),
1994 frame
.title
, frame
.ftitle_pixel
);
1997 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1998 frame
.title
, frame
.utitle
);
2000 XSetWindowBackground(blackbox
->getXDisplay(),
2001 frame
.title
, frame
.utitle_pixel
);
2003 XClearWindow(blackbox
->getXDisplay(), frame
.title
);
2009 if (decorations
& Decor_Handle
) {
2010 if (flags
.focused
) {
2012 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2013 frame
.handle
, frame
.fhandle
);
2015 XSetWindowBackground(blackbox
->getXDisplay(),
2016 frame
.handle
, frame
.fhandle_pixel
);
2019 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2020 frame
.left_grip
, frame
.fgrip
);
2021 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2022 frame
.right_grip
, frame
.fgrip
);
2024 XSetWindowBackground(blackbox
->getXDisplay(),
2025 frame
.left_grip
, frame
.fgrip_pixel
);
2026 XSetWindowBackground(blackbox
->getXDisplay(),
2027 frame
.right_grip
, frame
.fgrip_pixel
);
2031 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2032 frame
.handle
, frame
.uhandle
);
2034 XSetWindowBackground(blackbox
->getXDisplay(),
2035 frame
.handle
, frame
.uhandle_pixel
);
2038 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2039 frame
.left_grip
, frame
.ugrip
);
2040 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2041 frame
.right_grip
, frame
.ugrip
);
2043 XSetWindowBackground(blackbox
->getXDisplay(),
2044 frame
.left_grip
, frame
.ugrip_pixel
);
2045 XSetWindowBackground(blackbox
->getXDisplay(),
2046 frame
.right_grip
, frame
.ugrip_pixel
);
2049 XClearWindow(blackbox
->getXDisplay(), frame
.handle
);
2050 XClearWindow(blackbox
->getXDisplay(), frame
.left_grip
);
2051 XClearWindow(blackbox
->getXDisplay(), frame
.right_grip
);
2054 if (decorations
& Decor_Border
) {
2056 XSetWindowBorder(blackbox
->getXDisplay(),
2057 frame
.plate
, frame
.fborder_pixel
);
2059 XSetWindowBorder(blackbox
->getXDisplay(),
2060 frame
.plate
, frame
.uborder_pixel
);
2065 void BlackboxWindow::setFocusFlag(bool focus
) {
2066 // only focus a window if it is visible
2067 if (focus
&& !flags
.visible
)
2070 flags
.focused
= focus
;
2072 redrawWindowFrame();
2074 if (screen
->isSloppyFocus() && screen
->doAutoRaise()) {
2075 if (isFocused()) timer
->start();
2080 blackbox
->setFocusedWindow(this);
2082 if (! flags
.iconic
) {
2083 // iconic windows arent in a workspace menu!
2085 screen
->getCurrentWorkspace()->setFocused(this, isFocused());
2087 screen
->getWorkspace(blackbox_attrib
.workspace
)->
2088 setFocused(this, flags
.focused
);
2093 void BlackboxWindow::installColormap(bool install
) {
2094 int i
= 0, ncmap
= 0;
2095 Colormap
*cmaps
= XListInstalledColormaps(blackbox
->getXDisplay(),
2096 client
.window
, &ncmap
);
2098 XWindowAttributes wattrib
;
2099 if (XGetWindowAttributes(blackbox
->getXDisplay(),
2100 client
.window
, &wattrib
)) {
2102 // install the window's colormap
2103 for (i
= 0; i
< ncmap
; i
++) {
2104 if (*(cmaps
+ i
) == wattrib
.colormap
)
2105 // this window is using an installed color map... do not install
2108 // otherwise, install the window's colormap
2110 XInstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2112 // uninstall the window's colormap
2113 for (i
= 0; i
< ncmap
; i
++) {
2114 if (*(cmaps
+ i
) == wattrib
.colormap
)
2115 // we found the colormap to uninstall
2116 XUninstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2126 void BlackboxWindow::setAllowedActions(void) {
2130 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_shade
);
2131 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_change_desktop
);
2132 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_close
);
2134 if (functions
& Func_Move
)
2135 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_move
);
2136 if (functions
& Func_Resize
)
2137 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_resize
);
2138 if (functions
& Func_Maximize
) {
2139 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_horz
);
2140 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_vert
);
2143 xatom
->setValue(client
.window
, XAtom::net_wm_allowed_actions
, XAtom::atom
,
2148 void BlackboxWindow::setState(unsigned long new_state
) {
2149 current_state
= new_state
;
2151 unsigned long state
[2];
2152 state
[0] = current_state
;
2154 xatom
->setValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
, state
, 2);
2156 xatom
->setValue(client
.window
, XAtom::blackbox_attributes
,
2157 XAtom::blackbox_attributes
, (unsigned long *)&blackbox_attrib
,
2158 PropBlackboxAttributesElements
);
2163 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_modal
);
2165 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_shaded
);
2167 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_hidden
);
2168 if (flags
.skip_taskbar
)
2169 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
);
2170 if (flags
.skip_pager
)
2171 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_pager
);
2172 if (flags
.fullscreen
)
2173 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_fullscreen
);
2174 if (flags
.maximized
== 1 || flags
.maximized
== 2)
2175 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_vert
);
2176 if (flags
.maximized
== 1 || flags
.maximized
== 3)
2177 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_horz
);
2178 xatom
->setValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
2183 bool BlackboxWindow::getState(void) {
2184 bool ret
= xatom
->getValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
,
2186 if (! ret
) current_state
= 0;
2191 void BlackboxWindow::restoreAttributes(void) {
2192 unsigned long num
= PropBlackboxAttributesElements
;
2193 BlackboxAttributes
*net
;
2194 if (! xatom
->getValue(client
.window
, XAtom::blackbox_attributes
,
2195 XAtom::blackbox_attributes
, num
,
2196 (unsigned long **)&net
))
2198 if (num
< PropBlackboxAttributesElements
) {
2203 if (net
->flags
& AttribShaded
&& net
->attrib
& AttribShaded
) {
2204 flags
.shaded
= False
;
2205 unsigned long orig_state
= current_state
;
2209 At this point in the life of a window, current_state should only be set
2210 to IconicState if the window was an *icon*, not if it was shaded.
2212 if (orig_state
!= IconicState
)
2213 current_state
= WithdrawnState
;
2216 if (net
->workspace
!= screen
->getCurrentWorkspaceID() &&
2217 net
->workspace
< screen
->getWorkspaceCount())
2218 screen
->reassociateWindow(this, net
->workspace
, True
);
2220 if ((blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID()) &&
2221 (blackbox_attrib
.workspace
< screen
->getWorkspaceCount())) {
2222 // set to WithdrawnState so it will be mapped on the new workspace
2223 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2224 } else if (current_state
== WithdrawnState
) {
2225 // the window is on this workspace and is Withdrawn, so it is waiting to
2227 current_state
= NormalState
;
2230 if (net
->flags
& AttribOmnipresent
&& net
->attrib
& AttribOmnipresent
&&
2234 // if the window was on another workspace, it was going to be hidden. this
2235 // specifies that the window should be mapped since it is sticky.
2236 if (current_state
== WithdrawnState
) current_state
= NormalState
;
2239 if (net
->flags
& AttribMaxHoriz
|| net
->flags
& AttribMaxVert
) {
2240 int x
= net
->premax_x
, y
= net
->premax_y
;
2241 unsigned int w
= net
->premax_w
, h
= net
->premax_h
;
2242 flags
.maximized
= 0;
2245 if ((net
->flags
& AttribMaxHoriz
) &&
2246 (net
->flags
& AttribMaxVert
))
2247 m
= (net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
2248 else if (net
->flags
& AttribMaxVert
)
2249 m
= (net
->attrib
& AttribMaxVert
) ? 2 : 0;
2250 else if (net
->flags
& AttribMaxHoriz
)
2251 m
= (net
->attrib
& AttribMaxHoriz
) ? 3 : 0;
2255 blackbox_attrib
.premax_x
= x
;
2256 blackbox_attrib
.premax_y
= y
;
2257 blackbox_attrib
.premax_w
= w
;
2258 blackbox_attrib
.premax_h
= h
;
2261 if (net
->flags
& AttribDecoration
) {
2262 switch (net
->decoration
) {
2270 decorations
|= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
2271 Decor_Iconify
| Decor_Maximize
;
2276 decorations
|= Decor_Titlebar
| Decor_Iconify
;
2277 decorations
&= ~(Decor_Border
| Decor_Handle
| Decor_Maximize
);
2282 decorations
|= Decor_Titlebar
;
2283 decorations
&= ~(Decor_Iconify
| Decor_Border
| Decor_Handle
);
2288 // sanity check the new decor
2289 if (! (functions
& Func_Resize
) || isTransient())
2290 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2291 if (! (functions
& Func_Maximize
))
2292 decorations
&= ~Decor_Maximize
;
2294 if (decorations
& Decor_Titlebar
) {
2295 if (functions
& Func_Close
) // close button is controlled by function
2296 decorations
|= Decor_Close
; // not decor type
2298 if (flags
.shaded
) // we can not be shaded if we lack a titlebar
2302 if (flags
.visible
&& frame
.window
) {
2303 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
2304 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
2308 setState(current_state
);
2311 // with the state set it will then be the map event's job to read the
2312 // window's state and behave accordingly
2319 * Positions the Rect r according the the client window position and
2322 void BlackboxWindow::applyGravity(Rect
&r
) {
2323 // apply horizontal window gravity
2324 switch (client
.win_gravity
) {
2326 case NorthWestGravity
:
2327 case SouthWestGravity
:
2329 r
.setX(client
.rect
.x());
2335 r
.setX(client
.rect
.x() - (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2338 case NorthEastGravity
:
2339 case SouthEastGravity
:
2341 r
.setX(client
.rect
.x() - frame
.margin
.left
- frame
.margin
.right
+ 2);
2346 r
.setX(client
.rect
.x() - frame
.margin
.left
);
2350 // apply vertical window gravity
2351 switch (client
.win_gravity
) {
2353 case NorthWestGravity
:
2354 case NorthEastGravity
:
2356 r
.setY(client
.rect
.y());
2362 r
.setY(client
.rect
.y() - (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2365 case SouthWestGravity
:
2366 case SouthEastGravity
:
2368 r
.setY(client
.rect
.y() - frame
.margin
.top
- frame
.margin
.bottom
+ 2);
2373 r
.setY(client
.rect
.y() - frame
.margin
.top
);
2380 * The reverse of the applyGravity function.
2382 * Positions the Rect r according to the frame window position and
2385 void BlackboxWindow::restoreGravity(Rect
&r
) {
2386 // restore horizontal window gravity
2387 switch (client
.win_gravity
) {
2389 case NorthWestGravity
:
2390 case SouthWestGravity
:
2392 r
.setX(frame
.rect
.x());
2398 r
.setX(frame
.rect
.x() + (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2401 case NorthEastGravity
:
2402 case SouthEastGravity
:
2404 r
.setX(frame
.rect
.x() + frame
.margin
.left
+ frame
.margin
.right
- 2);
2409 r
.setX(frame
.rect
.x() + frame
.margin
.left
);
2413 // restore vertical window gravity
2414 switch (client
.win_gravity
) {
2416 case NorthWestGravity
:
2417 case NorthEastGravity
:
2419 r
.setY(frame
.rect
.y());
2425 r
.setY(frame
.rect
.y() + (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2428 case SouthWestGravity
:
2429 case SouthEastGravity
:
2431 r
.setY(frame
.rect
.y() + frame
.margin
.top
+ frame
.margin
.bottom
- 2);
2436 r
.setY(frame
.rect
.y() + frame
.margin
.top
);
2442 void BlackboxWindow::redrawLabel(void) const {
2443 if (flags
.focused
) {
2445 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2446 frame
.label
, frame
.flabel
);
2448 XSetWindowBackground(blackbox
->getXDisplay(),
2449 frame
.label
, frame
.flabel_pixel
);
2452 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2453 frame
.label
, frame
.ulabel
);
2455 XSetWindowBackground(blackbox
->getXDisplay(),
2456 frame
.label
, frame
.ulabel_pixel
);
2458 XClearWindow(blackbox
->getXDisplay(), frame
.label
);
2460 WindowStyle
*style
= screen
->getWindowStyle();
2462 int pos
= frame
.bevel_w
* 2;
2463 style
->doJustify(client
.title
.c_str(), pos
, frame
.label_w
, frame
.bevel_w
* 4);
2464 style
->font
->drawString(frame
.label
, pos
, 1,
2465 (flags
.focused
? style
->l_text_focus
:
2466 style
->l_text_unfocus
),
2471 void BlackboxWindow::redrawAllButtons(void) const {
2472 if (frame
.iconify_button
) redrawIconifyButton(False
);
2473 if (frame
.maximize_button
) redrawMaximizeButton(flags
.maximized
);
2474 if (frame
.close_button
) redrawCloseButton(False
);
2478 void BlackboxWindow::redrawIconifyButton(bool pressed
) const {
2480 if (flags
.focused
) {
2482 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2483 frame
.iconify_button
, frame
.fbutton
);
2485 XSetWindowBackground(blackbox
->getXDisplay(),
2486 frame
.iconify_button
, frame
.fbutton_pixel
);
2489 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2490 frame
.iconify_button
, frame
.ubutton
);
2492 XSetWindowBackground(blackbox
->getXDisplay(), frame
.iconify_button
,
2493 frame
.ubutton_pixel
);
2497 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2498 frame
.iconify_button
, frame
.pbutton
);
2500 XSetWindowBackground(blackbox
->getXDisplay(),
2501 frame
.iconify_button
, frame
.pbutton_pixel
);
2503 XClearWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
2505 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2506 screen
->getWindowStyle()->b_pic_unfocus
);
2507 XDrawRectangle(blackbox
->getXDisplay(), frame
.iconify_button
, pen
.gc(),
2508 2, (frame
.button_w
- 5), (frame
.button_w
- 5), 2);
2512 void BlackboxWindow::redrawMaximizeButton(bool pressed
) const {
2514 if (flags
.focused
) {
2516 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2517 frame
.maximize_button
, frame
.fbutton
);
2519 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2520 frame
.fbutton_pixel
);
2523 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2524 frame
.maximize_button
, frame
.ubutton
);
2526 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2527 frame
.ubutton_pixel
);
2531 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2532 frame
.maximize_button
, frame
.pbutton
);
2534 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2535 frame
.pbutton_pixel
);
2537 XClearWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
2539 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2540 screen
->getWindowStyle()->b_pic_unfocus
);
2541 XDrawRectangle(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2542 2, 2, (frame
.button_w
- 5), (frame
.button_w
- 5));
2543 XDrawLine(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2544 2, 3, (frame
.button_w
- 3), 3);
2548 void BlackboxWindow::redrawCloseButton(bool pressed
) const {
2550 if (flags
.focused
) {
2552 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2555 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2556 frame
.fbutton_pixel
);
2559 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2562 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2563 frame
.ubutton_pixel
);
2567 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2568 frame
.close_button
, frame
.pbutton
);
2570 XSetWindowBackground(blackbox
->getXDisplay(),
2571 frame
.close_button
, frame
.pbutton_pixel
);
2573 XClearWindow(blackbox
->getXDisplay(), frame
.close_button
);
2575 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2576 screen
->getWindowStyle()->b_pic_unfocus
);
2577 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2578 2, 2, (frame
.button_w
- 3), (frame
.button_w
- 3));
2579 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2580 2, (frame
.button_w
- 3), (frame
.button_w
- 3), 2);
2584 void BlackboxWindow::mapRequestEvent(const XMapRequestEvent
*re
) {
2585 if (re
->window
!= client
.window
)
2589 fprintf(stderr
, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2593 switch (current_state
) {
2598 case WithdrawnState
:
2607 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2609 if (! blackbox
->isStartup()) {
2610 XSync(blackbox
->getXDisplay(), False
); // make sure the frame is mapped
2611 if (screen
->doFocusNew()|| (isTransient() && getTransientFor() &&
2612 getTransientFor()->isFocused())) {
2615 if (screen
->getPlacementPolicy() == BScreen::ClickMousePlacement
) {
2619 XQueryPointer(blackbox
->getXDisplay(), screen
->getRootWindow(),
2620 &r
, &c
, &rx
, &ry
, &x
, &y
, &m
);
2630 void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent
*ue
) {
2631 if (ue
->window
!= client
.window
)
2635 fprintf(stderr
, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2639 screen
->unmanageWindow(this, False
);
2643 void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent
*de
) {
2644 if (de
->window
!= client
.window
)
2648 fprintf(stderr
, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2652 screen
->unmanageWindow(this, False
);
2656 void BlackboxWindow::reparentNotifyEvent(const XReparentEvent
*re
) {
2657 if (re
->window
!= client
.window
|| re
->parent
== frame
.plate
)
2661 fprintf(stderr
, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2662 "0x%lx.\n", client
.window
, re
->parent
);
2667 XPutBackEvent(blackbox
->getXDisplay(), &ev
);
2668 screen
->unmanageWindow(this, True
);
2672 void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent
*pe
) {
2673 if (pe
->state
== PropertyDelete
)
2677 fprintf(stderr
, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n",
2683 case XA_WM_CLIENT_MACHINE
:
2687 case XA_WM_TRANSIENT_FOR
: {
2688 // determine if this is a transient window
2691 // adjust the window decorations based on transience
2692 if (isTransient()) {
2693 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2694 functions
&= ~Func_Maximize
;
2695 setAllowedActions();
2706 case XA_WM_ICON_NAME
:
2708 if (flags
.iconic
) screen
->propagateWindowName(this);
2711 case XAtom::net_wm_name
:
2715 if (decorations
& Decor_Titlebar
)
2718 screen
->propagateWindowName(this);
2721 case XA_WM_NORMAL_HINTS
: {
2724 if ((client
.normal_hint_flags
& PMinSize
) &&
2725 (client
.normal_hint_flags
& PMaxSize
)) {
2726 // the window now can/can't resize itself, so the buttons need to be
2729 if (client
.max_width
<= client
.min_width
&&
2730 client
.max_height
<= client
.min_height
) {
2731 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2732 functions
&= ~(Func_Resize
| Func_Maximize
);
2734 if (! isTransient()) {
2735 decorations
|= Decor_Maximize
| Decor_Handle
;
2736 functions
|= Func_Maximize
;
2738 functions
|= Func_Resize
;
2741 setAllowedActions();
2744 Rect old_rect
= frame
.rect
;
2748 if (old_rect
!= frame
.rect
)
2755 if (pe
->atom
== xatom
->getAtom(XAtom::wm_protocols
)) {
2758 if ((decorations
& Decor_Close
) && (! frame
.close_button
)) {
2759 createCloseButton();
2760 if (decorations
& Decor_Titlebar
) {
2761 positionButtons(True
);
2762 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
2764 if (windowmenu
) windowmenu
->reconfigure();
2766 } else if (pe
->atom
== xatom
->getAtom(XAtom::net_wm_strut
)) {
2775 void BlackboxWindow::exposeEvent(const XExposeEvent
*ee
) {
2777 fprintf(stderr
, "BlackboxWindow::exposeEvent() for 0x%lx\n", client
.window
);
2780 if (frame
.label
== ee
->window
&& (decorations
& Decor_Titlebar
))
2782 else if (frame
.close_button
== ee
->window
)
2783 redrawCloseButton(False
);
2784 else if (frame
.maximize_button
== ee
->window
)
2785 redrawMaximizeButton(flags
.maximized
);
2786 else if (frame
.iconify_button
== ee
->window
)
2787 redrawIconifyButton(False
);
2791 void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent
*cr
) {
2792 if (cr
->window
!= client
.window
|| flags
.iconic
)
2795 if (cr
->value_mask
& CWBorderWidth
)
2796 client
.old_bw
= cr
->border_width
;
2798 if (cr
->value_mask
& (CWX
| CWY
| CWWidth
| CWHeight
)) {
2799 Rect req
= frame
.rect
;
2801 if (cr
->value_mask
& (CWX
| CWY
)) {
2802 if (cr
->value_mask
& CWX
)
2803 client
.rect
.setX(cr
->x
);
2804 if (cr
->value_mask
& CWY
)
2805 client
.rect
.setY(cr
->y
);
2810 if (cr
->value_mask
& CWWidth
)
2811 req
.setWidth(cr
->width
+ frame
.margin
.left
+ frame
.margin
.right
);
2813 if (cr
->value_mask
& CWHeight
)
2814 req
.setHeight(cr
->height
+ frame
.margin
.top
+ frame
.margin
.bottom
);
2816 configure(req
.x(), req
.y(), req
.width(), req
.height());
2819 if (cr
->value_mask
& CWStackMode
&& !isDesktop()) {
2820 switch (cr
->detail
) {
2823 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2829 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2836 void BlackboxWindow::buttonPressEvent(const XButtonEvent
*be
) {
2838 fprintf(stderr
, "BlackboxWindow::buttonPressEvent() for 0x%lx\n",
2842 if (frame
.maximize_button
== be
->window
&& be
->button
<= 3) {
2843 redrawMaximizeButton(True
);
2844 } else if (be
->button
== 1 || (be
->button
== 3 && be
->state
== ModMask
)) {
2845 if (! flags
.focused
)
2848 if (frame
.iconify_button
== be
->window
) {
2849 redrawIconifyButton(True
);
2850 } else if (frame
.close_button
== be
->window
) {
2851 redrawCloseButton(True
);
2852 } else if (frame
.plate
== be
->window
) {
2853 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2855 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2857 XAllowEvents(blackbox
->getXDisplay(), ReplayPointer
, be
->time
);
2859 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
2860 if (((be
->time
- lastButtonPressTime
) <=
2861 blackbox
->getDoubleClickInterval()) ||
2862 (be
->state
== ControlMask
)) {
2863 lastButtonPressTime
= 0;
2866 lastButtonPressTime
= be
->time
;
2870 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2872 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2874 } else if (be
->button
== 2 && (be
->window
!= frame
.iconify_button
) &&
2875 (be
->window
!= frame
.close_button
)) {
2876 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2877 } else if (windowmenu
&& be
->button
== 3 &&
2878 (frame
.title
== be
->window
|| frame
.label
== be
->window
||
2879 frame
.handle
== be
->window
|| frame
.window
== be
->window
)) {
2880 if (windowmenu
->isVisible()) {
2883 int mx
= be
->x_root
- windowmenu
->getWidth() / 2,
2884 my
= be
->y_root
- windowmenu
->getHeight() / 2;
2886 // snap the window menu into a corner/side if necessary
2887 int left_edge
, right_edge
, top_edge
, bottom_edge
;
2890 the " + (frame.border_w * 2) - 1" bits are to get the proper width
2891 and height of the menu, as the sizes returned by it do not include
2894 left_edge
= frame
.rect
.x();
2895 right_edge
= frame
.rect
.right() -
2896 (windowmenu
->getWidth() + (frame
.border_w
* 2) - 1);
2897 top_edge
= client
.rect
.top() - (frame
.border_w
+ frame
.mwm_border_w
);
2898 bottom_edge
= client
.rect
.bottom() -
2899 (windowmenu
->getHeight() + (frame
.border_w
* 2) - 1) +
2900 (frame
.border_w
+ frame
.mwm_border_w
);
2904 if (mx
> right_edge
)
2908 if (my
> bottom_edge
)
2911 windowmenu
->move(mx
, my
);
2913 XRaiseWindow(blackbox
->getXDisplay(), windowmenu
->getWindowID());
2914 XRaiseWindow(blackbox
->getXDisplay(),
2915 windowmenu
->getSendToMenu()->getWindowID());
2918 } else if (be
->button
== 4) {
2919 if ((be
->window
== frame
.label
||
2920 be
->window
== frame
.title
||
2921 be
->window
== frame
.maximize_button
||
2922 be
->window
== frame
.iconify_button
||
2923 be
->window
== frame
.close_button
) &&
2927 } else if (be
->button
== 5) {
2928 if ((be
->window
== frame
.label
||
2929 be
->window
== frame
.title
||
2930 be
->window
== frame
.maximize_button
||
2931 be
->window
== frame
.iconify_button
||
2932 be
->window
== frame
.close_button
) &&
2939 void BlackboxWindow::buttonReleaseEvent(const XButtonEvent
*re
) {
2941 fprintf(stderr
, "BlackboxWindow::buttonReleaseEvent() for 0x%lx\n",
2945 if (re
->window
== frame
.maximize_button
&&
2946 re
->button
>= 1 && re
->button
<= 3) {
2947 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2948 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2949 maximize(re
->button
);
2951 redrawMaximizeButton(flags
.maximized
);
2953 } else if (re
->window
== frame
.iconify_button
&& re
->button
== 1) {
2954 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2955 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2958 redrawIconifyButton(False
);
2960 } else if (re
->window
== frame
.close_button
& re
->button
== 1) {
2961 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2962 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
)))
2964 redrawCloseButton(False
);
2965 } else if (flags
.moving
) {
2967 } else if (flags
.resizing
) {
2969 } else if (re
->window
== frame
.window
) {
2970 if (re
->button
== 2 && re
->state
== ModMask
)
2971 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
2977 void BlackboxWindow::beginMove(int x_root
, int y_root
) {
2978 assert(! (flags
.resizing
|| flags
.moving
));
2981 Only one window can be moved/resized at a time. If another window is already
2982 being moved or resized, then stop it before whating to work with this one.
2984 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
2985 if (changing
&& changing
!= this) {
2986 if (changing
->flags
.moving
)
2987 changing
->endMove();
2988 else // if (changing->flags.resizing)
2989 changing
->endResize();
2992 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
2993 PointerMotionMask
| ButtonReleaseMask
,
2994 GrabModeAsync
, GrabModeAsync
,
2995 None
, blackbox
->getMoveCursor(), CurrentTime
);
2997 if (windowmenu
&& windowmenu
->isVisible())
3000 flags
.moving
= True
;
3001 blackbox
->setChangingWindow(this);
3003 if (! screen
->doOpaqueMove()) {
3004 XGrabServer(blackbox
->getXDisplay());
3006 frame
.changing
= frame
.rect
;
3007 screen
->showPosition(frame
.changing
.x(), frame
.changing
.y());
3009 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3013 frame
.changing
.width() - 1,
3014 frame
.changing
.height() - 1);
3017 frame
.grab_x
= x_root
- frame
.rect
.x() - frame
.border_w
;
3018 frame
.grab_y
= y_root
- frame
.rect
.y() - frame
.border_w
;
3022 void BlackboxWindow::doMove(int x_root
, int y_root
) {
3023 assert(flags
.moving
);
3024 assert(blackbox
->getChangingWindow() == this);
3026 int dx
= x_root
- frame
.grab_x
, dy
= y_root
- frame
.grab_y
;
3027 dx
-= frame
.border_w
;
3028 dy
-= frame
.border_w
;
3030 if (screen
->doWorkspaceWarping()) {
3031 // workspace warping
3033 unsigned int dest
= screen
->getCurrentWorkspaceID();
3037 if (dest
> 0) dest
--;
3038 else dest
= screen
->getNumberOfWorkspaces() - 1;
3040 } else if (x_root
>= screen
->getRect().right()) {
3043 if (dest
< screen
->getNumberOfWorkspaces() - 1) dest
++;
3048 bool focus
= flags
.focused
; // had focus while moving?
3050 screen
->reassociateWindow(this, dest
, False
);
3051 screen
->changeWorkspaceID(dest
);
3056 If the XWarpPointer is done after the configure, we can end up
3057 grabbing another window, so made sure you do it first.
3061 dest_x
= screen
->getRect().right() - 1;
3062 XWarpPointer(blackbox
->getXDisplay(), None
,
3063 screen
->getRootWindow(), 0, 0, 0, 0,
3066 configure(dx
+ (screen
->getRect().width() - 1), dy
,
3067 frame
.rect
.width(), frame
.rect
.height());
3070 XWarpPointer(blackbox
->getXDisplay(), None
,
3071 screen
->getRootWindow(), 0, 0, 0, 0,
3074 configure(dx
- (screen
->getRect().width() - 1), dy
,
3075 frame
.rect
.width(), frame
.rect
.height());
3078 beginMove(dest_x
, y_root
);
3083 // how much resistance to edges to provide
3084 const int resistance_size
= screen
->getEdgeSnapThreshold();
3086 if (resistance_size
> 0) {
3089 // the amount of space away from the edge to provide resistance
3090 const int resistance_offset
= screen
->getEdgeSnapThreshold();
3093 const int wleft
= dx
,
3094 wright
= dx
+ frame
.rect
.width() - 1,
3096 wbottom
= dy
+ frame
.rect
.height() - 1;
3098 if (screen
->getWindowToWindowSnap()) {
3099 Workspace
*w
= screen
->getWorkspace(getWorkspaceNumber());
3102 // add windows on the workspace to the rect list
3103 const BlackboxWindowList
& stack_list
= w
->getStackingList();
3104 BlackboxWindowList::const_iterator st_it
, st_end
= stack_list
.end();
3105 for (st_it
= stack_list
.begin(); st_it
!= st_end
; ++st_it
)
3106 rectlist
.push_back( (*st_it
)->frameRect() );
3108 // add the toolbar and the slit to the rect list.
3109 // (only if they are not hidden)
3110 Toolbar
*tbar
= screen
->getToolbar();
3111 Slit
*slit
= screen
->getSlit();
3112 Rect tbar_rect
, slit_rect
;
3113 unsigned int bwidth
= screen
->getBorderWidth() * 2;
3115 if (! (screen
->doHideToolbar() || tbar
->isHidden())) {
3116 tbar_rect
.setRect(tbar
->getX(), tbar
->getY(), tbar
->getWidth() + bwidth
,
3117 tbar
->getHeight() + bwidth
);
3118 rectlist
.push_back(tbar_rect
);
3121 if (! slit
->isHidden()) {
3122 slit_rect
.setRect(slit
->getX(), slit
->getY(), slit
->getWidth() + bwidth
,
3123 slit
->getHeight() + bwidth
);
3124 rectlist
.push_back(slit_rect
);
3127 RectList::const_iterator it
, end
= rectlist
.end();
3128 for (it
= rectlist
.begin(); it
!= end
; ++it
) {
3129 bool snapped
= False
;
3131 const Rect
&winrect
= *it
;
3132 int dleft
= wright
- winrect
.left(),
3133 dright
= wleft
- winrect
.right(),
3134 dtop
= wbottom
- winrect
.top(),
3135 dbottom
= wtop
- winrect
.bottom();
3137 // if the windows are in the same plane vertically
3138 if (wtop
>= (signed)(winrect
.y() - frame
.rect
.height() + 1) &&
3139 wtop
< (signed)(winrect
.y() + winrect
.height() - 1)) {
3141 // snap left of other window?
3142 if (dleft
< resistance_size
&& dleft
> dright
) {
3143 dx
= winrect
.left() - frame
.rect
.width();
3146 // snap right of other window?
3147 else if (dright
< resistance_size
) {
3148 dx
= winrect
.right() + 1;
3153 if (screen
->getWindowCornerSnap()) {
3154 // try corner-snap to its other sides
3155 dtop
= abs(wtop
- winrect
.top());
3156 dbottom
= abs(wbottom
- winrect
.bottom());
3157 if (dtop
< resistance_size
&& dtop
<= dbottom
)
3159 else if (dbottom
< resistance_size
)
3160 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
3167 // if the windows are on the same plane horizontally
3168 if (wleft
>= (signed)(winrect
.x() - frame
.rect
.width() + 1) &&
3169 wleft
< (signed)(winrect
.x() + winrect
.width() - 1)) {
3171 // snap top of other window?
3172 if (dtop
< resistance_size
&& dtop
> dbottom
) {
3173 dy
= winrect
.top() - frame
.rect
.height();
3176 // snap bottom of other window?
3177 else if (dbottom
< resistance_size
) {
3178 dy
= winrect
.bottom() + 1;
3183 if (screen
->getWindowCornerSnap()) {
3184 // try corner-snap to its other sides
3185 dleft
= abs(wleft
- winrect
.left());
3186 dright
= abs(wright
- winrect
.right());
3187 if (dleft
< resistance_size
&& dleft
<= dright
)
3188 dx
= winrect
.left();
3189 else if (dright
< resistance_size
)
3190 dx
= winrect
.right() - frame
.rect
.width() + 1;
3199 // snap to the screen edges (and screen boundaries for xinerama)
3203 if (screen
->isXineramaActive() && blackbox
->doXineramaSnapping()) {
3204 rectlist
.insert(rectlist
.begin(),
3205 screen
->getXineramaAreas().begin(),
3206 screen
->getXineramaAreas().end());
3209 rectlist
.push_back(screen
->getRect());
3211 RectList::const_iterator it
, end
= rectlist
.end();
3212 for (it
= rectlist
.begin(); it
!= end
; ++it
) {
3213 const Rect
&srect
= *it
;
3215 // if we're not in the rectangle then don't snap to it.
3216 if (! srect
.intersects(Rect(wleft
, wtop
, frame
.rect
.width(),
3217 frame
.rect
.height())))
3220 int dleft
= wleft
- srect
.left(),
3221 dright
= wright
- srect
.right(),
3222 dtop
= wtop
- srect
.top(),
3223 dbottom
= wbottom
- srect
.bottom();
3226 if (dleft
< resistance_size
&& dleft
> dright
)
3229 else if (dright
< resistance_size
)
3230 dx
= srect
.right() - frame
.rect
.width() + 1;
3233 if (dtop
< resistance_size
&& dtop
> dbottom
)
3236 else if (dbottom
< resistance_size
)
3237 dy
= srect
.bottom() - frame
.rect
.height() + 1;
3241 if (screen
->doOpaqueMove()) {
3242 configure(dx
, dy
, frame
.rect
.width(), frame
.rect
.height());
3244 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3248 frame
.changing
.width() - 1,
3249 frame
.changing
.height() - 1);
3251 frame
.changing
.setPos(dx
, dy
);
3253 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3257 frame
.changing
.width() - 1,
3258 frame
.changing
.height() - 1);
3261 screen
->showPosition(dx
, dy
);
3265 void BlackboxWindow::endMove(void) {
3266 assert(flags
.moving
);
3267 assert(blackbox
->getChangingWindow() == this);
3269 flags
.moving
= False
;
3270 blackbox
->setChangingWindow(0);
3272 if (! screen
->doOpaqueMove()) {
3273 /* when drawing the rubber band, we need to make sure we only draw inside
3274 * the frame... frame.changing_* contain the new coords for the window,
3275 * so we need to subtract 1 from changing_w/changing_h every where we
3276 * draw the rubber band (for both moving and resizing)
3278 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3279 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3280 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3281 XUngrabServer(blackbox
->getXDisplay());
3283 configure(frame
.changing
.x(), frame
.changing
.y(),
3284 frame
.changing
.width(), frame
.changing
.height());
3286 configure(frame
.rect
.x(), frame
.rect
.y(),
3287 frame
.rect
.width(), frame
.rect
.height());
3289 screen
->hideGeometry();
3291 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3293 // if there are any left over motions from the move, drop them now
3294 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3296 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3301 void BlackboxWindow::beginResize(int x_root
, int y_root
, Corner dir
) {
3302 assert(! (flags
.resizing
|| flags
.moving
));
3305 Only one window can be moved/resized at a time. If another window is already
3306 being moved or resized, then stop it before whating to work with this one.
3308 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3309 if (changing
&& changing
!= this) {
3310 if (changing
->flags
.moving
)
3311 changing
->endMove();
3312 else // if (changing->flags.resizing)
3313 changing
->endResize();
3321 switch (resize_dir
) {
3324 cursor
= blackbox
->getLowerLeftAngleCursor();
3329 cursor
= blackbox
->getLowerRightAngleCursor();
3333 anchor
= BottomRight
;
3334 cursor
= blackbox
->getUpperLeftAngleCursor();
3338 anchor
= BottomLeft
;
3339 cursor
= blackbox
->getUpperRightAngleCursor();
3343 assert(false); // unhandled Corner
3344 return; // unreachable, for the compiler
3347 XGrabServer(blackbox
->getXDisplay());
3348 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3349 PointerMotionMask
| ButtonReleaseMask
,
3350 GrabModeAsync
, GrabModeAsync
, None
, cursor
, CurrentTime
);
3352 flags
.resizing
= True
;
3353 blackbox
->setChangingWindow(this);
3356 frame
.changing
= frame
.rect
;
3358 constrain(anchor
, &gw
, &gh
);
3360 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3361 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3362 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3364 screen
->showGeometry(gw
, gh
);
3366 frame
.grab_x
= x_root
;
3367 frame
.grab_y
= y_root
;
3371 void BlackboxWindow::doResize(int x_root
, int y_root
) {
3372 assert(flags
.resizing
);
3373 assert(blackbox
->getChangingWindow() == this);
3375 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3376 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3377 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3382 switch (resize_dir
) {
3385 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3386 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3390 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3391 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3394 anchor
= BottomRight
;
3395 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3396 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3399 anchor
= BottomLeft
;
3400 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3401 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3405 assert(false); // unhandled Corner
3406 return; // unreachable, for the compiler
3409 constrain(anchor
, &gw
, &gh
);
3411 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3412 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3413 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3415 screen
->showGeometry(gw
, gh
);
3419 void BlackboxWindow::endResize(void) {
3420 assert(flags
.resizing
);
3421 assert(blackbox
->getChangingWindow() == this);
3423 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3424 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3425 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3426 XUngrabServer(blackbox
->getXDisplay());
3428 // unset maximized state after resized when fully maximized
3429 if (flags
.maximized
== 1)
3432 flags
.resizing
= False
;
3433 blackbox
->setChangingWindow(0);
3435 configure(frame
.changing
.x(), frame
.changing
.y(),
3436 frame
.changing
.width(), frame
.changing
.height());
3437 screen
->hideGeometry();
3439 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3441 // if there are any left over motions from the resize, drop them now
3442 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3444 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3449 void BlackboxWindow::motionNotifyEvent(const XMotionEvent
*me
) {
3451 fprintf(stderr
, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n",
3456 doMove(me
->x_root
, me
->y_root
);
3457 } else if (flags
.resizing
) {
3458 doResize(me
->x_root
, me
->y_root
);
3460 if (!flags
.resizing
&& me
->state
& Button1Mask
&& (functions
& Func_Move
) &&
3461 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3462 frame
.handle
== me
->window
|| frame
.window
== me
->window
)) {
3463 beginMove(me
->x_root
, me
->y_root
);
3464 } else if ((functions
& Func_Resize
) &&
3465 (me
->state
& Button1Mask
&& (me
->window
== frame
.right_grip
||
3466 me
->window
== frame
.left_grip
)) ||
3467 (me
->state
& Button3Mask
&& me
->state
& ModMask
&&
3468 me
->window
== frame
.window
)) {
3469 unsigned int zones
= screen
->getResizeZones();
3472 if (me
->window
== frame
.left_grip
) {
3473 corner
= BottomLeft
;
3474 } else if (me
->window
== frame
.right_grip
|| zones
== 1) {
3475 corner
= BottomRight
;
3478 bool left
= (me
->x_root
- frame
.rect
.x() <=
3479 static_cast<signed>(frame
.rect
.width() / 2));
3482 else // (zones == 4)
3483 top
= (me
->y_root
- frame
.rect
.y() <=
3484 static_cast<signed>(frame
.rect
.height() / 2));
3485 corner
= (top
? (left
? TopLeft
: TopRight
) :
3486 (left
? BottomLeft
: BottomRight
));
3489 beginResize(me
->x_root
, me
->y_root
, corner
);
3496 void BlackboxWindow::shapeEvent(XShapeEvent
*) {
3497 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
3504 bool BlackboxWindow::validateClient(void) const {
3505 XSync(blackbox
->getXDisplay(), False
);
3508 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3509 DestroyNotify
, &e
) ||
3510 XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3512 XPutBackEvent(blackbox
->getXDisplay(), &e
);
3521 void BlackboxWindow::restore(bool remap
) {
3522 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeDelete
);
3523 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
3524 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, NoEventMask
);
3526 // do not leave a shaded window as an icon unless it was an icon
3527 if (flags
.shaded
&& ! flags
.iconic
)
3528 setState(NormalState
);
3530 restoreGravity(client
.rect
);
3532 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
3533 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
3535 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, client
.old_bw
);
3538 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3539 ReparentNotify
, &ev
)) {
3542 // according to the ICCCM - if the client doesn't reparent to
3543 // root, then we have to do it for them
3544 XReparentWindow(blackbox
->getXDisplay(), client
.window
,
3545 screen
->getRootWindow(),
3546 client
.rect
.x(), client
.rect
.y());
3549 if (remap
) XMapWindow(blackbox
->getXDisplay(), client
.window
);
3553 // timer for autoraise
3554 void BlackboxWindow::timeout(void) {
3555 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3559 void BlackboxWindow::changeBlackboxHints(const BlackboxHints
*net
) {
3560 if ((net
->flags
& AttribShaded
) &&
3561 ((blackbox_attrib
.attrib
& AttribShaded
) !=
3562 (net
->attrib
& AttribShaded
)))
3565 if (flags
.visible
&& // watch out for requests when we can not be seen
3566 (net
->flags
& (AttribMaxVert
| AttribMaxHoriz
)) &&
3567 ((blackbox_attrib
.attrib
& (AttribMaxVert
| AttribMaxHoriz
)) !=
3568 (net
->attrib
& (AttribMaxVert
| AttribMaxHoriz
)))) {
3569 if (flags
.maximized
) {
3574 if ((net
->flags
& AttribMaxHoriz
) && (net
->flags
& AttribMaxVert
))
3575 button
= ((net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0);
3576 else if (net
->flags
& AttribMaxVert
)
3577 button
= ((net
->attrib
& AttribMaxVert
) ? 2 : 0);
3578 else if (net
->flags
& AttribMaxHoriz
)
3579 button
= ((net
->attrib
& AttribMaxHoriz
) ? 3 : 0);
3585 if ((net
->flags
& AttribOmnipresent
) &&
3586 ((blackbox_attrib
.attrib
& AttribOmnipresent
) !=
3587 (net
->attrib
& AttribOmnipresent
)))
3590 if ((net
->flags
& AttribWorkspace
) &&
3591 (blackbox_attrib
.workspace
!= net
->workspace
)) {
3592 screen
->reassociateWindow(this, net
->workspace
, True
);
3594 if (screen
->getCurrentWorkspaceID() != net
->workspace
) {
3598 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3602 if (net
->flags
& AttribDecoration
) {
3603 switch (net
->decoration
) {
3611 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Iconify
;
3613 decorations
= ((functions
& Func_Resize
) && !isTransient() ?
3614 decorations
| Decor_Handle
:
3615 decorations
&= ~Decor_Handle
);
3616 decorations
= (functions
& Func_Maximize
?
3617 decorations
| Decor_Maximize
:
3618 decorations
&= ~Decor_Maximize
);
3623 decorations
|= Decor_Titlebar
| Decor_Iconify
;
3624 decorations
&= ~(Decor_Border
| Decor_Handle
);
3626 decorations
= (functions
& Func_Maximize
?
3627 decorations
| Decor_Maximize
:
3628 decorations
&= ~Decor_Maximize
);
3633 decorations
|= Decor_Titlebar
;
3634 decorations
&= ~(Decor_Iconify
| Decor_Border
);
3636 decorations
= ((functions
& Func_Resize
) && !isTransient() ?
3637 decorations
| Decor_Handle
:
3638 decorations
&= ~Decor_Handle
);
3639 decorations
= (functions
& Func_Maximize
?
3640 decorations
| Decor_Maximize
:
3641 decorations
&= ~Decor_Maximize
);
3646 // we can not be shaded if we lack a titlebar
3647 if (flags
.shaded
&& ! (decorations
& Decor_Titlebar
))
3650 if (flags
.visible
&& frame
.window
) {
3651 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
3652 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
3656 setState(current_state
);
3662 * Set the sizes of all components of the window frame
3663 * (the window decorations).
3664 * These values are based upon the current style settings and the client
3665 * window's dimensions.
3667 void BlackboxWindow::upsize(void) {
3668 frame
.bevel_w
= screen
->getBevelWidth();
3670 if (decorations
& Decor_Border
) {
3671 frame
.border_w
= screen
->getBorderWidth();
3672 if (! isTransient())
3673 frame
.mwm_border_w
= screen
->getFrameWidth();
3675 frame
.mwm_border_w
= 0;
3677 frame
.mwm_border_w
= frame
.border_w
= 0;
3680 if (decorations
& Decor_Titlebar
) {
3681 // the height of the titlebar is based upon the height of the font being
3682 // used to display the window's title
3683 WindowStyle
*style
= screen
->getWindowStyle();
3684 frame
.title_h
= style
->font
->height() + (frame
.bevel_w
* 2) + 2;
3686 frame
.label_h
= frame
.title_h
- (frame
.bevel_w
* 2);
3687 frame
.button_w
= (frame
.label_h
- 2);
3689 // set the top frame margin
3690 frame
.margin
.top
= frame
.border_w
+ frame
.title_h
+
3691 frame
.border_w
+ frame
.mwm_border_w
;
3697 // set the top frame margin
3698 frame
.margin
.top
= frame
.border_w
+ frame
.mwm_border_w
;
3701 // set the left/right frame margin
3702 frame
.margin
.left
= frame
.margin
.right
= frame
.border_w
+ frame
.mwm_border_w
;
3704 if (decorations
& Decor_Handle
) {
3705 frame
.grip_w
= frame
.button_w
* 2;
3706 frame
.handle_h
= screen
->getHandleWidth();
3708 // set the bottom frame margin
3709 frame
.margin
.bottom
= frame
.border_w
+ frame
.handle_h
+
3710 frame
.border_w
+ frame
.mwm_border_w
;
3715 // set the bottom frame margin
3716 frame
.margin
.bottom
= frame
.border_w
+ frame
.mwm_border_w
;
3720 We first get the normal dimensions and use this to define the inside_w/h
3721 then we modify the height if shading is in effect.
3722 If the shade state is not considered then frame.rect gets reset to the
3723 normal window size on a reconfigure() call resulting in improper
3724 dimensions appearing in move/resize and other events.
3727 height
= client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
,
3728 width
= client
.rect
.width() + frame
.margin
.left
+ frame
.margin
.right
;
3730 frame
.inside_w
= width
- (frame
.border_w
* 2);
3731 frame
.inside_h
= height
- (frame
.border_w
* 2);
3734 height
= frame
.title_h
+ (frame
.border_w
* 2);
3735 frame
.rect
.setSize(width
, height
);
3740 * Calculate the size of the client window and constrain it to the
3741 * size specified by the size hints of the client window.
3743 * The logical width and height are placed into pw and ph, if they
3744 * are non-zero. Logical size refers to the users perception of
3745 * the window size (for example an xterm resizes in cells, not in pixels).
3747 * The physical geometry is placed into frame.changing_{x,y,width,height}.
3748 * Physical geometry refers to the geometry of the window in pixels.
3750 void BlackboxWindow::constrain(Corner anchor
, int *pw
, int *ph
) {
3751 // frame.changing represents the requested frame size, we need to
3752 // strip the frame margin off and constrain the client size
3753 frame
.changing
.setCoords(frame
.changing
.left() + frame
.margin
.left
,
3754 frame
.changing
.top() + frame
.margin
.top
,
3755 frame
.changing
.right() - frame
.margin
.right
,
3756 frame
.changing
.bottom() - frame
.margin
.bottom
);
3758 int dw
= frame
.changing
.width(), dh
= frame
.changing
.height(),
3759 base_width
= (client
.base_width
) ? client
.base_width
: client
.min_width
,
3760 base_height
= (client
.base_height
) ? client
.base_height
:
3764 if (dw
< static_cast<signed>(client
.min_width
)) dw
= client
.min_width
;
3765 if (dh
< static_cast<signed>(client
.min_height
)) dh
= client
.min_height
;
3766 if (dw
> static_cast<signed>(client
.max_width
)) dw
= client
.max_width
;
3767 if (dh
> static_cast<signed>(client
.max_height
)) dh
= client
.max_height
;
3770 dw
/= client
.width_inc
;
3772 dh
/= client
.height_inc
;
3775 if (client
.width_inc
== 1)
3776 *pw
= dw
+ base_width
;
3781 if (client
.height_inc
== 1)
3782 *ph
= dh
+ base_height
;
3787 dw
*= client
.width_inc
;
3789 dh
*= client
.height_inc
;
3792 frame
.changing
.setSize(dw
, dh
);
3794 // add the frame margin back onto frame.changing
3795 frame
.changing
.setCoords(frame
.changing
.left() - frame
.margin
.left
,
3796 frame
.changing
.top() - frame
.margin
.top
,
3797 frame
.changing
.right() + frame
.margin
.right
,
3798 frame
.changing
.bottom() + frame
.margin
.bottom
);
3800 // move frame.changing to the specified anchor
3808 dx
= frame
.rect
.right() - frame
.changing
.right();
3812 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3816 dx
= frame
.rect
.right() - frame
.changing
.right();
3817 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3821 assert(false); // unhandled corner
3823 frame
.changing
.setPos(frame
.changing
.x() + dx
, frame
.changing
.y() + dy
);
3827 void WindowStyle::doJustify(const std::string
&text
, int &start_pos
,
3828 unsigned int max_length
,
3829 unsigned int modifier
) const {
3830 size_t text_len
= text
.size();
3831 unsigned int length
;
3834 length
= font
->measureString(string(text
, 0, text_len
)) + modifier
;
3835 } while (length
> max_length
&& text_len
-- > 0);
3839 start_pos
+= max_length
- length
;
3843 start_pos
+= (max_length
- length
) / 2;
3853 BWindowGroup::BWindowGroup(Blackbox
*b
, Window _group
)
3854 : blackbox(b
), group(_group
) {
3855 XWindowAttributes wattrib
;
3856 if (! XGetWindowAttributes(blackbox
->getXDisplay(), group
, &wattrib
)) {
3857 // group window doesn't seem to exist anymore
3862 XSelectInput(blackbox
->getXDisplay(), group
,
3863 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
3865 blackbox
->saveGroupSearch(group
, this);
3869 BWindowGroup::~BWindowGroup(void) {
3870 blackbox
->removeGroupSearch(group
);
3875 BWindowGroup::find(BScreen
*screen
, bool allow_transients
) const {
3876 BlackboxWindow
*ret
= blackbox
->getFocusedWindow();
3878 // does the focus window match (or any transient_fors)?
3880 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3881 if (ret
->isTransient() && allow_transients
) break;
3882 else if (! ret
->isTransient()) break;
3885 ret
= ret
->getTransientFor();
3888 if (ret
) return ret
;
3890 // the focus window didn't match, look in the group's window list
3891 BlackboxWindowList::const_iterator it
, end
= windowList
.end();
3892 for (it
= windowList
.begin(); it
!= end
; ++it
) {
3894 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3895 if (ret
->isTransient() && allow_transients
) break;
3896 else if (! ret
->isTransient()) break;