1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2 // Window.cc for Blackbox - an X11 Window manager
3 // Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry <shaleh at debian.org>
4 // Copyright (c) 1997 - 2000, 2002 Brad Hughes <bhughes at trolltech.com>
6 // Permission is hereby granted, free of charge, to any person obtaining a
7 // copy of this software and associated documentation files (the "Software"),
8 // to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 // and/or sell copies of the Software, and to permit persons to whom the
11 // Software is furnished to do so, subject to the following conditions:
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 // DEALINGS IN THE SOFTWARE.
25 # include "../config.h"
26 #endif // HAVE_CONFIG_H
29 #include <X11/Xatom.h>
30 #include <X11/keysym.h>
34 #endif // HAVE_STRING_H
39 # endif // HAVE_STDIO_H
46 #include "blackbox.hh"
48 #include "Iconmenu.hh"
54 #include "Windowmenu.hh"
55 #include "Workspace.hh"
61 * Initializes the class with default values/the window's set initial values.
63 BlackboxWindow::BlackboxWindow(Blackbox
*b
, Window w
, BScreen
*s
) {
64 // fprintf(stderr, "BlackboxWindow size: %d bytes\n",
65 // sizeof(BlackboxWindow));
68 fprintf(stderr
, "BlackboxWindow::BlackboxWindow(): creating 0x%lx\n", w
);
72 set timer to zero... it is initialized properly later, so we check
73 if timer is zero in the destructor, and assume that the window is not
74 fully constructed if timer is zero...
80 xatom
= blackbox
->getXAtom();
82 if (! validateClient()) {
87 // set the eventmask early in the game so that we make sure we get
88 // all the events we are interested in
89 XSetWindowAttributes attrib_set
;
90 attrib_set
.event_mask
= PropertyChangeMask
| FocusChangeMask
|
92 attrib_set
.do_not_propagate_mask
= ButtonPressMask
| ButtonReleaseMask
|
94 XChangeWindowAttributes(blackbox
->getXDisplay(), client
.window
,
95 CWEventMask
|CWDontPropagate
, &attrib_set
);
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 flags
.moving
= flags
.resizing
= flags
.shaded
= flags
.visible
=
112 flags
.iconic
= flags
.focused
= flags
.stuck
= flags
.modal
=
113 flags
.send_focus_message
= flags
.shaped
= flags
.skip_taskbar
=
114 flags
.skip_pager
= flags
.fullscreen
= False
;
117 blackbox_attrib
.workspace
= window_number
= BSENTINEL
;
119 blackbox_attrib
.flags
= blackbox_attrib
.attrib
= blackbox_attrib
.stack
120 = blackbox_attrib
.decoration
= 0l;
121 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
122 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
125 frame
.window
= frame
.plate
= frame
.title
= frame
.handle
= None
;
126 frame
.close_button
= frame
.iconify_button
= frame
.maximize_button
= None
;
127 frame
.right_grip
= frame
.left_grip
= None
;
129 frame
.ulabel_pixel
= frame
.flabel_pixel
= frame
.utitle_pixel
=
130 frame
.ftitle_pixel
= frame
.uhandle_pixel
= frame
.fhandle_pixel
=
131 frame
.ubutton_pixel
= frame
.fbutton_pixel
= frame
.pbutton_pixel
=
132 frame
.uborder_pixel
= frame
.fborder_pixel
= frame
.ugrip_pixel
=
133 frame
.fgrip_pixel
= 0;
134 frame
.utitle
= frame
.ftitle
= frame
.uhandle
= frame
.fhandle
= None
;
135 frame
.ulabel
= frame
.flabel
= frame
.ubutton
= frame
.fbutton
= None
;
136 frame
.pbutton
= frame
.ugrip
= frame
.fgrip
= decorations
;
138 decorations
= Decor_Titlebar
| Decor_Border
| Decor_Handle
|
139 Decor_Iconify
| Decor_Maximize
;
140 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
142 client
.wm_hint_flags
= client
.normal_hint_flags
= 0;
143 client
.transient_for
= 0;
146 get the initial size and location of client window (relative to the
147 _root window_). This position is the reference point used with the
148 window's gravity to find the window's initial position.
150 client
.rect
.setRect(wattrib
.x
, wattrib
.y
, wattrib
.width
, wattrib
.height
);
151 client
.old_bw
= wattrib
.border_width
;
154 lastButtonPressTime
= 0;
156 timer
= new BTimer(blackbox
, this);
157 timer
->setTimeout(blackbox
->getAutoRaiseDelay());
159 if (! getBlackboxHints()) {
164 // get size, aspect, minimum/maximum size and other hints set by the
170 if (client
.initial_state
== WithdrawnState
) {
171 screen
->getSlit()->addClient(client
.window
);
176 if (isKDESystrayWindow()) {
177 screen
->addSystrayWindow(client
.window
);
182 frame
.window
= createToplevelWindow();
183 frame
.plate
= createChildWindow(frame
.window
);
184 associateClientWindow();
186 blackbox
->saveWindowSearch(frame
.window
, this);
187 blackbox
->saveWindowSearch(frame
.plate
, this);
188 blackbox
->saveWindowSearch(client
.window
, this);
190 screen
->addStrut(&client
.strut
);
193 // determine if this is a transient window
196 // determine the window's type, so we can decide its decorations and
197 // functionality, or if we should not manage it at all
200 // adjust the window decorations/behavior based on the window type
201 switch (window_type
) {
203 // desktop windows are not managed by us, we just make sure they stay on the
208 // docks (such as kicker) cannot be moved, and appear on all workspaces
209 functions
&= ~(Func_Move
);
214 // these windows have minimal decorations, only a titlebar, and cannot
215 // be resized or iconified
216 decorations
&= ~(Decor_Maximize
| Decor_Handle
| Decor_Border
|
218 functions
&= ~(Func_Resize
| Func_Maximize
| Func_Iconify
);
222 // splash screens have no functionality or decorations, they are left up
223 // to the application which created them
229 // dialogs cannot be maximized, and don't display a handle
230 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
231 functions
&= ~Func_Maximize
;
235 // normal windows retain all of the possible decorations and functionality
239 // further adjeust the window's decorations/behavior based on window sizes
240 if ((client
.normal_hint_flags
& PMinSize
) &&
241 (client
.normal_hint_flags
& PMaxSize
) &&
242 client
.max_width
<= client
.min_width
&&
243 client
.max_height
<= client
.min_height
) {
244 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
245 functions
&= ~(Func_Resize
| Func_Maximize
);
251 bool place_window
= True
;
252 if (blackbox
->isStartup() || isTransient() ||
253 client
.normal_hint_flags
& (PPosition
|USPosition
)) {
257 if (blackbox
->isStartup() ||
258 client
.rect
.intersects(screen
->availableArea()))
259 place_window
= False
;
262 if (decorations
& Decor_Titlebar
)
265 if (decorations
& Decor_Handle
)
269 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
274 if ((! screen
->isSloppyFocus()) || screen
->doClickRaise()) {
275 // grab button 1 for changing focus/raising
276 blackbox
->grabButton(Button1
, 0, frame
.plate
, True
, ButtonPressMask
,
277 GrabModeSync
, GrabModeSync
, None
, None
);
280 if (functions
& Func_Move
)
281 blackbox
->grabButton(Button1
, Mod1Mask
, frame
.window
, True
,
282 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
283 GrabModeAsync
, frame
.window
,
284 blackbox
->getMoveCursor());
285 blackbox
->grabButton(Button2
, Mod1Mask
, frame
.window
, True
,
286 ButtonReleaseMask
, GrabModeAsync
, GrabModeAsync
,
288 if (functions
& Func_Resize
)
289 blackbox
->grabButton(Button3
, Mod1Mask
, frame
.window
, True
,
290 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
292 blackbox
->getLowerRightAngleCursor());
297 if (decorations
& Decor_Titlebar
)
298 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
299 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
301 windowmenu
= new Windowmenu(this);
303 if (blackbox_attrib
.workspace
>= screen
->getWorkspaceCount())
304 screen
->getCurrentWorkspace()->addWindow(this, place_window
);
306 screen
->getWorkspace(blackbox_attrib
.workspace
)->
307 addWindow(this, place_window
);
309 if (! place_window
) {
310 // don't need to call configure if we are letting the workspace
312 configure(frame
.rect
.x(), frame
.rect
.y(),
313 frame
.rect
.width(), frame
.rect
.height());
316 // preserve the window's initial state on first map, and its current state
319 if (client
.wm_hint_flags
& StateHint
)
320 current_state
= client
.initial_state
;
322 current_state
= NormalState
;
325 // get sticky state from our parent window if we've got one
326 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
327 client
.transient_for
->isStuck() != flags
.stuck
)
331 flags
.shaded
= False
;
335 Because the iconic'ness of shaded windows is lost, we need to set the
336 state to NormalState so that shaded windows on other workspaces will not
337 get shown on the first workspace.
338 At this point in the life of a window, current_state should only be set
339 to IconicState if the window was an *icon*, not if it was shaded.
341 current_state
= NormalState
;
349 if (flags
.maximized
&& (functions
& Func_Maximize
)) {
354 When the window is mapped (and also when its attributes are restored), the
355 current_state that was set here will be used.
356 It is set to Normal if the window is to be mapped or it is set to Iconic
357 if the window is to be iconified.
358 *Note* that for sticky windows, the same rules apply here, they are in
359 fact never set to Iconic since there is no way for us to tell if a sticky
360 window was iconified previously.
367 BlackboxWindow::~BlackboxWindow(void) {
369 fprintf(stderr
, "BlackboxWindow::~BlackboxWindow: destroying 0x%lx\n",
373 if (! timer
) // window not managed...
376 screen
->removeStrut(&client
.strut
);
377 screen
->updateAvailableArea();
379 // We don't need to worry about resizing because resizing always grabs the X
380 // server. This should only ever happen if using opaque moving.
388 if (client
.window_group
) {
389 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
390 if (group
) group
->removeWindow(this);
393 // remove ourselves from our transient_for
395 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
396 client
.transient_for
->client
.transientList
.remove(this);
398 client
.transient_for
= (BlackboxWindow
*) 0;
401 if (client
.transientList
.size() > 0) {
402 // reset transient_for for all transients
403 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
404 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
405 (*it
)->client
.transient_for
= (BlackboxWindow
*) 0;
416 blackbox
->removeWindowSearch(frame
.plate
);
417 XDestroyWindow(blackbox
->getXDisplay(), frame
.plate
);
421 blackbox
->removeWindowSearch(frame
.window
);
422 XDestroyWindow(blackbox
->getXDisplay(), frame
.window
);
425 blackbox
->removeWindowSearch(client
.window
);
430 * Creates a new top level window, with a given location, size, and border
432 * Returns: the newly created window
434 Window
BlackboxWindow::createToplevelWindow(void) {
435 XSetWindowAttributes attrib_create
;
436 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
| CWColormap
|
437 CWOverrideRedirect
| CWEventMask
;
439 attrib_create
.background_pixmap
= None
;
440 attrib_create
.colormap
= screen
->getColormap();
441 attrib_create
.override_redirect
= True
;
442 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
443 ButtonMotionMask
| EnterWindowMask
;
445 return XCreateWindow(blackbox
->getXDisplay(), screen
->getRootWindow(),
446 -1, -1, 1, 1, frame
.border_w
, screen
->getDepth(),
447 InputOutput
, screen
->getVisual(), create_mask
,
453 * Creates a child window, and optionally associates a given cursor with
456 Window
BlackboxWindow::createChildWindow(Window parent
, Cursor cursor
) {
457 XSetWindowAttributes attrib_create
;
458 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
|
461 attrib_create
.background_pixmap
= None
;
462 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
463 ButtonMotionMask
| ExposureMask
;
466 create_mask
|= CWCursor
;
467 attrib_create
.cursor
= cursor
;
470 return XCreateWindow(blackbox
->getXDisplay(), parent
, 0, 0, 1, 1, 0,
471 screen
->getDepth(), InputOutput
, screen
->getVisual(),
472 create_mask
, &attrib_create
);
476 void BlackboxWindow::associateClientWindow(void) {
477 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, 0);
481 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeInsert
);
483 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, SubstructureRedirectMask
);
485 XGrabServer(blackbox
->getXDisplay());
486 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
487 XReparentWindow(blackbox
->getXDisplay(), client
.window
, frame
.plate
, 0, 0);
488 XSelectInput(blackbox
->getXDisplay(), client
.window
,
489 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
490 XUngrabServer(blackbox
->getXDisplay());
492 XRaiseWindow(blackbox
->getXDisplay(), frame
.plate
);
493 XMapSubwindows(blackbox
->getXDisplay(), frame
.plate
);
497 if (blackbox
->hasShapeExtensions()) {
498 XShapeSelectInput(blackbox
->getXDisplay(), client
.window
,
505 XShapeQueryExtents(blackbox
->getXDisplay(), client
.window
, &shaped
,
506 &foo
, &foo
, &ufoo
, &ufoo
, &foo
, &foo
, &foo
,
508 flags
.shaped
= shaped
;
514 void BlackboxWindow::decorate(void) {
517 texture
= &(screen
->getWindowStyle()->b_focus
);
518 frame
.fbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
521 frame
.fbutton_pixel
= texture
->color().pixel();
523 texture
= &(screen
->getWindowStyle()->b_unfocus
);
524 frame
.ubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
527 frame
.ubutton_pixel
= texture
->color().pixel();
529 texture
= &(screen
->getWindowStyle()->b_pressed
);
530 frame
.pbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
533 frame
.pbutton_pixel
= texture
->color().pixel();
535 if (decorations
& Decor_Titlebar
) {
536 texture
= &(screen
->getWindowStyle()->t_focus
);
537 frame
.ftitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
540 frame
.ftitle_pixel
= texture
->color().pixel();
542 texture
= &(screen
->getWindowStyle()->t_unfocus
);
543 frame
.utitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
546 frame
.utitle_pixel
= texture
->color().pixel();
548 XSetWindowBorder(blackbox
->getXDisplay(), frame
.title
,
549 screen
->getBorderColor()->pixel());
554 if (decorations
& Decor_Border
) {
555 frame
.fborder_pixel
= screen
->getWindowStyle()->f_focus
.pixel();
556 frame
.uborder_pixel
= screen
->getWindowStyle()->f_unfocus
.pixel();
557 blackbox_attrib
.flags
|= AttribDecoration
;
558 blackbox_attrib
.decoration
= DecorNormal
;
560 blackbox_attrib
.flags
|= AttribDecoration
;
561 blackbox_attrib
.decoration
= DecorNone
;
564 if (decorations
& Decor_Handle
) {
565 texture
= &(screen
->getWindowStyle()->h_focus
);
566 frame
.fhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
569 frame
.fhandle_pixel
= texture
->color().pixel();
571 texture
= &(screen
->getWindowStyle()->h_unfocus
);
572 frame
.uhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
575 frame
.uhandle_pixel
= texture
->color().pixel();
577 texture
= &(screen
->getWindowStyle()->g_focus
);
578 frame
.fgrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.fgrip
);
580 frame
.fgrip_pixel
= texture
->color().pixel();
582 texture
= &(screen
->getWindowStyle()->g_unfocus
);
583 frame
.ugrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.ugrip
);
585 frame
.ugrip_pixel
= texture
->color().pixel();
587 XSetWindowBorder(blackbox
->getXDisplay(), frame
.handle
,
588 screen
->getBorderColor()->pixel());
589 XSetWindowBorder(blackbox
->getXDisplay(), frame
.left_grip
,
590 screen
->getBorderColor()->pixel());
591 XSetWindowBorder(blackbox
->getXDisplay(), frame
.right_grip
,
592 screen
->getBorderColor()->pixel());
595 XSetWindowBorder(blackbox
->getXDisplay(), frame
.window
,
596 screen
->getBorderColor()->pixel());
600 void BlackboxWindow::decorateLabel(void) {
603 texture
= &(screen
->getWindowStyle()->l_focus
);
604 frame
.flabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.flabel
);
606 frame
.flabel_pixel
= texture
->color().pixel();
608 texture
= &(screen
->getWindowStyle()->l_unfocus
);
609 frame
.ulabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.ulabel
);
611 frame
.ulabel_pixel
= texture
->color().pixel();
615 void BlackboxWindow::createHandle(void) {
616 frame
.handle
= createChildWindow(frame
.window
);
617 blackbox
->saveWindowSearch(frame
.handle
, this);
620 createChildWindow(frame
.handle
, blackbox
->getLowerLeftAngleCursor());
621 blackbox
->saveWindowSearch(frame
.left_grip
, this);
624 createChildWindow(frame
.handle
, blackbox
->getLowerRightAngleCursor());
625 blackbox
->saveWindowSearch(frame
.right_grip
, this);
629 void BlackboxWindow::destroyHandle(void) {
631 screen
->getImageControl()->removeImage(frame
.fhandle
);
634 screen
->getImageControl()->removeImage(frame
.uhandle
);
637 screen
->getImageControl()->removeImage(frame
.fgrip
);
640 screen
->getImageControl()->removeImage(frame
.ugrip
);
642 blackbox
->removeWindowSearch(frame
.left_grip
);
643 blackbox
->removeWindowSearch(frame
.right_grip
);
645 XDestroyWindow(blackbox
->getXDisplay(), frame
.left_grip
);
646 XDestroyWindow(blackbox
->getXDisplay(), frame
.right_grip
);
647 frame
.left_grip
= frame
.right_grip
= None
;
649 blackbox
->removeWindowSearch(frame
.handle
);
650 XDestroyWindow(blackbox
->getXDisplay(), frame
.handle
);
655 void BlackboxWindow::createTitlebar(void) {
656 frame
.title
= createChildWindow(frame
.window
);
657 frame
.label
= createChildWindow(frame
.title
);
658 blackbox
->saveWindowSearch(frame
.title
, this);
659 blackbox
->saveWindowSearch(frame
.label
, this);
661 if (decorations
& Decor_Iconify
) createIconifyButton();
662 if (decorations
& Decor_Maximize
) createMaximizeButton();
663 if (decorations
& Decor_Close
) createCloseButton();
667 void BlackboxWindow::destroyTitlebar(void) {
668 if (frame
.close_button
)
669 destroyCloseButton();
671 if (frame
.iconify_button
)
672 destroyIconifyButton();
674 if (frame
.maximize_button
)
675 destroyMaximizeButton();
678 screen
->getImageControl()->removeImage(frame
.ftitle
);
681 screen
->getImageControl()->removeImage(frame
.utitle
);
684 screen
->getImageControl()->removeImage(frame
.flabel
);
687 screen
->getImageControl()->removeImage(frame
.ulabel
);
690 screen
->getImageControl()->removeImage(frame
.fbutton
);
693 screen
->getImageControl()->removeImage(frame
.ubutton
);
696 screen
->getImageControl()->removeImage(frame
.pbutton
);
698 blackbox
->removeWindowSearch(frame
.title
);
699 blackbox
->removeWindowSearch(frame
.label
);
701 XDestroyWindow(blackbox
->getXDisplay(), frame
.label
);
702 XDestroyWindow(blackbox
->getXDisplay(), frame
.title
);
703 frame
.title
= frame
.label
= None
;
707 void BlackboxWindow::createCloseButton(void) {
708 if (frame
.title
!= None
) {
709 frame
.close_button
= createChildWindow(frame
.title
);
710 blackbox
->saveWindowSearch(frame
.close_button
, this);
715 void BlackboxWindow::destroyCloseButton(void) {
716 blackbox
->removeWindowSearch(frame
.close_button
);
717 XDestroyWindow(blackbox
->getXDisplay(), frame
.close_button
);
718 frame
.close_button
= None
;
722 void BlackboxWindow::createIconifyButton(void) {
723 if (frame
.title
!= None
) {
724 frame
.iconify_button
= createChildWindow(frame
.title
);
725 blackbox
->saveWindowSearch(frame
.iconify_button
, this);
730 void BlackboxWindow::destroyIconifyButton(void) {
731 blackbox
->removeWindowSearch(frame
.iconify_button
);
732 XDestroyWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
733 frame
.iconify_button
= None
;
737 void BlackboxWindow::createMaximizeButton(void) {
738 if (frame
.title
!= None
) {
739 frame
.maximize_button
= createChildWindow(frame
.title
);
740 blackbox
->saveWindowSearch(frame
.maximize_button
, this);
745 void BlackboxWindow::destroyMaximizeButton(void) {
746 blackbox
->removeWindowSearch(frame
.maximize_button
);
747 XDestroyWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
748 frame
.maximize_button
= None
;
752 void BlackboxWindow::positionButtons(bool redecorate_label
) {
753 string layout
= blackbox
->getTitlebarLayout();
756 bool hasclose
, hasiconify
, hasmaximize
, haslabel
;
757 hasclose
= hasiconify
= hasmaximize
= haslabel
= false;
759 string::const_iterator it
, end
;
760 for (it
= layout
.begin(), end
= layout
.end(); it
!= end
; ++it
) {
763 if (! hasclose
&& (decorations
& Decor_Close
)) {
769 if (! hasiconify
&& (decorations
& Decor_Iconify
)) {
775 if (! hasmaximize
&& (decorations
& Decor_Maximize
)) {
787 if (! hasclose
&& frame
.close_button
)
788 destroyCloseButton();
789 if (! hasiconify
&& frame
.iconify_button
)
790 destroyIconifyButton();
791 if (! hasmaximize
&& frame
.maximize_button
)
792 destroyMaximizeButton();
794 parsed
+= 'L'; // require that the label be in the layout
796 const unsigned int bsep
= frame
.bevel_w
+ 1; // separation between elements
797 const unsigned int by
= frame
.bevel_w
+ 1;
798 const unsigned int ty
= frame
.bevel_w
;
800 frame
.label_w
= frame
.inside_w
- bsep
* 2 -
801 (frame
.button_w
+ bsep
) * (parsed
.size() - 1);
803 unsigned int x
= bsep
;
804 for (it
= parsed
.begin(), end
= parsed
.end(); it
!= end
; ++it
) {
807 if (! frame
.close_button
) createCloseButton();
808 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.close_button
, x
, by
,
809 frame
.button_w
, frame
.button_w
);
810 x
+= frame
.button_w
+ bsep
;
813 if (! frame
.iconify_button
) createIconifyButton();
814 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.iconify_button
, x
, by
,
815 frame
.button_w
, frame
.button_w
);
816 x
+= frame
.button_w
+ bsep
;
819 if (! frame
.maximize_button
) createMaximizeButton();
820 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.maximize_button
, x
, by
,
821 frame
.button_w
, frame
.button_w
);
822 x
+= frame
.button_w
+ bsep
;
825 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.label
, x
, ty
,
826 frame
.label_w
, frame
.label_h
);
827 x
+= frame
.label_w
+ bsep
;
832 if (redecorate_label
) decorateLabel();
838 void BlackboxWindow::reconfigure(void) {
841 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
842 frame
.rect
.top() + frame
.margin
.top
);
847 XClearWindow(blackbox
->getXDisplay(), frame
.window
);
848 setFocusFlag(flags
.focused
);
850 configure(frame
.rect
.x(), frame
.rect
.y(),
851 frame
.rect
.width(), frame
.rect
.height());
854 windowmenu
->move(windowmenu
->getX(), frame
.rect
.y() + frame
.title_h
);
855 windowmenu
->reconfigure();
860 void BlackboxWindow::updateFocusModel(void) {
861 if ((! screen
->isSloppyFocus()) || screen
->doClickRaise()) {
862 // grab button 1 for changing focus/raising
863 blackbox
->grabButton(Button1
, 0, frame
.plate
, True
, ButtonPressMask
,
864 GrabModeSync
, GrabModeSync
, None
, None
);
866 blackbox
->ungrabButton(Button1
, 0, frame
.plate
);
871 void BlackboxWindow::positionWindows(void) {
872 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.window
,
873 frame
.rect
.x(), frame
.rect
.y(), frame
.inside_w
,
874 (flags
.shaded
) ? frame
.title_h
: frame
.inside_h
);
875 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.window
, frame
.border_w
);
876 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.plate
,
878 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.plate
,
879 frame
.margin
.left
- frame
.mwm_border_w
- frame
.border_w
,
880 frame
.margin
.top
- frame
.mwm_border_w
- frame
.border_w
,
881 client
.rect
.width(), client
.rect
.height());
882 XMoveResizeWindow(blackbox
->getXDisplay(), client
.window
,
883 0, 0, client
.rect
.width(), client
.rect
.height());
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
) {
929 void BlackboxWindow::updateStrut(void) {
930 unsigned long num
= 4;
932 if (! xatom
->getValue(client
.window
, XAtom::net_wm_strut
, XAtom::cardinal
,
937 client
.strut
.left
= data
[0];
938 client
.strut
.right
= data
[1];
939 client
.strut
.top
= data
[2];
940 client
.strut
.bottom
= data
[3];
942 screen
->updateAvailableArea();
949 void BlackboxWindow::getWindowType(void) {
951 if (xatom
->getValue(client
.window
, XAtom::net_wm_window_type
, XAtom::atom
,
953 if (val
== xatom
->getAtom(XAtom::net_wm_window_type_desktop
))
954 window_type
= Type_Desktop
;
955 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_dock
))
956 window_type
= Type_Dock
;
957 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_toolbar
))
958 window_type
= Type_Toolbar
;
959 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_menu
))
960 window_type
= Type_Menu
;
961 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_utility
))
962 window_type
= Type_Utility
;
963 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_splash
))
964 window_type
= Type_Splash
;
965 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_dialog
))
966 window_type
= Type_Dialog
;
967 else //if (val[0] == xatom->getAtom(XAtom::net_wm_window_type_normal))
968 window_type
= Type_Normal
;
973 * the window type hint was not set, which means we either classify ourself
974 * as a normal window or a dialog, depending on if we are a transient.
977 window_type
= Type_Dialog
;
979 window_type
= Type_Normal
;
983 void BlackboxWindow::getWMName(void) {
984 if (xatom
->getValue(client
.window
, XAtom::net_wm_name
,
985 XAtom::utf8
, client
.title
) &&
986 !client
.title
.empty()) {
987 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
990 //fall through to using WM_NAME
991 if (xatom
->getValue(client
.window
, XAtom::wm_name
, XAtom::ansi
, client
.title
)
992 && !client
.title
.empty()) {
993 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
996 // fall back to an internal default
997 client
.title
= i18n(WindowSet
, WindowUnnamed
, "Unnamed");
998 xatom
->setValue(client
.window
, XAtom::net_wm_visible_name
, XAtom::utf8
,
1003 void BlackboxWindow::getWMIconName(void) {
1004 if (xatom
->getValue(client
.window
, XAtom::net_wm_icon_name
,
1005 XAtom::utf8
, client
.icon_title
) &&
1006 !client
.icon_title
.empty()) {
1007 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1010 //fall through to using WM_ICON_NAME
1011 if (xatom
->getValue(client
.window
, XAtom::wm_icon_name
, XAtom::ansi
,
1012 client
.icon_title
) &&
1013 !client
.icon_title
.empty()) {
1014 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1017 // fall back to using the main name
1018 client
.icon_title
= client
.title
;
1019 xatom
->setValue(client
.window
, XAtom::net_wm_visible_icon_name
, XAtom::utf8
,
1025 * Retrieve which WM Protocols are supported by the client window.
1026 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
1027 * window's decorations and allow the close behavior.
1028 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
1031 void BlackboxWindow::getWMProtocols(void) {
1035 if (XGetWMProtocols(blackbox
->getXDisplay(), client
.window
,
1036 &proto
, &num_return
)) {
1037 for (int i
= 0; i
< num_return
; ++i
) {
1038 if (proto
[i
] == xatom
->getAtom(XAtom::wm_delete_window
)) {
1039 decorations
|= Decor_Close
;
1040 functions
|= Func_Close
;
1041 } else if (proto
[i
] == xatom
->getAtom(XAtom::wm_take_focus
))
1042 flags
.send_focus_message
= True
;
1043 else if (proto
[i
] == xatom
->getAtom(XAtom::blackbox_structure_messages
))
1044 screen
->addNetizen(new Netizen(screen
, client
.window
));
1053 * Gets the value of the WM_HINTS property.
1054 * If the property is not set, then use a set of default values.
1056 void BlackboxWindow::getWMHints(void) {
1057 focus_mode
= F_Passive
;
1058 client
.initial_state
= NormalState
;
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 client
.initial_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 group
= new BWindowGroup(blackbox
, client
.window_group
);
1094 group
->addWindow(this);
1097 client
.wm_hint_flags
= wmhint
->flags
;
1103 * Gets the value of the WM_NORMAL_HINTS property.
1104 * If the property is not set, then use a set of default values.
1106 void BlackboxWindow::getWMNormalHints(void) {
1108 XSizeHints sizehint
;
1110 client
.min_width
= client
.min_height
=
1111 client
.width_inc
= client
.height_inc
= 1;
1112 client
.base_width
= client
.base_height
= 0;
1115 use the full screen, not the strut modified size. otherwise when the
1116 availableArea changes max_width/height will be incorrect and lead to odd
1119 const Rect
& screen_area
= screen
->getRect();
1120 client
.max_width
= screen_area
.width();
1122 client
.max_height
= screen_area
.height();
1123 client
.min_aspect_x
= client
.min_aspect_y
=
1124 client
.max_aspect_x
= client
.max_aspect_y
= 1;
1125 client
.win_gravity
= NorthWestGravity
;
1127 if (! XGetWMNormalHints(blackbox
->getXDisplay(), client
.window
,
1128 &sizehint
, &icccm_mask
))
1131 client
.normal_hint_flags
= sizehint
.flags
;
1133 if (sizehint
.flags
& PMinSize
) {
1134 client
.min_width
= sizehint
.min_width
;
1135 client
.min_height
= sizehint
.min_height
;
1138 if (sizehint
.flags
& PMaxSize
) {
1139 client
.max_width
= sizehint
.max_width
;
1140 client
.max_height
= sizehint
.max_height
;
1143 if (sizehint
.flags
& PResizeInc
) {
1144 client
.width_inc
= sizehint
.width_inc
;
1145 client
.height_inc
= sizehint
.height_inc
;
1148 if (sizehint
.flags
& PAspect
) {
1149 client
.min_aspect_x
= sizehint
.min_aspect
.x
;
1150 client
.min_aspect_y
= sizehint
.min_aspect
.y
;
1151 client
.max_aspect_x
= sizehint
.max_aspect
.x
;
1152 client
.max_aspect_y
= sizehint
.max_aspect
.y
;
1155 if (sizehint
.flags
& PBaseSize
) {
1156 client
.base_width
= sizehint
.base_width
;
1157 client
.base_height
= sizehint
.base_height
;
1160 if (sizehint
.flags
& PWinGravity
)
1161 client
.win_gravity
= sizehint
.win_gravity
;
1166 * Gets the NETWM hints for the class' contained window.
1168 void BlackboxWindow::getNetWMHints(void) {
1169 unsigned long workspace
;
1171 if (xatom
->getValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1173 if (workspace
== 0xffffffff)
1176 blackbox_attrib
.workspace
= workspace
;
1179 unsigned long *state
;
1180 unsigned long num
= (unsigned) -1;
1181 if (xatom
->getValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
1185 for (unsigned long i
= 0; i
< num
; ++i
) {
1186 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
))
1188 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_shaded
))
1189 flags
.shaded
= True
;
1190 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
))
1191 flags
.skip_taskbar
= True
;
1192 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_pager
))
1193 flags
.skip_pager
= True
;
1194 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_fullscreen
))
1195 flags
.fullscreen
= True
;
1196 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_hidden
))
1197 setState(IconicState
);
1198 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_vert
))
1200 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_horz
))
1204 flags
.maximized
= 1;
1206 flags
.maximized
= 2;
1208 flags
.maximized
= 3;
1216 * Gets the MWM hints for the class' contained window.
1217 * This is used while initializing the window to its first state, and not
1219 * Returns: true if the MWM hints are successfully retreived and applied;
1220 * false if they are not.
1222 void BlackboxWindow::getMWMHints(void) {
1226 num
= PropMwmHintsElements
;
1227 if (! xatom
->getValue(client
.window
, XAtom::motif_wm_hints
,
1228 XAtom::motif_wm_hints
, num
,
1229 (unsigned long **)&mwm_hint
) ||
1230 num
< PropMwmHintsElements
)
1233 if (mwm_hint
->flags
& MwmHintsDecorations
) {
1234 if (mwm_hint
->decorations
& MwmDecorAll
) {
1235 decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
1236 Decor_Iconify
| Decor_Maximize
| Decor_Close
;
1240 if (mwm_hint
->decorations
& MwmDecorBorder
)
1241 decorations
|= Decor_Border
;
1242 if (mwm_hint
->decorations
& MwmDecorHandle
)
1243 decorations
|= Decor_Handle
;
1244 if (mwm_hint
->decorations
& MwmDecorTitle
)
1245 decorations
|= Decor_Titlebar
;
1246 if (mwm_hint
->decorations
& MwmDecorIconify
)
1247 decorations
|= Decor_Iconify
;
1248 if (mwm_hint
->decorations
& MwmDecorMaximize
)
1249 decorations
|= Decor_Maximize
;
1253 if (mwm_hint
->flags
& MwmHintsFunctions
) {
1254 if (mwm_hint
->functions
& MwmFuncAll
) {
1255 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
|
1260 if (mwm_hint
->functions
& MwmFuncResize
)
1261 functions
|= Func_Resize
;
1262 if (mwm_hint
->functions
& MwmFuncMove
)
1263 functions
|= Func_Move
;
1264 if (mwm_hint
->functions
& MwmFuncIconify
)
1265 functions
|= Func_Iconify
;
1266 if (mwm_hint
->functions
& MwmFuncMaximize
)
1267 functions
|= Func_Maximize
;
1268 if (mwm_hint
->functions
& MwmFuncClose
)
1269 functions
|= Func_Close
;
1277 * Gets the blackbox hints from the class' contained window.
1278 * This is used while initializing the window to its first state, and not
1280 * Returns: true if the hints are successfully retreived and applied; false if
1283 bool BlackboxWindow::getBlackboxHints(void) {
1285 BlackboxHints
*blackbox_hint
;
1287 num
= PropBlackboxHintsElements
;
1288 if (! xatom
->getValue(client
.window
, XAtom::blackbox_hints
,
1289 XAtom::blackbox_hints
, num
,
1290 (unsigned long **)&blackbox_hint
) ||
1291 num
< PropBlackboxHintsElements
)
1294 if (blackbox_hint
->flags
& AttribShaded
)
1295 flags
.shaded
= (blackbox_hint
->attrib
& AttribShaded
);
1297 if ((blackbox_hint
->flags
& AttribMaxHoriz
) &&
1298 (blackbox_hint
->flags
& AttribMaxVert
))
1299 flags
.maximized
= (blackbox_hint
->attrib
&
1300 (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1301 else if (blackbox_hint
->flags
& AttribMaxVert
)
1302 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxVert
) ? 2 : 0;
1303 else if (blackbox_hint
->flags
& AttribMaxHoriz
)
1304 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1306 if (blackbox_hint
->flags
& AttribOmnipresent
)
1307 flags
.stuck
= (blackbox_hint
->attrib
& AttribOmnipresent
);
1309 if (blackbox_hint
->flags
& AttribWorkspace
)
1310 blackbox_attrib
.workspace
= blackbox_hint
->workspace
;
1312 // if (blackbox_hint->flags & AttribStack)
1313 // don't yet have always on top/bottom for blackbox yet... working
1316 if (blackbox_hint
->flags
& AttribDecoration
) {
1317 switch (blackbox_hint
->decoration
) {
1319 // clear all decorations except close
1320 decorations
&= Decor_Close
;
1321 // clear all functions except close
1322 functions
&= Func_Close
;
1327 decorations
|= Decor_Titlebar
| Decor_Iconify
;
1328 decorations
&= ~(Decor_Border
| Decor_Handle
| Decor_Maximize
);
1329 functions
|= Func_Move
| Func_Iconify
;
1330 functions
&= ~(Func_Resize
| Func_Maximize
);
1335 decorations
|= Decor_Titlebar
;
1336 decorations
&= ~(Decor_Iconify
| Decor_Border
| Decor_Handle
);
1337 functions
|= Func_Move
;
1338 functions
&= ~(Func_Resize
| Func_Maximize
| Func_Iconify
);
1344 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Handle
|
1345 Decor_Iconify
| Decor_Maximize
;
1346 functions
|= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
1354 delete blackbox_hint
;
1360 void BlackboxWindow::getTransientInfo(void) {
1361 if (client
.transient_for
&&
1362 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1363 // the transient for hint was removed, so we need to tell our
1364 // previous transient_for that we are going away
1365 client
.transient_for
->client
.transientList
.remove(this);
1368 // we have no transient_for until we find a new one
1369 client
.transient_for
= 0;
1372 if (! XGetTransientForHint(blackbox
->getXDisplay(), client
.window
,
1374 // transient_for hint not set
1378 if (trans_for
== client
.window
) {
1379 // wierd client... treat this window as a normal window
1383 if (trans_for
== None
|| trans_for
== screen
->getRootWindow()) {
1384 // this is an undocumented interpretation of the ICCCM. a transient
1385 // associated with None/Root/itself is assumed to be a modal root
1386 // transient. we don't support the concept of a global transient,
1387 // so we just associate this transient with nothing, and perhaps
1388 // we will add support later for global modality.
1389 client
.transient_for
= (BlackboxWindow
*) ~0ul;
1394 client
.transient_for
= blackbox
->searchWindow(trans_for
);
1395 if (! client
.transient_for
&&
1396 client
.window_group
&& trans_for
== client
.window_group
) {
1397 // no direct transient_for, perhaps this is a group transient?
1398 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1399 if (group
) client
.transient_for
= group
->find(screen
);
1402 if (! client
.transient_for
|| client
.transient_for
== this) {
1403 // no transient_for found, or we have a wierd client that wants to be
1404 // a transient for itself, so we treat this window as a normal window
1405 client
.transient_for
= (BlackboxWindow
*) 0;
1409 // register ourselves with our new transient_for
1410 client
.transient_for
->client
.transientList
.push_back(this);
1411 flags
.stuck
= client
.transient_for
->flags
.stuck
;
1415 bool BlackboxWindow::isKDESystrayWindow(void) {
1417 if (xatom
->getValue(client
.window
, XAtom::kde_net_wm_system_tray_window_for
,
1418 XAtom::window
, systray
) && systray
)
1424 BlackboxWindow
*BlackboxWindow::getTransientFor(void) const {
1425 if (client
.transient_for
&&
1426 client
.transient_for
!= (BlackboxWindow
*) ~0ul)
1427 return client
.transient_for
;
1432 void BlackboxWindow::configure(int dx
, int dy
,
1433 unsigned int dw
, unsigned int dh
) {
1434 bool send_event
= (frame
.rect
.x() != dx
|| frame
.rect
.y() != dy
);
1436 if ((dw
!= frame
.rect
.width()) || (dh
!= frame
.rect
.height())) {
1437 frame
.rect
.setRect(dx
, dy
, dw
, dh
);
1438 frame
.inside_w
= frame
.rect
.width() - (frame
.border_w
* 2);
1439 frame
.inside_h
= frame
.rect
.height() - (frame
.border_w
* 2);
1441 if (frame
.rect
.right() <= 0 || frame
.rect
.bottom() <= 0)
1442 frame
.rect
.setPos(0, 0);
1444 client
.rect
.setCoords(frame
.rect
.left() + frame
.margin
.left
,
1445 frame
.rect
.top() + frame
.margin
.top
,
1446 frame
.rect
.right() - frame
.margin
.right
,
1447 frame
.rect
.bottom() - frame
.margin
.bottom
);
1450 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
1457 setFocusFlag(flags
.focused
);
1460 frame
.rect
.setPos(dx
, dy
);
1462 XMoveWindow(blackbox
->getXDisplay(), frame
.window
,
1463 frame
.rect
.x(), frame
.rect
.y());
1465 if (! flags
.moving
) send_event
= True
;
1468 if (send_event
&& ! flags
.moving
) {
1469 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1470 frame
.rect
.top() + frame
.margin
.top
);
1473 event
.type
= ConfigureNotify
;
1475 event
.xconfigure
.display
= blackbox
->getXDisplay();
1476 event
.xconfigure
.event
= client
.window
;
1477 event
.xconfigure
.window
= client
.window
;
1478 event
.xconfigure
.x
= client
.rect
.x();
1479 event
.xconfigure
.y
= client
.rect
.y();
1480 event
.xconfigure
.width
= client
.rect
.width();
1481 event
.xconfigure
.height
= client
.rect
.height();
1482 event
.xconfigure
.border_width
= client
.old_bw
;
1483 event
.xconfigure
.above
= frame
.window
;
1484 event
.xconfigure
.override_redirect
= False
;
1486 XSendEvent(blackbox
->getXDisplay(), client
.window
, True
,
1487 NoEventMask
, &event
);
1489 screen
->updateNetizenConfigNotify(&event
);
1495 void BlackboxWindow::configureShape(void) {
1496 XShapeCombineShape(blackbox
->getXDisplay(), frame
.window
, ShapeBounding
,
1497 frame
.margin
.left
- frame
.border_w
,
1498 frame
.margin
.top
- frame
.border_w
,
1499 client
.window
, ShapeBounding
, ShapeSet
);
1502 XRectangle xrect
[2];
1504 if (decorations
& Decor_Titlebar
) {
1505 xrect
[0].x
= xrect
[0].y
= -frame
.border_w
;
1506 xrect
[0].width
= frame
.rect
.width();
1507 xrect
[0].height
= frame
.title_h
+ (frame
.border_w
* 2);
1511 if (decorations
& Decor_Handle
) {
1512 xrect
[1].x
= -frame
.border_w
;
1513 xrect
[1].y
= frame
.rect
.height() - frame
.margin
.bottom
+
1514 frame
.mwm_border_w
- frame
.border_w
;
1515 xrect
[1].width
= frame
.rect
.width();
1516 xrect
[1].height
= frame
.handle_h
+ (frame
.border_w
* 2);
1520 XShapeCombineRectangles(blackbox
->getXDisplay(), frame
.window
,
1521 ShapeBounding
, 0, 0, xrect
, num
,
1522 ShapeUnion
, Unsorted
);
1527 bool BlackboxWindow::setInputFocus(void) {
1528 if (flags
.focused
) return True
;
1530 assert(! flags
.iconic
);
1532 // if the window is not visible, mark the window as wanting focus rather
1533 // than give it focus.
1534 if (! flags
.visible
) {
1535 Workspace
*wkspc
= screen
->getWorkspace(blackbox_attrib
.workspace
);
1536 wkspc
->setLastFocusedWindow(this);
1540 if (! client
.rect
.intersects(screen
->getRect())) {
1541 // client is outside the screen, move it to the center
1542 configure((screen
->getWidth() - frame
.rect
.width()) / 2,
1543 (screen
->getHeight() - frame
.rect
.height()) / 2,
1544 frame
.rect
.width(), frame
.rect
.height());
1547 if (client
.transientList
.size() > 0) {
1548 // transfer focus to any modal transients
1549 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1550 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1551 if ((*it
)->flags
.modal
) return (*it
)->setInputFocus();
1556 if (focus_mode
== F_LocallyActive
|| focus_mode
== F_Passive
) {
1557 XSetInputFocus(blackbox
->getXDisplay(), client
.window
,
1558 RevertToPointerRoot
, CurrentTime
);
1560 blackbox
->setFocusedWindow(this);
1562 /* we could set the focus to none, since the window doesn't accept focus,
1563 * but we shouldn't set focus to nothing since this would surely make
1569 if (flags
.send_focus_message
) {
1571 ce
.xclient
.type
= ClientMessage
;
1572 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1573 ce
.xclient
.display
= blackbox
->getXDisplay();
1574 ce
.xclient
.window
= client
.window
;
1575 ce
.xclient
.format
= 32;
1576 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_take_focus
);
1577 ce
.xclient
.data
.l
[1] = blackbox
->getLastTime();
1578 ce
.xclient
.data
.l
[2] = 0l;
1579 ce
.xclient
.data
.l
[3] = 0l;
1580 ce
.xclient
.data
.l
[4] = 0l;
1581 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1589 void BlackboxWindow::iconify(void) {
1590 if (flags
.iconic
) return;
1592 // We don't need to worry about resizing because resizing always grabs the X
1593 // server. This should only ever happen if using opaque moving.
1597 if (windowmenu
) windowmenu
->hide();
1600 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1601 * we need to clear the event mask on client.window for a split second.
1602 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1603 * split second, leaving us with a ghost window... so, we need to do this
1604 * while the X server is grabbed
1606 XGrabServer(blackbox
->getXDisplay());
1607 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
1608 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1609 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1610 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
1611 XUngrabServer(blackbox
->getXDisplay());
1613 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1614 flags
.visible
= False
;
1615 flags
.iconic
= True
;
1617 setState(IconicState
);
1619 screen
->getWorkspace(blackbox_attrib
.workspace
)->removeWindow(this);
1621 if (isTransient()) {
1622 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1623 ! client
.transient_for
->flags
.iconic
) {
1624 // iconify our transient_for
1625 client
.transient_for
->iconify();
1629 screen
->addIcon(this);
1631 if (client
.transientList
.size() > 0) {
1632 // iconify all transients
1633 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1634 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1635 if (! (*it
)->flags
.iconic
) (*it
)->iconify();
1641 void BlackboxWindow::show(void) {
1642 flags
.visible
= True
;
1643 flags
.iconic
= False
;
1645 current_state
= (flags
.shaded
) ? IconicState
: NormalState
;
1646 setState(current_state
);
1648 XMapWindow(blackbox
->getXDisplay(), client
.window
);
1649 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
1650 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
1654 void BlackboxWindow::deiconify(bool reassoc
, bool raise
) {
1655 if (flags
.iconic
|| reassoc
)
1656 screen
->reassociateWindow(this, BSENTINEL
, False
);
1657 else if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspace()->getID())
1662 // reassociate and deiconify all transients
1663 if (reassoc
&& client
.transientList
.size() > 0) {
1664 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1665 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1666 (*it
)->deiconify(True
, False
);
1671 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1675 void BlackboxWindow::close(void) {
1677 ce
.xclient
.type
= ClientMessage
;
1678 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1679 ce
.xclient
.display
= blackbox
->getXDisplay();
1680 ce
.xclient
.window
= client
.window
;
1681 ce
.xclient
.format
= 32;
1682 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_delete_window
);
1683 ce
.xclient
.data
.l
[1] = CurrentTime
;
1684 ce
.xclient
.data
.l
[2] = 0l;
1685 ce
.xclient
.data
.l
[3] = 0l;
1686 ce
.xclient
.data
.l
[4] = 0l;
1687 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
, NoEventMask
, &ce
);
1691 void BlackboxWindow::withdraw(void) {
1692 // We don't need to worry about resizing because resizing always grabs the X
1693 // server. This should only ever happen if using opaque moving.
1697 flags
.visible
= False
;
1698 flags
.iconic
= False
;
1700 setState(current_state
);
1702 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1704 XGrabServer(blackbox
->getXDisplay());
1706 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
1707 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1708 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1709 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
1711 XUngrabServer(blackbox
->getXDisplay());
1713 if (windowmenu
) windowmenu
->hide();
1717 void BlackboxWindow::maximize(unsigned int button
) {
1718 // We don't need to worry about resizing because resizing always grabs the X
1719 // server. This should only ever happen if using opaque moving.
1723 // handle case where menu is open then the max button is used instead
1724 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
1726 if (flags
.maximized
) {
1727 flags
.maximized
= 0;
1729 blackbox_attrib
.flags
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1730 blackbox_attrib
.attrib
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1733 when a resize finishes, maximize(0) is called to clear any maximization
1734 flags currently set. Otherwise it still thinks it is maximized.
1735 so we do not need to call configure() because resizing will handle it
1737 if (! flags
.resizing
)
1738 configure(blackbox_attrib
.premax_x
, blackbox_attrib
.premax_y
,
1739 blackbox_attrib
.premax_w
, blackbox_attrib
.premax_h
);
1741 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
1742 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
1745 setState(current_state
);
1749 blackbox_attrib
.premax_x
= frame
.rect
.x();
1750 blackbox_attrib
.premax_y
= frame
.rect
.y();
1751 blackbox_attrib
.premax_w
= frame
.rect
.width();
1752 // use client.rect so that clients can be restored even if shaded
1753 blackbox_attrib
.premax_h
=
1754 client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
;
1756 const Rect
&screen_area
= screen
->availableArea();
1757 frame
.changing
= screen_area
;
1762 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1763 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1767 blackbox_attrib
.flags
|= AttribMaxVert
;
1768 blackbox_attrib
.attrib
|= AttribMaxVert
;
1770 frame
.changing
.setX(frame
.rect
.x());
1771 frame
.changing
.setWidth(frame
.rect
.width());
1775 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1776 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1778 frame
.changing
.setY(frame
.rect
.y());
1779 frame
.changing
.setHeight(frame
.rect
.height());
1784 blackbox_attrib
.flags
^= AttribShaded
;
1785 blackbox_attrib
.attrib
^= AttribShaded
;
1786 flags
.shaded
= False
;
1789 flags
.maximized
= button
;
1791 configure(frame
.changing
.x(), frame
.changing
.y(),
1792 frame
.changing
.width(), frame
.changing
.height());
1794 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1796 setState(current_state
);
1800 // re-maximizes the window to take into account availableArea changes
1801 void BlackboxWindow::remaximize(void) {
1802 // save the original dimensions because maximize will wipe them out
1803 int premax_x
= blackbox_attrib
.premax_x
,
1804 premax_y
= blackbox_attrib
.premax_y
,
1805 premax_w
= blackbox_attrib
.premax_w
,
1806 premax_h
= blackbox_attrib
.premax_h
;
1808 unsigned int button
= flags
.maximized
;
1809 flags
.maximized
= 0; // trick maximize() into working
1812 // restore saved values
1813 blackbox_attrib
.premax_x
= premax_x
;
1814 blackbox_attrib
.premax_y
= premax_y
;
1815 blackbox_attrib
.premax_w
= premax_w
;
1816 blackbox_attrib
.premax_h
= premax_h
;
1820 void BlackboxWindow::setWorkspace(unsigned int n
) {
1821 blackbox_attrib
.flags
|= AttribWorkspace
;
1822 blackbox_attrib
.workspace
= n
;
1823 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
, n
);
1827 void BlackboxWindow::shade(void) {
1829 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1830 frame
.inside_w
, frame
.inside_h
);
1831 flags
.shaded
= False
;
1832 blackbox_attrib
.flags
^= AttribShaded
;
1833 blackbox_attrib
.attrib
^= AttribShaded
;
1835 setState(NormalState
);
1837 // set the frame rect to the normal size
1838 frame
.rect
.setHeight(client
.rect
.height() + frame
.margin
.top
+
1839 frame
.margin
.bottom
);
1841 if (! (decorations
& Decor_Titlebar
))
1844 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1845 frame
.inside_w
, frame
.title_h
);
1846 flags
.shaded
= True
;
1847 blackbox_attrib
.flags
|= AttribShaded
;
1848 blackbox_attrib
.attrib
|= AttribShaded
;
1850 setState(IconicState
);
1852 // set the frame rect to the shaded size
1853 frame
.rect
.setHeight(frame
.title_h
+ (frame
.border_w
* 2));
1859 * (Un)Sticks a window and its relatives.
1861 void BlackboxWindow::stick(void) {
1863 blackbox_attrib
.flags
^= AttribOmnipresent
;
1864 blackbox_attrib
.attrib
^= AttribOmnipresent
;
1866 flags
.stuck
= False
;
1869 screen
->reassociateWindow(this, BSENTINEL
, True
);
1871 // temporary fix since sticky windows suck. set the hint to what we
1872 // actually hold in our data.
1873 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1874 blackbox_attrib
.workspace
);
1876 setState(current_state
);
1880 blackbox_attrib
.flags
|= AttribOmnipresent
;
1881 blackbox_attrib
.attrib
|= AttribOmnipresent
;
1883 // temporary fix since sticky windows suck. set the hint to a different
1884 // value than that contained in the class' data.
1885 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1888 setState(current_state
);
1891 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1892 client
.transient_for
->isStuck() != flags
.stuck
)
1893 client
.transient_for
->stick();
1894 // go down the chain
1895 BlackboxWindowList::iterator it
;
1896 const BlackboxWindowList::iterator end
= client
.transientList
.end();
1897 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1898 if ((*it
)->isStuck() != flags
.stuck
)
1903 void BlackboxWindow::setFocusFlag(bool focus
) {
1904 // only focus a window if it is visible
1905 if (focus
&& !flags
.visible
)
1908 flags
.focused
= focus
;
1910 if (decorations
& Decor_Titlebar
) {
1911 if (flags
.focused
) {
1913 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1914 frame
.title
, frame
.ftitle
);
1916 XSetWindowBackground(blackbox
->getXDisplay(),
1917 frame
.title
, frame
.ftitle_pixel
);
1920 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1921 frame
.title
, frame
.utitle
);
1923 XSetWindowBackground(blackbox
->getXDisplay(),
1924 frame
.title
, frame
.utitle_pixel
);
1926 XClearWindow(blackbox
->getXDisplay(), frame
.title
);
1932 if (decorations
& Decor_Handle
) {
1933 if (flags
.focused
) {
1935 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1936 frame
.handle
, frame
.fhandle
);
1938 XSetWindowBackground(blackbox
->getXDisplay(),
1939 frame
.handle
, frame
.fhandle_pixel
);
1942 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1943 frame
.left_grip
, frame
.fgrip
);
1944 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1945 frame
.right_grip
, frame
.fgrip
);
1947 XSetWindowBackground(blackbox
->getXDisplay(),
1948 frame
.left_grip
, frame
.fgrip_pixel
);
1949 XSetWindowBackground(blackbox
->getXDisplay(),
1950 frame
.right_grip
, frame
.fgrip_pixel
);
1954 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1955 frame
.handle
, frame
.uhandle
);
1957 XSetWindowBackground(blackbox
->getXDisplay(),
1958 frame
.handle
, frame
.uhandle_pixel
);
1961 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1962 frame
.left_grip
, frame
.ugrip
);
1963 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1964 frame
.right_grip
, frame
.ugrip
);
1966 XSetWindowBackground(blackbox
->getXDisplay(),
1967 frame
.left_grip
, frame
.ugrip_pixel
);
1968 XSetWindowBackground(blackbox
->getXDisplay(),
1969 frame
.right_grip
, frame
.ugrip_pixel
);
1972 XClearWindow(blackbox
->getXDisplay(), frame
.handle
);
1973 XClearWindow(blackbox
->getXDisplay(), frame
.left_grip
);
1974 XClearWindow(blackbox
->getXDisplay(), frame
.right_grip
);
1977 if (decorations
& Decor_Border
) {
1979 XSetWindowBorder(blackbox
->getXDisplay(),
1980 frame
.plate
, frame
.fborder_pixel
);
1982 XSetWindowBorder(blackbox
->getXDisplay(),
1983 frame
.plate
, frame
.uborder_pixel
);
1986 if (screen
->isSloppyFocus() && screen
->doAutoRaise()) {
1987 if (isFocused()) timer
->start();
1992 blackbox
->setFocusedWindow(this);
1996 void BlackboxWindow::installColormap(bool install
) {
1997 int i
= 0, ncmap
= 0;
1998 Colormap
*cmaps
= XListInstalledColormaps(blackbox
->getXDisplay(),
1999 client
.window
, &ncmap
);
2000 XWindowAttributes wattrib
;
2002 if (XGetWindowAttributes(blackbox
->getXDisplay(),
2003 client
.window
, &wattrib
)) {
2005 // install the window's colormap
2006 for (i
= 0; i
< ncmap
; i
++) {
2007 if (*(cmaps
+ i
) == wattrib
.colormap
)
2008 // this window is using an installed color map... do not install
2011 // otherwise, install the window's colormap
2013 XInstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2015 // uninstall the window's colormap
2016 for (i
= 0; i
< ncmap
; i
++) {
2017 if (*(cmaps
+ i
) == wattrib
.colormap
)
2018 // we found the colormap to uninstall
2019 XUninstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2029 void BlackboxWindow::setAllowedActions(void) {
2033 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_shade
);
2034 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_change_desktop
);
2035 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_close
);
2037 if (functions
& Func_Move
)
2038 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_move
);
2039 if (functions
& Func_Resize
)
2040 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_resize
);
2041 if (functions
& Func_Maximize
) {
2042 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_horz
);
2043 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_vert
);
2046 xatom
->setValue(client
.window
, XAtom::net_wm_allowed_actions
, XAtom::atom
,
2051 void BlackboxWindow::setState(unsigned long new_state
) {
2052 current_state
= new_state
;
2054 unsigned long state
[2];
2055 state
[0] = current_state
;
2057 xatom
->setValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
, state
, 2);
2059 xatom
->setValue(client
.window
, XAtom::blackbox_attributes
,
2060 XAtom::blackbox_attributes
, (unsigned long *)&blackbox_attrib
,
2061 PropBlackboxAttributesElements
);
2066 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_modal
);
2068 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_shaded
);
2070 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_hidden
);
2071 if (flags
.skip_taskbar
)
2072 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
);
2073 if (flags
.skip_pager
)
2074 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_pager
);
2075 if (flags
.fullscreen
)
2076 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_fullscreen
);
2077 if (flags
.maximized
== 1 || flags
.maximized
== 2)
2078 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_vert
);
2079 if (flags
.maximized
== 1 || flags
.maximized
== 3)
2080 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_horz
);
2081 xatom
->setValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
2086 bool BlackboxWindow::getState(void) {
2087 bool ret
= xatom
->getValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
,
2089 if (! ret
) current_state
= 0;
2094 void BlackboxWindow::restoreAttributes(void) {
2095 unsigned long num
= PropBlackboxAttributesElements
;
2096 BlackboxAttributes
*net
;
2097 if (! xatom
->getValue(client
.window
, XAtom::blackbox_attributes
,
2098 XAtom::blackbox_attributes
, num
,
2099 (unsigned long **)&net
))
2101 if (num
< PropBlackboxAttributesElements
) {
2106 if (net
->flags
& AttribShaded
&& net
->attrib
& AttribShaded
) {
2107 flags
.shaded
= False
;
2111 Because the iconic'ness of shaded windows is lost, we need to set the
2112 state to NormalState so that shaded windows on other workspaces will not
2113 get shown on the first workspace.
2114 At this point in the life of a window, current_state should only be set
2115 to IconicState if the window was an *icon*, not if it was shaded.
2117 current_state
= NormalState
;
2120 if ((net
->workspace
!= screen
->getCurrentWorkspaceID()) &&
2121 (net
->workspace
< screen
->getWorkspaceCount()))
2122 screen
->reassociateWindow(this, net
->workspace
, True
);
2124 if ((blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID()) &&
2125 (blackbox_attrib
.workspace
< screen
->getWorkspaceCount())) {
2126 // set to WithdrawnState so it will be mapped on the new workspace
2127 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2128 } else if (current_state
== WithdrawnState
) {
2129 // the window is on this workspace and is Withdrawn, so it is waiting to
2131 current_state
= NormalState
;
2134 if (net
->flags
& AttribOmnipresent
&& net
->attrib
& AttribOmnipresent
) {
2135 flags
.stuck
= False
;
2138 // if the window was on another workspace, it was going to be hidden. this
2139 // specifies that the window should be mapped since it is sticky.
2140 if (current_state
== WithdrawnState
) current_state
= NormalState
;
2143 if (net
->flags
& AttribMaxHoriz
|| net
->flags
& AttribMaxVert
) {
2144 int x
= net
->premax_x
, y
= net
->premax_y
;
2145 unsigned int w
= net
->premax_w
, h
= net
->premax_h
;
2146 flags
.maximized
= 0;
2149 if ((net
->flags
& AttribMaxHoriz
) &&
2150 (net
->flags
& AttribMaxVert
))
2151 m
= (net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
2152 else if (net
->flags
& AttribMaxVert
)
2153 m
= (net
->attrib
& AttribMaxVert
) ? 2 : 0;
2154 else if (net
->flags
& AttribMaxHoriz
)
2155 m
= (net
->attrib
& AttribMaxHoriz
) ? 3 : 0;
2159 blackbox_attrib
.premax_x
= x
;
2160 blackbox_attrib
.premax_y
= y
;
2161 blackbox_attrib
.premax_w
= w
;
2162 blackbox_attrib
.premax_h
= h
;
2165 // with the state set it will then be the map events job to read the window's
2166 // state and behave accordingly
2173 * Positions the frame according the the client window position and window
2176 void BlackboxWindow::setGravityOffsets(void) {
2177 // x coordinates for each gravity type
2178 const int x_west
= client
.rect
.x();
2179 const int x_east
= client
.rect
.right() - frame
.inside_w
+ 1;
2180 const int x_center
= client
.rect
.left() +
2181 ((client
.rect
.width() - frame
.rect
.width()) / 2);
2182 // y coordinates for each gravity type
2183 const int y_north
= client
.rect
.y();
2184 const int y_south
= client
.rect
.bottom() - frame
.inside_h
+ 1;
2185 const int y_center
= client
.rect
.top() +
2186 ((client
.rect
.height() - frame
.rect
.height()) / 2);
2188 switch (client
.win_gravity
) {
2190 case NorthWestGravity
: frame
.rect
.setPos(x_west
, y_north
); break;
2191 case NorthGravity
: frame
.rect
.setPos(x_center
, y_north
); break;
2192 case NorthEastGravity
: frame
.rect
.setPos(x_east
, y_north
); break;
2193 case SouthWestGravity
: frame
.rect
.setPos(x_west
, y_south
); break;
2194 case SouthGravity
: frame
.rect
.setPos(x_center
, y_south
); break;
2195 case SouthEastGravity
: frame
.rect
.setPos(x_east
, y_south
); break;
2196 case WestGravity
: frame
.rect
.setPos(x_west
, y_center
); break;
2197 case CenterGravity
: frame
.rect
.setPos(x_center
, y_center
); break;
2198 case EastGravity
: frame
.rect
.setPos(x_east
, y_center
); break;
2202 frame
.rect
.setPos(client
.rect
.x() - frame
.margin
.left
,
2203 client
.rect
.y() - frame
.margin
.top
);
2210 * The reverse of the setGravityOffsets function. Uses the frame window's
2211 * position to find the window's reference point.
2213 void BlackboxWindow::restoreGravity(void) {
2214 // x coordinates for each gravity type
2215 const int x_west
= frame
.rect
.x();
2216 const int x_east
= frame
.rect
.x() + frame
.inside_w
- client
.rect
.width();
2217 const int x_center
= frame
.rect
.x() -
2218 ((client
.rect
.width() - frame
.rect
.width()) / 2);
2219 // y coordinates for each gravity type
2220 const int y_north
= frame
.rect
.y();
2221 const int y_south
= frame
.rect
.y() + frame
.inside_h
- client
.rect
.height();
2222 const int y_center
= frame
.rect
.y() -
2223 ((client
.rect
.height() - frame
.rect
.height()) / 2);
2225 switch(client
.win_gravity
) {
2227 case NorthWestGravity
: client
.rect
.setPos(x_west
, y_north
); break;
2228 case NorthGravity
: client
.rect
.setPos(x_center
, y_north
); break;
2229 case NorthEastGravity
: client
.rect
.setPos(x_east
, y_north
); break;
2230 case SouthWestGravity
: client
.rect
.setPos(x_west
, y_south
); break;
2231 case SouthGravity
: client
.rect
.setPos(x_center
, y_south
); break;
2232 case SouthEastGravity
: client
.rect
.setPos(x_east
, y_south
); break;
2233 case WestGravity
: client
.rect
.setPos(x_west
, y_center
); break;
2234 case CenterGravity
: client
.rect
.setPos(x_center
, y_center
); break;
2235 case EastGravity
: client
.rect
.setPos(x_east
, y_center
); break;
2239 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
2240 frame
.rect
.top() + frame
.margin
.top
);
2246 void BlackboxWindow::redrawLabel(void) {
2247 if (flags
.focused
) {
2249 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2250 frame
.label
, frame
.flabel
);
2252 XSetWindowBackground(blackbox
->getXDisplay(),
2253 frame
.label
, frame
.flabel_pixel
);
2256 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2257 frame
.label
, frame
.ulabel
);
2259 XSetWindowBackground(blackbox
->getXDisplay(),
2260 frame
.label
, frame
.ulabel_pixel
);
2262 XClearWindow(blackbox
->getXDisplay(), frame
.label
);
2264 WindowStyle
*style
= screen
->getWindowStyle();
2266 int pos
= frame
.bevel_w
* 2,
2267 dlen
= style
->doJustify(client
.title
.c_str(), pos
, frame
.label_w
,
2268 frame
.bevel_w
* 4, i18n
.multibyte());
2270 BPen
pen((flags
.focused
) ? style
->l_text_focus
: style
->l_text_unfocus
,
2272 if (i18n
.multibyte())
2273 XmbDrawString(blackbox
->getXDisplay(), frame
.label
, style
->fontset
,
2275 (1 - style
->fontset_extents
->max_ink_extent
.y
),
2276 client
.title
.c_str(), dlen
);
2278 XDrawString(blackbox
->getXDisplay(), frame
.label
, pen
.gc(), pos
,
2279 (style
->font
->ascent
+ 1), client
.title
.c_str(), dlen
);
2283 void BlackboxWindow::redrawAllButtons(void) {
2284 if (frame
.iconify_button
) redrawIconifyButton(False
);
2285 if (frame
.maximize_button
) redrawMaximizeButton(flags
.maximized
);
2286 if (frame
.close_button
) redrawCloseButton(False
);
2290 void BlackboxWindow::redrawIconifyButton(bool pressed
) {
2292 if (flags
.focused
) {
2294 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2295 frame
.iconify_button
, frame
.fbutton
);
2297 XSetWindowBackground(blackbox
->getXDisplay(),
2298 frame
.iconify_button
, frame
.fbutton_pixel
);
2301 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2302 frame
.iconify_button
, frame
.ubutton
);
2304 XSetWindowBackground(blackbox
->getXDisplay(), frame
.iconify_button
,
2305 frame
.ubutton_pixel
);
2309 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2310 frame
.iconify_button
, frame
.pbutton
);
2312 XSetWindowBackground(blackbox
->getXDisplay(),
2313 frame
.iconify_button
, frame
.pbutton_pixel
);
2315 XClearWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
2317 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2318 screen
->getWindowStyle()->b_pic_unfocus
);
2319 XDrawRectangle(blackbox
->getXDisplay(), frame
.iconify_button
, pen
.gc(),
2320 2, (frame
.button_w
- 5), (frame
.button_w
- 5), 2);
2324 void BlackboxWindow::redrawMaximizeButton(bool pressed
) {
2326 if (flags
.focused
) {
2328 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2329 frame
.maximize_button
, frame
.fbutton
);
2331 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2332 frame
.fbutton_pixel
);
2335 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2336 frame
.maximize_button
, frame
.ubutton
);
2338 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2339 frame
.ubutton_pixel
);
2343 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2344 frame
.maximize_button
, frame
.pbutton
);
2346 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2347 frame
.pbutton_pixel
);
2349 XClearWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
2351 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2352 screen
->getWindowStyle()->b_pic_unfocus
);
2353 XDrawRectangle(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2354 2, 2, (frame
.button_w
- 5), (frame
.button_w
- 5));
2355 XDrawLine(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2356 2, 3, (frame
.button_w
- 3), 3);
2360 void BlackboxWindow::redrawCloseButton(bool pressed
) {
2362 if (flags
.focused
) {
2364 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2367 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2368 frame
.fbutton_pixel
);
2371 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2374 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2375 frame
.ubutton_pixel
);
2379 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2380 frame
.close_button
, frame
.pbutton
);
2382 XSetWindowBackground(blackbox
->getXDisplay(),
2383 frame
.close_button
, frame
.pbutton_pixel
);
2385 XClearWindow(blackbox
->getXDisplay(), frame
.close_button
);
2387 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2388 screen
->getWindowStyle()->b_pic_unfocus
);
2389 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2390 2, 2, (frame
.button_w
- 3), (frame
.button_w
- 3));
2391 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2392 2, (frame
.button_w
- 3), (frame
.button_w
- 3), 2);
2396 void BlackboxWindow::mapRequestEvent(XMapRequestEvent
*re
) {
2397 if (re
->window
!= client
.window
)
2401 fprintf(stderr
, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2405 switch (current_state
) {
2410 case WithdrawnState
:
2419 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2420 if (! blackbox
->isStartup() && (isTransient() || screen
->doFocusNew())) {
2421 XSync(blackbox
->getXDisplay(), False
); // make sure the frame is mapped..
2429 void BlackboxWindow::unmapNotifyEvent(XUnmapEvent
*ue
) {
2430 if (ue
->window
!= client
.window
)
2434 fprintf(stderr
, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2438 screen
->unmanageWindow(this, False
);
2442 void BlackboxWindow::destroyNotifyEvent(XDestroyWindowEvent
*de
) {
2443 if (de
->window
!= client
.window
)
2447 fprintf(stderr
, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2451 screen
->unmanageWindow(this, False
);
2455 void BlackboxWindow::reparentNotifyEvent(XReparentEvent
*re
) {
2456 if (re
->window
!= client
.window
|| re
->parent
== frame
.plate
)
2460 fprintf(stderr
, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2461 "0x%lx.\n", client
.window
, re
->parent
);
2466 XPutBackEvent(blackbox
->getXDisplay(), &ev
);
2467 screen
->unmanageWindow(this, True
);
2471 void BlackboxWindow::propertyNotifyEvent(Atom atom
) {
2474 case XA_WM_CLIENT_MACHINE
:
2478 case XA_WM_TRANSIENT_FOR
: {
2479 // determine if this is a transient window
2482 // adjust the window decorations based on transience
2483 if (isTransient()) {
2484 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2485 functions
&= ~Func_Maximize
;
2486 setAllowedActions();
2497 case XA_WM_ICON_NAME
:
2499 if (flags
.iconic
) screen
->propagateWindowName(this);
2502 case XAtom::net_wm_name
:
2506 if (decorations
& Decor_Titlebar
)
2509 screen
->propagateWindowName(this);
2512 case XA_WM_NORMAL_HINTS
: {
2515 if ((client
.normal_hint_flags
& PMinSize
) &&
2516 (client
.normal_hint_flags
& PMaxSize
)) {
2517 if (client
.max_width
<= client
.min_width
&&
2518 client
.max_height
<= client
.min_height
) {
2519 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2520 functions
&= ~(Func_Resize
| Func_Maximize
);
2522 decorations
|= Decor_Maximize
| Decor_Handle
;
2523 functions
|= Func_Resize
| Func_Maximize
;
2525 setAllowedActions();
2528 Rect old_rect
= frame
.rect
;
2532 if (old_rect
!= frame
.rect
)
2539 if (atom
== xatom
->getAtom(XAtom::wm_protocols
)) {
2542 if ((decorations
& Decor_Close
) && (! frame
.close_button
)) {
2543 createCloseButton();
2544 if (decorations
& Decor_Titlebar
) {
2545 positionButtons(True
);
2546 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
2548 if (windowmenu
) windowmenu
->reconfigure();
2550 } else if (atom
== xatom
->getAtom(XAtom::net_wm_strut
)) {
2559 void BlackboxWindow::exposeEvent(XExposeEvent
*ee
) {
2560 if (frame
.label
== ee
->window
&& (decorations
& Decor_Titlebar
))
2562 else if (frame
.close_button
== ee
->window
)
2563 redrawCloseButton(False
);
2564 else if (frame
.maximize_button
== ee
->window
)
2565 redrawMaximizeButton(flags
.maximized
);
2566 else if (frame
.iconify_button
== ee
->window
)
2567 redrawIconifyButton(False
);
2571 void BlackboxWindow::configureRequestEvent(XConfigureRequestEvent
*cr
) {
2572 if (cr
->window
!= client
.window
|| flags
.iconic
)
2575 int cx
= frame
.rect
.x(), cy
= frame
.rect
.y();
2576 unsigned int cw
= frame
.rect
.width(), ch
= frame
.rect
.height();
2578 if (cr
->value_mask
& CWBorderWidth
)
2579 client
.old_bw
= cr
->border_width
;
2581 if (cr
->value_mask
& CWX
)
2582 cx
= cr
->x
- frame
.margin
.left
;
2584 if (cr
->value_mask
& CWY
)
2585 cy
= cr
->y
- frame
.margin
.top
;
2587 if (cr
->value_mask
& CWWidth
)
2588 cw
= cr
->width
+ frame
.margin
.left
+ frame
.margin
.right
;
2590 if (cr
->value_mask
& CWHeight
)
2591 ch
= cr
->height
+ frame
.margin
.top
+ frame
.margin
.bottom
;
2593 if (frame
.rect
!= Rect(cx
, cy
, cw
, ch
))
2594 configure(cx
, cy
, cw
, ch
);
2596 if (cr
->value_mask
& CWStackMode
) {
2597 switch (cr
->detail
) {
2600 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2606 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2613 void BlackboxWindow::buttonPressEvent(XButtonEvent
*be
) {
2614 if (frame
.maximize_button
== be
->window
) {
2615 redrawMaximizeButton(True
);
2616 } else if (be
->button
== 1 || (be
->button
== 3 && be
->state
== Mod1Mask
)) {
2617 if (! flags
.focused
)
2620 if (frame
.iconify_button
== be
->window
) {
2621 redrawIconifyButton(True
);
2622 } else if (frame
.close_button
== be
->window
) {
2623 redrawCloseButton(True
);
2624 } else if (frame
.plate
== be
->window
) {
2625 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2627 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2629 XAllowEvents(blackbox
->getXDisplay(), ReplayPointer
, be
->time
);
2631 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
2632 if (((be
->time
- lastButtonPressTime
) <=
2633 blackbox
->getDoubleClickInterval()) ||
2634 (be
->state
& ControlMask
)) {
2635 lastButtonPressTime
= 0;
2638 lastButtonPressTime
= be
->time
;
2642 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2644 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2646 } else if (be
->button
== 2 && (be
->window
!= frame
.iconify_button
) &&
2647 (be
->window
!= frame
.close_button
)) {
2648 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2649 } else if (windowmenu
&& be
->button
== 3 &&
2650 (frame
.title
== be
->window
|| frame
.label
== be
->window
||
2651 frame
.handle
== be
->window
|| frame
.window
== be
->window
)) {
2654 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
2655 mx
= be
->x_root
- (windowmenu
->getWidth() / 2);
2656 my
= frame
.rect
.y() + frame
.title_h
+ frame
.border_w
;
2657 } else if (frame
.handle
== be
->window
) {
2658 mx
= be
->x_root
- (windowmenu
->getWidth() / 2);
2659 my
= frame
.rect
.bottom() - frame
.handle_h
- (frame
.border_w
* 3) -
2660 windowmenu
->getHeight();
2662 mx
= be
->x_root
- (windowmenu
->getWidth() / 2);
2664 if (be
->y
<= static_cast<signed>(frame
.bevel_w
))
2665 my
= frame
.rect
.y() + frame
.title_h
;
2667 my
= be
->y_root
- (windowmenu
->getHeight() / 2);
2670 // snap the window menu into a corner if necessary - we check the
2671 // position of the menu with the coordinates of the client to
2672 // make the comparisions easier.
2673 // XXX: this needs some work!
2674 if (mx
> client
.rect
.right() -
2675 static_cast<signed>(windowmenu
->getWidth()))
2676 mx
= frame
.rect
.right() - windowmenu
->getWidth() - frame
.border_w
+ 1;
2677 if (mx
< client
.rect
.left())
2678 mx
= frame
.rect
.x();
2680 if (my
> client
.rect
.bottom() -
2681 static_cast<signed>(windowmenu
->getHeight()))
2682 my
= frame
.rect
.bottom() - windowmenu
->getHeight() - frame
.border_w
+ 1;
2683 if (my
< client
.rect
.top())
2684 my
= frame
.rect
.y() + ((decorations
& Decor_Titlebar
) ?
2688 if (! windowmenu
->isVisible()) {
2689 windowmenu
->move(mx
, my
);
2691 XRaiseWindow(blackbox
->getXDisplay(), windowmenu
->getWindowID());
2692 XRaiseWindow(blackbox
->getXDisplay(),
2693 windowmenu
->getSendToMenu()->getWindowID());
2699 } else if (be
->button
== 4) {
2700 if ((be
->window
== frame
.label
||
2701 be
->window
== frame
.title
) &&
2705 } else if (be
->button
== 5) {
2706 if ((be
->window
== frame
.label
||
2707 be
->window
== frame
.title
) &&
2714 void BlackboxWindow::buttonReleaseEvent(XButtonEvent
*re
) {
2715 if (re
->window
== frame
.maximize_button
) {
2716 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2717 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2718 maximize(re
->button
);
2720 redrawMaximizeButton(flags
.maximized
);
2722 } else if (re
->window
== frame
.iconify_button
) {
2723 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2724 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2727 redrawIconifyButton(False
);
2729 } else if (re
->window
== frame
.close_button
) {
2730 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2731 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
)))
2733 redrawCloseButton(False
);
2734 } else if (flags
.moving
) {
2736 } else if (flags
.resizing
) {
2738 } else if (re
->window
== frame
.window
) {
2739 if (re
->button
== 2 && re
->state
== Mod1Mask
)
2740 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
2745 void BlackboxWindow::beginMove(int x_root
, int y_root
) {
2746 assert(! (flags
.resizing
|| flags
.moving
));
2749 Only one window can be moved/resized at a time. If another window is already
2750 being moved or resized, then stop it before whating to work with this one.
2752 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
2753 if (changing
&& changing
!= this) {
2754 if (changing
->flags
.moving
)
2755 changing
->endMove();
2756 else // if (changing->flags.resizing)
2757 changing
->endResize();
2760 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
2761 PointerMotionMask
| ButtonReleaseMask
,
2762 GrabModeAsync
, GrabModeAsync
,
2763 None
, blackbox
->getMoveCursor(), CurrentTime
);
2765 if (windowmenu
&& windowmenu
->isVisible())
2768 flags
.moving
= True
;
2769 blackbox
->setChangingWindow(this);
2771 if (! screen
->doOpaqueMove()) {
2772 XGrabServer(blackbox
->getXDisplay());
2774 frame
.changing
= frame
.rect
;
2775 screen
->showPosition(frame
.changing
.x(), frame
.changing
.y());
2777 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2781 frame
.changing
.width() - 1,
2782 frame
.changing
.height() - 1);
2785 frame
.grab_x
= x_root
- frame
.rect
.x() - frame
.border_w
;
2786 frame
.grab_y
= y_root
- frame
.rect
.y() - frame
.border_w
;
2789 void BlackboxWindow::doMove(int x_root
, int y_root
) {
2790 assert(flags
.moving
);
2791 assert(blackbox
->getChangingWindow() == this);
2793 int dx
= x_root
- frame
.grab_x
, dy
= y_root
- frame
.grab_y
;
2794 dx
-= frame
.border_w
;
2795 dy
-= frame
.border_w
;
2797 const int snap_distance
= screen
->getEdgeSnapThreshold();
2799 if (snap_distance
) {
2800 Rect srect
= screen
->availableArea();
2802 const int wleft
= dx
,
2803 wright
= dx
+ frame
.rect
.width() - 1,
2805 wbottom
= dy
+ frame
.rect
.height() - 1;
2807 int dleft
= std::abs(wleft
- srect
.left()),
2808 dright
= std::abs(wright
- srect
.right()),
2809 dtop
= std::abs(wtop
- srect
.top()),
2810 dbottom
= std::abs(wbottom
- srect
.bottom());
2813 if (dleft
< snap_distance
&& dleft
< dright
)
2816 else if (dright
< snap_distance
&& dright
< dleft
)
2817 dx
= srect
.right() - frame
.rect
.width() + 1;
2820 if (dtop
< snap_distance
&& dtop
< dbottom
)
2823 else if (dbottom
< snap_distance
&& dbottom
< dtop
)
2824 dy
= srect
.bottom() - frame
.rect
.height() + 1;
2826 srect
= screen
->getRect(); // now get the full screen
2828 dleft
= std::abs(wleft
- srect
.left()),
2829 dright
= std::abs(wright
- srect
.right()),
2830 dtop
= std::abs(wtop
- srect
.top()),
2831 dbottom
= std::abs(wbottom
- srect
.bottom());
2834 if (dleft
< snap_distance
&& dleft
< dright
)
2837 else if (dright
< snap_distance
&& dright
< dleft
)
2838 dx
= srect
.right() - frame
.rect
.width() + 1;
2841 if (dtop
< snap_distance
&& dtop
< dbottom
)
2844 else if (dbottom
< snap_distance
&& dbottom
< dtop
)
2845 dy
= srect
.bottom() - frame
.rect
.height() + 1;
2848 if (screen
->doOpaqueMove()) {
2849 configure(dx
, dy
, frame
.rect
.width(), frame
.rect
.height());
2851 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2855 frame
.changing
.width() - 1,
2856 frame
.changing
.height() - 1);
2858 frame
.changing
.setPos(dx
, dy
);
2860 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2864 frame
.changing
.width() - 1,
2865 frame
.changing
.height() - 1);
2868 screen
->showPosition(dx
, dy
);
2872 void BlackboxWindow::endMove(void) {
2873 assert(flags
.moving
);
2874 assert(blackbox
->getChangingWindow() == this);
2876 flags
.moving
= False
;
2877 blackbox
->setChangingWindow(0);
2879 if (! screen
->doOpaqueMove()) {
2880 /* when drawing the rubber band, we need to make sure we only draw inside
2881 * the frame... frame.changing_* contain the new coords for the window,
2882 * so we need to subtract 1 from changing_w/changing_h every where we
2883 * draw the rubber band (for both moving and resizing)
2885 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2886 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
2887 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
2888 XUngrabServer(blackbox
->getXDisplay());
2890 configure(frame
.changing
.x(), frame
.changing
.y(),
2891 frame
.changing
.width(), frame
.changing
.height());
2893 configure(frame
.rect
.x(), frame
.rect
.y(),
2894 frame
.rect
.width(), frame
.rect
.height());
2896 screen
->hideGeometry();
2898 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
2900 // if there are any left over motions from the move, drop them now
2901 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
2903 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
2908 void BlackboxWindow::beginResize(int x_root
, int y_root
, Corner dir
) {
2909 assert(! (flags
.resizing
|| flags
.moving
));
2912 Only one window can be moved/resized at a time. If another window is already
2913 being moved or resized, then stop it before whating to work with this one.
2915 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
2916 if (changing
&& changing
!= this) {
2917 if (changing
->flags
.moving
)
2918 changing
->endMove();
2919 else // if (changing->flags.resizing)
2920 changing
->endResize();
2928 switch (resize_dir
) {
2931 cursor
= blackbox
->getLowerLeftAngleCursor();
2936 cursor
= blackbox
->getLowerRightAngleCursor();
2940 anchor
= BottomRight
;
2941 cursor
= blackbox
->getUpperLeftAngleCursor();
2945 anchor
= BottomLeft
;
2946 cursor
= blackbox
->getUpperRightAngleCursor();
2950 assert(false); // unhandled Corner
2953 XGrabServer(blackbox
->getXDisplay());
2954 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
2955 PointerMotionMask
| ButtonReleaseMask
,
2956 GrabModeAsync
, GrabModeAsync
, None
, cursor
, CurrentTime
);
2958 flags
.resizing
= True
;
2959 blackbox
->setChangingWindow(this);
2962 frame
.changing
= frame
.rect
;
2964 constrain(anchor
, &gw
, &gh
);
2966 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2967 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
2968 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
2970 screen
->showGeometry(gw
, gh
);
2972 frame
.grab_x
= x_root
;
2973 frame
.grab_y
= y_root
;
2977 void BlackboxWindow::doResize(int x_root
, int y_root
) {
2978 assert(flags
.resizing
);
2979 assert(blackbox
->getChangingWindow() == this);
2981 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2982 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
2983 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
2988 switch (resize_dir
) {
2991 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
2992 frame
.rect
.height() + (y_root
- frame
.grab_y
));
2996 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
2997 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3000 anchor
= BottomRight
;
3001 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3002 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3005 anchor
= BottomLeft
;
3006 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3007 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3011 assert(false); // unhandled Corner
3014 constrain(anchor
, &gw
, &gh
);
3016 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3017 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3018 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3020 screen
->showGeometry(gw
, gh
);
3024 void BlackboxWindow::endResize(void) {
3025 assert(flags
.resizing
);
3026 assert(blackbox
->getChangingWindow() == this);
3028 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3029 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3030 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3031 XUngrabServer(blackbox
->getXDisplay());
3033 // unset maximized state after resized when fully maximized
3034 if (flags
.maximized
== 1)
3037 flags
.resizing
= False
;
3038 blackbox
->setChangingWindow(0);
3040 configure(frame
.changing
.x(), frame
.changing
.y(),
3041 frame
.changing
.width(), frame
.changing
.height());
3042 screen
->hideGeometry();
3044 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3046 // if there are any left over motions from the resize, drop them now
3047 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3049 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3054 void BlackboxWindow::motionNotifyEvent(XMotionEvent
*me
) {
3056 doMove(me
->x_root
, me
->y_root
);
3057 } else if (flags
.resizing
) {
3058 doResize(me
->x_root
, me
->y_root
);
3060 if (! flags
.resizing
&& (me
->state
& Button1Mask
) &&
3061 (functions
& Func_Move
) &&
3062 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3063 frame
.handle
== me
->window
|| frame
.window
== me
->window
)) {
3064 beginMove(me
->x_root
, me
->y_root
);
3065 } else if ((functions
& Func_Resize
) &&
3066 (((me
->state
& Button1Mask
) &&
3067 (me
->window
== frame
.right_grip
||
3068 me
->window
== frame
.left_grip
)) ||
3069 (me
->state
& (Mod1Mask
| Button3Mask
) &&
3070 me
->window
== frame
.window
))) {
3071 beginResize(me
->x_root
, me
->y_root
,
3072 (me
->window
== frame
.left_grip
) ? BottomLeft
: BottomRight
);
3079 void BlackboxWindow::shapeEvent(XShapeEvent
*) {
3080 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
3087 bool BlackboxWindow::validateClient(void) const {
3088 XSync(blackbox
->getXDisplay(), False
);
3091 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3092 DestroyNotify
, &e
) ||
3093 XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3095 XPutBackEvent(blackbox
->getXDisplay(), &e
);
3104 void BlackboxWindow::restore(bool remap
) {
3105 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeDelete
);
3106 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
3107 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, NoEventMask
);
3111 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
3112 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
3114 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, client
.old_bw
);
3117 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3118 ReparentNotify
, &ev
)) {
3121 // according to the ICCCM - if the client doesn't reparent to
3122 // root, then we have to do it for them
3123 XReparentWindow(blackbox
->getXDisplay(), client
.window
,
3124 screen
->getRootWindow(),
3125 client
.rect
.x(), client
.rect
.y());
3128 if (remap
) XMapWindow(blackbox
->getXDisplay(), client
.window
);
3132 // timer for autoraise
3133 void BlackboxWindow::timeout(void) {
3134 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3138 void BlackboxWindow::changeBlackboxHints(BlackboxHints
*net
) {
3139 if ((net
->flags
& AttribShaded
) &&
3140 ((blackbox_attrib
.attrib
& AttribShaded
) !=
3141 (net
->attrib
& AttribShaded
)))
3144 if (flags
.visible
&& // watch out for requests when we can not be seen
3145 (net
->flags
& (AttribMaxVert
| AttribMaxHoriz
)) &&
3146 ((blackbox_attrib
.attrib
& (AttribMaxVert
| AttribMaxHoriz
)) !=
3147 (net
->attrib
& (AttribMaxVert
| AttribMaxHoriz
)))) {
3148 if (flags
.maximized
) {
3153 if ((net
->flags
& AttribMaxHoriz
) && (net
->flags
& AttribMaxVert
))
3154 button
= ((net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0);
3155 else if (net
->flags
& AttribMaxVert
)
3156 button
= ((net
->attrib
& AttribMaxVert
) ? 2 : 0);
3157 else if (net
->flags
& AttribMaxHoriz
)
3158 button
= ((net
->attrib
& AttribMaxHoriz
) ? 3 : 0);
3164 if ((net
->flags
& AttribOmnipresent
) &&
3165 ((blackbox_attrib
.attrib
& AttribOmnipresent
) !=
3166 (net
->attrib
& AttribOmnipresent
)))
3169 if ((net
->flags
& AttribWorkspace
) &&
3170 (blackbox_attrib
.workspace
!= net
->workspace
)) {
3171 screen
->reassociateWindow(this, net
->workspace
, True
);
3173 if (screen
->getCurrentWorkspaceID() != net
->workspace
) {
3177 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3181 if (net
->flags
& AttribDecoration
) {
3182 switch (net
->decoration
) {
3184 // clear all decorations except close
3185 decorations
&= Decor_Close
;
3191 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Iconify
;
3193 decorations
= ((functions
& Func_Resize
) && !isTransient() ?
3194 decorations
| Decor_Handle
:
3195 decorations
&= ~Decor_Handle
);
3196 decorations
= (functions
& Func_Maximize
?
3197 decorations
| Decor_Maximize
:
3198 decorations
&= ~Decor_Maximize
);
3203 decorations
|= Decor_Titlebar
| Decor_Iconify
;
3204 decorations
&= ~(Decor_Border
| Decor_Handle
);
3206 decorations
= (functions
& Func_Maximize
?
3207 decorations
| Decor_Maximize
:
3208 decorations
&= ~Decor_Maximize
);
3213 decorations
|= Decor_Titlebar
;
3214 decorations
&= ~(Decor_Iconify
| Decor_Border
);
3216 decorations
= ((functions
& Func_Resize
) && !isTransient() ?
3217 decorations
| Decor_Handle
:
3218 decorations
&= ~Decor_Handle
);
3219 decorations
= (functions
& Func_Maximize
?
3220 decorations
| Decor_Maximize
:
3221 decorations
&= ~Decor_Maximize
);
3226 // we can not be shaded if we lack a titlebar
3227 if (flags
.shaded
&& ! (decorations
& Decor_Titlebar
))
3231 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
3232 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
3236 setState(current_state
);
3242 * Set the sizes of all components of the window frame
3243 * (the window decorations).
3244 * These values are based upon the current style settings and the client
3245 * window's dimensions.
3247 void BlackboxWindow::upsize(void) {
3248 frame
.bevel_w
= screen
->getBevelWidth();
3250 if (decorations
& Decor_Border
) {
3251 frame
.border_w
= screen
->getBorderWidth();
3252 if (! isTransient())
3253 frame
.mwm_border_w
= screen
->getFrameWidth();
3255 frame
.mwm_border_w
= 0;
3257 frame
.mwm_border_w
= frame
.border_w
= 0;
3260 if (decorations
& Decor_Titlebar
) {
3261 // the height of the titlebar is based upon the height of the font being
3262 // used to display the window's title
3263 WindowStyle
*style
= screen
->getWindowStyle();
3264 if (i18n
.multibyte())
3265 frame
.title_h
= (style
->fontset_extents
->max_ink_extent
.height
+
3266 (frame
.bevel_w
* 2) + 2);
3268 frame
.title_h
= (style
->font
->ascent
+ style
->font
->descent
+
3269 (frame
.bevel_w
* 2) + 2);
3271 frame
.label_h
= frame
.title_h
- (frame
.bevel_w
* 2);
3272 frame
.button_w
= (frame
.label_h
- 2);
3274 // set the top frame margin
3275 frame
.margin
.top
= frame
.border_w
+ frame
.title_h
+
3276 frame
.border_w
+ frame
.mwm_border_w
;
3282 // set the top frame margin
3283 frame
.margin
.top
= frame
.border_w
+ frame
.mwm_border_w
;
3286 // set the left/right frame margin
3287 frame
.margin
.left
= frame
.margin
.right
= frame
.border_w
+ frame
.mwm_border_w
;
3289 if (decorations
& Decor_Handle
) {
3290 frame
.grip_w
= frame
.button_w
* 2;
3291 frame
.handle_h
= screen
->getHandleWidth();
3293 // set the bottom frame margin
3294 frame
.margin
.bottom
= frame
.border_w
+ frame
.handle_h
+
3295 frame
.border_w
+ frame
.mwm_border_w
;
3300 // set the bottom frame margin
3301 frame
.margin
.bottom
= frame
.border_w
+ frame
.mwm_border_w
;
3305 We first get the normal dimensions and use this to define the inside_w/h
3306 then we modify the height if shading is in effect.
3307 If the shade state is not considered then frame.rect gets reset to the
3308 normal window size on a reconfigure() call resulting in improper
3309 dimensions appearing in move/resize and other events.
3312 height
= client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
,
3313 width
= client
.rect
.width() + frame
.margin
.left
+ frame
.margin
.right
;
3315 frame
.inside_w
= width
- (frame
.border_w
* 2);
3316 frame
.inside_h
= height
- (frame
.border_w
* 2);
3319 height
= frame
.title_h
+ (frame
.border_w
* 2);
3320 frame
.rect
.setSize(width
, height
);
3325 * Calculate the size of the client window and constrain it to the
3326 * size specified by the size hints of the client window.
3328 * The logical width and height are placed into pw and ph, if they
3329 * are non-zero. Logical size refers to the users perception of
3330 * the window size (for example an xterm resizes in cells, not in pixels).
3332 * The physical geometry is placed into frame.changing_{x,y,width,height}.
3333 * Physical geometry refers to the geometry of the window in pixels.
3335 void BlackboxWindow::constrain(Corner anchor
, int *pw
, int *ph
) {
3336 // frame.changing represents the requested frame size, we need to
3337 // strip the frame margin off and constrain the client size
3338 frame
.changing
.setCoords(frame
.changing
.left() + frame
.margin
.left
,
3339 frame
.changing
.top() + frame
.margin
.top
,
3340 frame
.changing
.right() - frame
.margin
.right
,
3341 frame
.changing
.bottom() - frame
.margin
.bottom
);
3343 int dw
= frame
.changing
.width(), dh
= frame
.changing
.height(),
3344 base_width
= (client
.base_width
) ? client
.base_width
: client
.min_width
,
3345 base_height
= (client
.base_height
) ? client
.base_height
:
3349 if (dw
< static_cast<signed>(client
.min_width
)) dw
= client
.min_width
;
3350 if (dh
< static_cast<signed>(client
.min_height
)) dh
= client
.min_height
;
3351 if (dw
> static_cast<signed>(client
.max_width
)) dw
= client
.max_width
;
3352 if (dh
> static_cast<signed>(client
.max_height
)) dh
= client
.max_height
;
3355 dw
/= client
.width_inc
;
3357 dh
/= client
.height_inc
;
3362 dw
*= client
.width_inc
;
3364 dh
*= client
.height_inc
;
3367 frame
.changing
.setSize(dw
, dh
);
3369 // add the frame margin back onto frame.changing
3370 frame
.changing
.setCoords(frame
.changing
.left() - frame
.margin
.left
,
3371 frame
.changing
.top() - frame
.margin
.top
,
3372 frame
.changing
.right() + frame
.margin
.right
,
3373 frame
.changing
.bottom() + frame
.margin
.bottom
);
3375 // move frame.changing to the specified anchor
3383 dx
= frame
.rect
.right() - frame
.changing
.right();
3387 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3391 dx
= frame
.rect
.right() - frame
.changing
.right();
3392 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3396 assert(false); // unhandled corner
3398 frame
.changing
.setPos(frame
.changing
.x() + dx
, frame
.changing
.y() + dy
);
3402 int WindowStyle::doJustify(const char *text
, int &start_pos
,
3403 unsigned int max_length
, unsigned int modifier
,
3404 bool multibyte
) const {
3405 size_t text_len
= strlen(text
);
3406 unsigned int length
;
3410 XRectangle ink
, logical
;
3411 XmbTextExtents(fontset
, text
, text_len
, &ink
, &logical
);
3412 length
= logical
.width
;
3414 length
= XTextWidth(font
, text
, text_len
);
3417 } while (length
> max_length
&& text_len
-- > 0);
3421 start_pos
+= max_length
- length
;
3425 start_pos
+= (max_length
- length
) / 2;
3437 BWindowGroup::BWindowGroup(Blackbox
*b
, Window _group
)
3438 : blackbox(b
), group(_group
) {
3439 XWindowAttributes wattrib
;
3440 if (! XGetWindowAttributes(blackbox
->getXDisplay(), group
, &wattrib
)) {
3441 // group window doesn't seem to exist anymore
3447 watch for destroy notify on the group window (in addition to
3448 any other events we are looking for)
3450 since some managed windows can also be window group controllers,
3451 we need to make sure that we don't clobber the event mask for the
3454 XSelectInput(blackbox
->getXDisplay(), group
,
3455 wattrib
.your_event_mask
| StructureNotifyMask
);
3457 blackbox
->saveGroupSearch(group
, this);
3461 BWindowGroup::~BWindowGroup(void) {
3462 blackbox
->removeGroupSearch(group
);
3467 BWindowGroup::find(BScreen
*screen
, bool allow_transients
) const {
3468 BlackboxWindow
*ret
= blackbox
->getFocusedWindow();
3470 // does the focus window match (or any transient_fors)?
3472 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3473 if (ret
->isTransient() && allow_transients
) break;
3474 else if (! ret
->isTransient()) break;
3477 ret
= ret
->getTransientFor();
3480 if (ret
) return ret
;
3482 // the focus window didn't match, look in the group's window list
3483 BlackboxWindowList::const_iterator it
, end
= windowList
.end();
3484 for (it
= windowList
.begin(); it
!= end
; ++it
) {
3486 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3487 if (ret
->isTransient() && allow_transients
) break;
3488 else if (! ret
->isTransient()) break;