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
= False
;
116 blackbox_attrib
.workspace
= window_number
= BSENTINEL
;
118 blackbox_attrib
.flags
= blackbox_attrib
.attrib
= blackbox_attrib
.stack
119 = blackbox_attrib
.decoration
= 0l;
120 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
121 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
124 frame
.window
= frame
.plate
= frame
.title
= frame
.handle
= None
;
125 frame
.close_button
= frame
.iconify_button
= frame
.maximize_button
= None
;
126 frame
.right_grip
= frame
.left_grip
= None
;
128 frame
.ulabel_pixel
= frame
.flabel_pixel
= frame
.utitle_pixel
=
129 frame
.ftitle_pixel
= frame
.uhandle_pixel
= frame
.fhandle_pixel
=
130 frame
.ubutton_pixel
= frame
.fbutton_pixel
= frame
.pbutton_pixel
=
131 frame
.uborder_pixel
= frame
.fborder_pixel
= frame
.ugrip_pixel
=
132 frame
.fgrip_pixel
= 0;
133 frame
.utitle
= frame
.ftitle
= frame
.uhandle
= frame
.fhandle
= None
;
134 frame
.ulabel
= frame
.flabel
= frame
.ubutton
= frame
.fbutton
= None
;
135 frame
.pbutton
= frame
.ugrip
= frame
.fgrip
= decorations
;
137 decorations
= Decor_Titlebar
| Decor_Border
| Decor_Handle
|
138 Decor_Iconify
| Decor_Maximize
;
139 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
141 client
.wm_hint_flags
= client
.normal_hint_flags
= 0;
142 client
.transient_for
= 0;
145 get the initial size and location of client window (relative to the
146 _root window_). This position is the reference point used with the
147 window's gravity to find the window's initial position.
149 client
.rect
.setRect(wattrib
.x
, wattrib
.y
, wattrib
.width
, wattrib
.height
);
150 client
.old_bw
= wattrib
.border_width
;
153 lastButtonPressTime
= 0;
155 timer
= new BTimer(blackbox
, this);
156 timer
->setTimeout(blackbox
->getAutoRaiseDelay());
158 if (! getBlackboxHints())
161 // get size, aspect, minimum/maximum size and other hints set by the
167 if (client
.initial_state
== WithdrawnState
) {
168 screen
->getSlit()->addClient(client
.window
);
173 frame
.window
= createToplevelWindow();
174 frame
.plate
= createChildWindow(frame
.window
);
175 associateClientWindow();
177 blackbox
->saveWindowSearch(frame
.window
, this);
178 blackbox
->saveWindowSearch(frame
.plate
, this);
179 blackbox
->saveWindowSearch(client
.window
, this);
181 // determine if this is a transient window
184 // adjust the window decorations based on transience and window sizes
186 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
187 functions
&= ~Func_Maximize
;
190 if ((client
.normal_hint_flags
& PMinSize
) &&
191 (client
.normal_hint_flags
& PMaxSize
) &&
192 client
.max_width
<= client
.min_width
&&
193 client
.max_height
<= client
.min_height
) {
194 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
195 functions
&= ~(Func_Resize
| Func_Maximize
);
199 bool place_window
= True
;
200 if (blackbox
->isStartup() || isTransient() ||
201 client
.normal_hint_flags
& (PPosition
|USPosition
)) {
205 if (blackbox
->isStartup() ||
206 client
.rect
.intersects(screen
->availableArea()))
207 place_window
= False
;
210 if (decorations
& Decor_Titlebar
)
213 if (decorations
& Decor_Handle
)
217 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
222 if ((! screen
->isSloppyFocus()) || screen
->doClickRaise()) {
223 // grab button 1 for changing focus/raising
224 blackbox
->grabButton(Button1
, 0, frame
.plate
, True
, ButtonPressMask
,
225 GrabModeSync
, GrabModeSync
, frame
.plate
, None
);
228 blackbox
->grabButton(Button1
, Mod1Mask
, frame
.window
, True
,
229 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
230 GrabModeAsync
, frame
.window
, blackbox
->getMoveCursor());
231 blackbox
->grabButton(Button2
, Mod1Mask
, frame
.window
, True
,
232 ButtonReleaseMask
, GrabModeAsync
, GrabModeAsync
,
234 blackbox
->grabButton(Button3
, Mod1Mask
, frame
.window
, True
,
235 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
236 GrabModeAsync
, frame
.window
,
237 blackbox
->getLowerRightAngleCursor());
242 if (decorations
& Decor_Titlebar
)
243 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
244 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
246 windowmenu
= new Windowmenu(this);
248 if (blackbox_attrib
.workspace
>= screen
->getWorkspaceCount())
249 screen
->getCurrentWorkspace()->addWindow(this, place_window
);
251 screen
->getWorkspace(blackbox_attrib
.workspace
)->
252 addWindow(this, place_window
);
254 if (! place_window
) {
255 // don't need to call configure if we are letting the workspace
257 configure(frame
.rect
.x(), frame
.rect
.y(),
258 frame
.rect
.width(), frame
.rect
.height());
261 // preserve the window's initial state on first map, and its current state
264 if (client
.wm_hint_flags
& StateHint
)
265 current_state
= client
.initial_state
;
267 current_state
= NormalState
;
271 flags
.shaded
= False
;
275 Because the iconic'ness of shaded windows is lost, we need to set the
276 state to NormalState so that shaded windows on other workspaces will not
277 get shown on the first workspace.
278 At this point in the life of a window, current_state should only be set
279 to IconicState if the window was an *icon*, not if it was shaded.
281 current_state
= NormalState
;
289 if (flags
.maximized
&& (functions
& Func_Maximize
)) {
294 When the window is mapped (and also when its attributes are restored), the
295 current_state that was set here will be used.
296 It is set to Normal if the window is to be mapped or it is set to Iconic
297 if the window is to be iconified.
298 *Note* that for sticky windows, the same rules apply here, they are in
299 fact never set to Iconic since there is no way for us to tell if a sticky
300 window was iconified previously.
307 BlackboxWindow::~BlackboxWindow(void) {
309 fprintf(stderr
, "BlackboxWindow::~BlackboxWindow: destroying 0x%lx\n",
313 if (! timer
) // window not managed...
316 if (flags
.moving
|| flags
.resizing
) {
317 screen
->hideGeometry();
318 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
325 if (client
.window_group
) {
326 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
327 if (group
) group
->removeWindow(this);
330 // remove ourselves from our transient_for
332 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
333 client
.transient_for
->client
.transientList
.remove(this);
335 client
.transient_for
= (BlackboxWindow
*) 0;
338 if (client
.transientList
.size() > 0) {
339 // reset transient_for for all transients
340 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
341 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
342 (*it
)->client
.transient_for
= (BlackboxWindow
*) 0;
353 blackbox
->removeWindowSearch(frame
.plate
);
354 XDestroyWindow(blackbox
->getXDisplay(), frame
.plate
);
358 blackbox
->removeWindowSearch(frame
.window
);
359 XDestroyWindow(blackbox
->getXDisplay(), frame
.window
);
362 blackbox
->removeWindowSearch(client
.window
);
367 * Creates a new top level window, with a given location, size, and border
369 * Returns: the newly created window
371 Window
BlackboxWindow::createToplevelWindow(void) {
372 XSetWindowAttributes attrib_create
;
373 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
| CWColormap
|
374 CWOverrideRedirect
| CWEventMask
;
376 attrib_create
.background_pixmap
= None
;
377 attrib_create
.colormap
= screen
->getColormap();
378 attrib_create
.override_redirect
= True
;
379 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
380 ButtonMotionMask
| EnterWindowMask
;
382 return XCreateWindow(blackbox
->getXDisplay(), screen
->getRootWindow(),
383 -1, -1, 1, 1, frame
.border_w
, screen
->getDepth(),
384 InputOutput
, screen
->getVisual(), create_mask
,
390 * Creates a child window, and optionally associates a given cursor with
393 Window
BlackboxWindow::createChildWindow(Window parent
, Cursor cursor
) {
394 XSetWindowAttributes attrib_create
;
395 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
|
398 attrib_create
.background_pixmap
= None
;
399 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
400 ButtonMotionMask
| ExposureMask
;
403 create_mask
|= CWCursor
;
404 attrib_create
.cursor
= cursor
;
407 return XCreateWindow(blackbox
->getXDisplay(), parent
, 0, 0, 1, 1, 0,
408 screen
->getDepth(), InputOutput
, screen
->getVisual(),
409 create_mask
, &attrib_create
);
413 void BlackboxWindow::associateClientWindow(void) {
414 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, 0);
418 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeInsert
);
420 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, SubstructureRedirectMask
);
422 XGrabServer(blackbox
->getXDisplay());
423 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
424 XReparentWindow(blackbox
->getXDisplay(), client
.window
, frame
.plate
, 0, 0);
425 XSelectInput(blackbox
->getXDisplay(), client
.window
,
426 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
427 XUngrabServer(blackbox
->getXDisplay());
429 XRaiseWindow(blackbox
->getXDisplay(), frame
.plate
);
430 XMapSubwindows(blackbox
->getXDisplay(), frame
.plate
);
434 if (blackbox
->hasShapeExtensions()) {
435 XShapeSelectInput(blackbox
->getXDisplay(), client
.window
,
442 XShapeQueryExtents(blackbox
->getXDisplay(), client
.window
, &shaped
,
443 &foo
, &foo
, &ufoo
, &ufoo
, &foo
, &foo
, &foo
,
445 flags
.shaped
= shaped
;
451 void BlackboxWindow::decorate(void) {
454 texture
= &(screen
->getWindowStyle()->b_focus
);
455 frame
.fbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
458 frame
.fbutton_pixel
= texture
->color().pixel();
460 texture
= &(screen
->getWindowStyle()->b_unfocus
);
461 frame
.ubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
464 frame
.ubutton_pixel
= texture
->color().pixel();
466 texture
= &(screen
->getWindowStyle()->b_pressed
);
467 frame
.pbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
470 frame
.pbutton_pixel
= texture
->color().pixel();
472 if (decorations
& Decor_Titlebar
) {
473 texture
= &(screen
->getWindowStyle()->t_focus
);
474 frame
.ftitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
477 frame
.ftitle_pixel
= texture
->color().pixel();
479 texture
= &(screen
->getWindowStyle()->t_unfocus
);
480 frame
.utitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
483 frame
.utitle_pixel
= texture
->color().pixel();
485 XSetWindowBorder(blackbox
->getXDisplay(), frame
.title
,
486 screen
->getBorderColor()->pixel());
491 if (decorations
& Decor_Border
) {
492 frame
.fborder_pixel
= screen
->getWindowStyle()->f_focus
.pixel();
493 frame
.uborder_pixel
= screen
->getWindowStyle()->f_unfocus
.pixel();
494 blackbox_attrib
.flags
|= AttribDecoration
;
495 blackbox_attrib
.decoration
= DecorNormal
;
497 blackbox_attrib
.flags
|= AttribDecoration
;
498 blackbox_attrib
.decoration
= DecorNone
;
501 if (decorations
& Decor_Handle
) {
502 texture
= &(screen
->getWindowStyle()->h_focus
);
503 frame
.fhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
506 frame
.fhandle_pixel
= texture
->color().pixel();
508 texture
= &(screen
->getWindowStyle()->h_unfocus
);
509 frame
.uhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
512 frame
.uhandle_pixel
= texture
->color().pixel();
514 texture
= &(screen
->getWindowStyle()->g_focus
);
515 frame
.fgrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.fgrip
);
517 frame
.fgrip_pixel
= texture
->color().pixel();
519 texture
= &(screen
->getWindowStyle()->g_unfocus
);
520 frame
.ugrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.ugrip
);
522 frame
.ugrip_pixel
= texture
->color().pixel();
524 XSetWindowBorder(blackbox
->getXDisplay(), frame
.handle
,
525 screen
->getBorderColor()->pixel());
526 XSetWindowBorder(blackbox
->getXDisplay(), frame
.left_grip
,
527 screen
->getBorderColor()->pixel());
528 XSetWindowBorder(blackbox
->getXDisplay(), frame
.right_grip
,
529 screen
->getBorderColor()->pixel());
532 XSetWindowBorder(blackbox
->getXDisplay(), frame
.window
,
533 screen
->getBorderColor()->pixel());
537 void BlackboxWindow::decorateLabel(void) {
540 texture
= &(screen
->getWindowStyle()->l_focus
);
541 frame
.flabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.flabel
);
543 frame
.flabel_pixel
= texture
->color().pixel();
545 texture
= &(screen
->getWindowStyle()->l_unfocus
);
546 frame
.ulabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.ulabel
);
548 frame
.ulabel_pixel
= texture
->color().pixel();
552 void BlackboxWindow::createHandle(void) {
553 frame
.handle
= createChildWindow(frame
.window
);
554 blackbox
->saveWindowSearch(frame
.handle
, this);
557 createChildWindow(frame
.handle
, blackbox
->getLowerLeftAngleCursor());
558 blackbox
->saveWindowSearch(frame
.left_grip
, this);
561 createChildWindow(frame
.handle
, blackbox
->getLowerRightAngleCursor());
562 blackbox
->saveWindowSearch(frame
.right_grip
, this);
566 void BlackboxWindow::destroyHandle(void) {
568 screen
->getImageControl()->removeImage(frame
.fhandle
);
571 screen
->getImageControl()->removeImage(frame
.uhandle
);
574 screen
->getImageControl()->removeImage(frame
.fgrip
);
577 screen
->getImageControl()->removeImage(frame
.ugrip
);
579 blackbox
->removeWindowSearch(frame
.left_grip
);
580 blackbox
->removeWindowSearch(frame
.right_grip
);
582 XDestroyWindow(blackbox
->getXDisplay(), frame
.left_grip
);
583 XDestroyWindow(blackbox
->getXDisplay(), frame
.right_grip
);
584 frame
.left_grip
= frame
.right_grip
= None
;
586 blackbox
->removeWindowSearch(frame
.handle
);
587 XDestroyWindow(blackbox
->getXDisplay(), frame
.handle
);
592 void BlackboxWindow::createTitlebar(void) {
593 frame
.title
= createChildWindow(frame
.window
);
594 frame
.label
= createChildWindow(frame
.title
);
595 blackbox
->saveWindowSearch(frame
.title
, this);
596 blackbox
->saveWindowSearch(frame
.label
, this);
598 if (decorations
& Decor_Iconify
) createIconifyButton();
599 if (decorations
& Decor_Maximize
) createMaximizeButton();
600 if (decorations
& Decor_Close
) createCloseButton();
604 void BlackboxWindow::destroyTitlebar(void) {
605 if (frame
.close_button
)
606 destroyCloseButton();
608 if (frame
.iconify_button
)
609 destroyIconifyButton();
611 if (frame
.maximize_button
)
612 destroyMaximizeButton();
615 screen
->getImageControl()->removeImage(frame
.ftitle
);
618 screen
->getImageControl()->removeImage(frame
.utitle
);
621 screen
->getImageControl()->removeImage(frame
.flabel
);
624 screen
->getImageControl()->removeImage(frame
.ulabel
);
627 screen
->getImageControl()->removeImage(frame
.fbutton
);
630 screen
->getImageControl()->removeImage(frame
.ubutton
);
633 screen
->getImageControl()->removeImage(frame
.pbutton
);
635 blackbox
->removeWindowSearch(frame
.title
);
636 blackbox
->removeWindowSearch(frame
.label
);
638 XDestroyWindow(blackbox
->getXDisplay(), frame
.label
);
639 XDestroyWindow(blackbox
->getXDisplay(), frame
.title
);
640 frame
.title
= frame
.label
= None
;
644 void BlackboxWindow::createCloseButton(void) {
645 if (frame
.title
!= None
) {
646 frame
.close_button
= createChildWindow(frame
.title
);
647 blackbox
->saveWindowSearch(frame
.close_button
, this);
652 void BlackboxWindow::destroyCloseButton(void) {
653 blackbox
->removeWindowSearch(frame
.close_button
);
654 XDestroyWindow(blackbox
->getXDisplay(), frame
.close_button
);
655 frame
.close_button
= None
;
659 void BlackboxWindow::createIconifyButton(void) {
660 if (frame
.title
!= None
) {
661 frame
.iconify_button
= createChildWindow(frame
.title
);
662 blackbox
->saveWindowSearch(frame
.iconify_button
, this);
667 void BlackboxWindow::destroyIconifyButton(void) {
668 blackbox
->removeWindowSearch(frame
.iconify_button
);
669 XDestroyWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
670 frame
.iconify_button
= None
;
674 void BlackboxWindow::createMaximizeButton(void) {
675 if (frame
.title
!= None
) {
676 frame
.maximize_button
= createChildWindow(frame
.title
);
677 blackbox
->saveWindowSearch(frame
.maximize_button
, this);
682 void BlackboxWindow::destroyMaximizeButton(void) {
683 blackbox
->removeWindowSearch(frame
.maximize_button
);
684 XDestroyWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
685 frame
.maximize_button
= None
;
689 void BlackboxWindow::positionButtons(bool redecorate_label
) {
690 string layout
= blackbox
->getTitlebarLayout();
693 bool hasclose
, hasiconify
, hasmaximize
, haslabel
;
694 hasclose
= hasiconify
= hasmaximize
= haslabel
= false;
696 string::const_iterator it
, end
;
697 for (it
= layout
.begin(), end
= layout
.end(); it
!= end
; ++it
) {
700 if (! hasclose
&& (decorations
& Decor_Close
)) {
706 if (! hasiconify
&& (decorations
& Decor_Iconify
)) {
712 if (! hasmaximize
&& (decorations
& Decor_Maximize
)) {
724 if (! hasclose
&& frame
.close_button
)
725 destroyCloseButton();
726 if (! hasiconify
&& frame
.iconify_button
)
727 destroyIconifyButton();
728 if (! hasmaximize
&& frame
.maximize_button
)
729 destroyMaximizeButton();
731 parsed
+= 'L'; // require that the label be in the layout
733 const unsigned int bsep
= frame
.bevel_w
+ 1; // separation between elements
734 const unsigned int by
= frame
.bevel_w
+ 1;
735 const unsigned int ty
= frame
.bevel_w
;
737 frame
.label_w
= frame
.inside_w
- bsep
* 2 -
738 (frame
.button_w
+ bsep
) * (parsed
.size() - 1);
740 unsigned int x
= bsep
;
741 for (it
= parsed
.begin(), end
= parsed
.end(); it
!= end
; ++it
) {
744 if (!frame
.close_button
) createCloseButton();
745 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.close_button
, x
, by
,
746 frame
.button_w
, frame
.button_w
);
747 x
+= frame
.button_w
+ bsep
;
750 if (!frame
.iconify_button
) createIconifyButton();
751 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.iconify_button
, x
, by
,
752 frame
.button_w
, frame
.button_w
);
753 x
+= frame
.button_w
+ bsep
;
756 if (!frame
.maximize_button
) createMaximizeButton();
757 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.maximize_button
, x
, by
,
758 frame
.button_w
, frame
.button_w
);
759 x
+= frame
.button_w
+ bsep
;
762 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.label
, x
, ty
,
763 frame
.label_w
, frame
.label_h
);
764 x
+= frame
.label_w
+ bsep
;
769 if (redecorate_label
) decorateLabel();
775 void BlackboxWindow::reconfigure(void) {
778 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
779 frame
.rect
.top() + frame
.margin
.top
);
784 XClearWindow(blackbox
->getXDisplay(), frame
.window
);
785 setFocusFlag(flags
.focused
);
787 configure(frame
.rect
.x(), frame
.rect
.y(),
788 frame
.rect
.width(), frame
.rect
.height());
791 windowmenu
->move(windowmenu
->getX(), frame
.rect
.y() + frame
.title_h
);
792 windowmenu
->reconfigure();
797 void BlackboxWindow::updateFocusModel(void) {
798 if ((! screen
->isSloppyFocus()) || screen
->doClickRaise()) {
799 // grab button 1 for changing focus/raising
800 blackbox
->grabButton(Button1
, 0, frame
.plate
, True
, ButtonPressMask
,
801 GrabModeSync
, GrabModeSync
, None
, None
);
803 blackbox
->ungrabButton(Button1
, 0, frame
.plate
);
808 void BlackboxWindow::positionWindows(void) {
809 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.window
,
810 frame
.rect
.x(), frame
.rect
.y(), frame
.inside_w
,
811 (flags
.shaded
) ? frame
.title_h
: frame
.inside_h
);
812 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.window
, frame
.border_w
);
813 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.plate
,
815 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.plate
,
816 frame
.margin
.left
- frame
.mwm_border_w
- frame
.border_w
,
817 frame
.margin
.top
- frame
.mwm_border_w
- frame
.border_w
,
818 client
.rect
.width(), client
.rect
.height());
819 XMoveResizeWindow(blackbox
->getXDisplay(), client
.window
,
820 0, 0, client
.rect
.width(), client
.rect
.height());
822 if (decorations
& Decor_Titlebar
) {
823 if (frame
.title
== None
) createTitlebar();
825 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.title
,
827 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.title
, -frame
.border_w
,
828 -frame
.border_w
, frame
.inside_w
, frame
.title_h
);
831 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
832 XMapWindow(blackbox
->getXDisplay(), frame
.title
);
833 } else if (frame
.title
) {
836 if (decorations
& Decor_Handle
) {
837 if (frame
.handle
== None
) createHandle();
838 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.handle
,
840 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.left_grip
,
842 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.right_grip
,
845 // use client.rect here so the value is correct even if shaded
846 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.handle
,
848 client
.rect
.height() + frame
.margin
.top
+
849 frame
.mwm_border_w
- frame
.border_w
,
850 frame
.inside_w
, frame
.handle_h
);
851 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.left_grip
,
852 -frame
.border_w
, -frame
.border_w
,
853 frame
.grip_w
, frame
.handle_h
);
854 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.right_grip
,
855 frame
.inside_w
- frame
.grip_w
- frame
.border_w
,
856 -frame
.border_w
, frame
.grip_w
, frame
.handle_h
);
858 XMapSubwindows(blackbox
->getXDisplay(), frame
.handle
);
859 XMapWindow(blackbox
->getXDisplay(), frame
.handle
);
860 } else if (frame
.handle
) {
866 void BlackboxWindow::getWMName(void) {
867 XTextProperty text_prop
;
869 if (XGetWMName(blackbox
->getXDisplay(), client
.window
, &text_prop
)) {
870 client
.title
= textPropertyToString(blackbox
->getXDisplay(), text_prop
);
871 if (client
.title
.empty())
872 client
.title
= i18n(WindowSet
, WindowUnnamed
, "Unnamed");
873 XFree((char *) text_prop
.value
);
875 client
.title
= i18n(WindowSet
, WindowUnnamed
, "Unnamed");
880 void BlackboxWindow::getWMIconName(void) {
881 XTextProperty text_prop
;
883 if (XGetWMIconName(blackbox
->getXDisplay(), client
.window
, &text_prop
)) {
885 textPropertyToString(blackbox
->getXDisplay(), text_prop
);
886 if (client
.icon_title
.empty())
887 client
.icon_title
= client
.title
;
888 XFree((char *) text_prop
.value
);
890 client
.icon_title
= client
.title
;
896 * Retrieve which WM Protocols are supported by the client window.
897 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
898 * window's decorations and allow the close behavior.
899 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
902 void BlackboxWindow::getWMProtocols(void) {
906 if (XGetWMProtocols(blackbox
->getXDisplay(), client
.window
,
907 &proto
, &num_return
)) {
908 for (int i
= 0; i
< num_return
; ++i
) {
909 if (proto
[i
] == blackbox
->getWMDeleteAtom()) {
910 decorations
|= Decor_Close
;
911 functions
|= Func_Close
;
912 } else if (proto
[i
] == blackbox
->getWMTakeFocusAtom())
913 flags
.send_focus_message
= True
;
914 else if (proto
[i
] == blackbox
->getBlackboxStructureMessagesAtom())
915 screen
->addNetizen(new Netizen(screen
, client
.window
));
924 * Gets the value of the WM_HINTS property.
925 * If the property is not set, then use a set of default values.
927 void BlackboxWindow::getWMHints(void) {
928 focus_mode
= F_Passive
;
929 client
.initial_state
= NormalState
;
931 // remove from current window group
932 if (client
.window_group
) {
933 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
934 if (group
) group
->removeWindow(this);
936 client
.window_group
= None
;
938 XWMHints
*wmhint
= XGetWMHints(blackbox
->getXDisplay(), client
.window
);
943 if (wmhint
->flags
& InputHint
) {
944 if (wmhint
->input
== True
) {
945 if (flags
.send_focus_message
)
946 focus_mode
= F_LocallyActive
;
948 if (flags
.send_focus_message
)
949 focus_mode
= F_GloballyActive
;
951 focus_mode
= F_NoInput
;
955 if (wmhint
->flags
& StateHint
)
956 client
.initial_state
= wmhint
->initial_state
;
958 if (wmhint
->flags
& WindowGroupHint
) {
959 client
.window_group
= wmhint
->window_group
;
961 // add window to the appropriate group
962 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
963 if (! group
) // no group found, create it!
964 group
= new BWindowGroup(blackbox
, client
.window_group
);
965 group
->addWindow(this);
968 client
.wm_hint_flags
= wmhint
->flags
;
974 * Gets the value of the WM_NORMAL_HINTS property.
975 * If the property is not set, then use a set of default values.
977 void BlackboxWindow::getWMNormalHints(void) {
981 client
.min_width
= client
.min_height
=
982 client
.width_inc
= client
.height_inc
= 1;
983 client
.base_width
= client
.base_height
= 0;
986 use the full screen, not the strut modified size. otherwise when the
987 availableArea changes max_width/height will be incorrect and lead to odd
990 const Rect
& screen_area
= screen
->getRect();
991 client
.max_width
= screen_area
.width();
993 client
.max_height
= screen_area
.height();
994 client
.min_aspect_x
= client
.min_aspect_y
=
995 client
.max_aspect_x
= client
.max_aspect_y
= 1;
996 client
.win_gravity
= NorthWestGravity
;
998 if (! XGetWMNormalHints(blackbox
->getXDisplay(), client
.window
,
999 &sizehint
, &icccm_mask
))
1002 client
.normal_hint_flags
= sizehint
.flags
;
1004 if (sizehint
.flags
& PMinSize
) {
1005 client
.min_width
= sizehint
.min_width
;
1006 client
.min_height
= sizehint
.min_height
;
1009 if (sizehint
.flags
& PMaxSize
) {
1010 client
.max_width
= sizehint
.max_width
;
1011 client
.max_height
= sizehint
.max_height
;
1014 if (sizehint
.flags
& PResizeInc
) {
1015 client
.width_inc
= sizehint
.width_inc
;
1016 client
.height_inc
= sizehint
.height_inc
;
1019 if (sizehint
.flags
& PAspect
) {
1020 client
.min_aspect_x
= sizehint
.min_aspect
.x
;
1021 client
.min_aspect_y
= sizehint
.min_aspect
.y
;
1022 client
.max_aspect_x
= sizehint
.max_aspect
.x
;
1023 client
.max_aspect_y
= sizehint
.max_aspect
.y
;
1026 if (sizehint
.flags
& PBaseSize
) {
1027 client
.base_width
= sizehint
.base_width
;
1028 client
.base_height
= sizehint
.base_height
;
1031 if (sizehint
.flags
& PWinGravity
)
1032 client
.win_gravity
= sizehint
.win_gravity
;
1037 * Gets the MWM hints for the class' contained window.
1038 * This is used while initializing the window to its first state, and not
1040 * Returns: true if the MWM hints are successfully retreived and applied;
1041 * false if they are not.
1043 void BlackboxWindow::getMWMHints(void) {
1046 unsigned long num
, len
;
1047 MwmHints
*mwm_hint
= 0;
1049 int ret
= XGetWindowProperty(blackbox
->getXDisplay(), client
.window
,
1050 blackbox
->getMotifWMHintsAtom(), 0,
1051 PropMwmHintsElements
, False
,
1052 blackbox
->getMotifWMHintsAtom(), &atom_return
,
1053 &format
, &num
, &len
,
1054 (unsigned char **) &mwm_hint
);
1056 if (ret
!= Success
|| ! mwm_hint
|| num
!= PropMwmHintsElements
)
1059 if (mwm_hint
->flags
& MwmHintsDecorations
) {
1060 if (mwm_hint
->decorations
& MwmDecorAll
) {
1061 decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
1062 Decor_Iconify
| Decor_Maximize
| Decor_Close
;
1066 if (mwm_hint
->decorations
& MwmDecorBorder
)
1067 decorations
|= Decor_Border
;
1068 if (mwm_hint
->decorations
& MwmDecorHandle
)
1069 decorations
|= Decor_Handle
;
1070 if (mwm_hint
->decorations
& MwmDecorTitle
)
1071 decorations
|= Decor_Titlebar
;
1072 if (mwm_hint
->decorations
& MwmDecorIconify
)
1073 decorations
|= Decor_Iconify
;
1074 if (mwm_hint
->decorations
& MwmDecorMaximize
)
1075 decorations
|= Decor_Maximize
;
1079 if (mwm_hint
->flags
& MwmHintsFunctions
) {
1080 if (mwm_hint
->functions
& MwmFuncAll
) {
1081 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
|
1086 if (mwm_hint
->functions
& MwmFuncResize
)
1087 functions
|= Func_Resize
;
1088 if (mwm_hint
->functions
& MwmFuncMove
)
1089 functions
|= Func_Move
;
1090 if (mwm_hint
->functions
& MwmFuncIconify
)
1091 functions
|= Func_Iconify
;
1092 if (mwm_hint
->functions
& MwmFuncMaximize
)
1093 functions
|= Func_Maximize
;
1094 if (mwm_hint
->functions
& MwmFuncClose
)
1095 functions
|= Func_Close
;
1103 * Gets the blackbox hints from the class' contained window.
1104 * This is used while initializing the window to its first state, and not
1106 * Returns: true if the hints are successfully retreived and applied; false if
1109 bool BlackboxWindow::getBlackboxHints(void) {
1112 unsigned long num
, len
;
1113 BlackboxHints
*blackbox_hint
= 0;
1115 int ret
= XGetWindowProperty(blackbox
->getXDisplay(), client
.window
,
1116 blackbox
->getBlackboxHintsAtom(), 0,
1117 PropBlackboxHintsElements
, False
,
1118 blackbox
->getBlackboxHintsAtom(), &atom_return
,
1119 &format
, &num
, &len
,
1120 (unsigned char **) &blackbox_hint
);
1121 if (ret
!= Success
|| ! blackbox_hint
|| num
!= PropBlackboxHintsElements
)
1124 if (blackbox_hint
->flags
& AttribShaded
)
1125 flags
.shaded
= (blackbox_hint
->attrib
& AttribShaded
);
1127 if ((blackbox_hint
->flags
& AttribMaxHoriz
) &&
1128 (blackbox_hint
->flags
& AttribMaxVert
))
1129 flags
.maximized
= (blackbox_hint
->attrib
&
1130 (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1131 else if (blackbox_hint
->flags
& AttribMaxVert
)
1132 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxVert
) ? 2 : 0;
1133 else if (blackbox_hint
->flags
& AttribMaxHoriz
)
1134 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1136 if (blackbox_hint
->flags
& AttribOmnipresent
)
1137 flags
.stuck
= (blackbox_hint
->attrib
& AttribOmnipresent
);
1139 if (blackbox_hint
->flags
& AttribWorkspace
)
1140 blackbox_attrib
.workspace
= blackbox_hint
->workspace
;
1142 // if (blackbox_hint->flags & AttribStack)
1143 // don't yet have always on top/bottom for blackbox yet... working
1146 if (blackbox_hint
->flags
& AttribDecoration
) {
1147 switch (blackbox_hint
->decoration
) {
1149 // clear all decorations except close
1150 decorations
&= Decor_Close
;
1151 // clear all functions except close
1152 functions
&= Func_Close
;
1157 decorations
|= Decor_Titlebar
| Decor_Iconify
;
1158 decorations
&= ~(Decor_Border
| Decor_Handle
| Decor_Maximize
);
1159 functions
|= Func_Move
| Func_Iconify
;
1160 functions
&= ~(Func_Resize
| Func_Maximize
);
1165 decorations
|= Decor_Titlebar
;
1166 decorations
&= ~(Decor_Iconify
| Decor_Border
| Decor_Handle
);
1167 functions
|= Func_Move
;
1168 functions
&= ~(Func_Resize
| Func_Maximize
| Func_Iconify
);
1174 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Handle
|
1175 Decor_Iconify
| Decor_Maximize
;
1176 functions
|= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
1183 XFree(blackbox_hint
);
1188 void BlackboxWindow::getTransientInfo(void) {
1189 if (client
.transient_for
&&
1190 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1191 // the transient for hint was removed, so we need to tell our
1192 // previous transient_for that we are going away
1193 client
.transient_for
->client
.transientList
.remove(this);
1196 // we have no transient_for until we find a new one
1197 client
.transient_for
= 0;
1200 if (! XGetTransientForHint(blackbox
->getXDisplay(), client
.window
,
1202 // transient_for hint not set
1206 if (trans_for
== client
.window
) {
1207 // wierd client... treat this window as a normal window
1211 if (trans_for
== None
|| trans_for
== screen
->getRootWindow()) {
1212 // this is an undocumented interpretation of the ICCCM. a transient
1213 // associated with None/Root/itself is assumed to be a modal root
1214 // transient. we don't support the concept of a global transient,
1215 // so we just associate this transient with nothing, and perhaps
1216 // we will add support later for global modality.
1217 client
.transient_for
= (BlackboxWindow
*) ~0ul;
1222 client
.transient_for
= blackbox
->searchWindow(trans_for
);
1223 if (! client
.transient_for
&&
1224 client
.window_group
&& trans_for
== client
.window_group
) {
1225 // no direct transient_for, perhaps this is a group transient?
1226 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1227 if (group
) client
.transient_for
= group
->find(screen
);
1230 if (! client
.transient_for
|| client
.transient_for
== this) {
1231 // no transient_for found, or we have a wierd client that wants to be
1232 // a transient for itself, so we treat this window as a normal window
1233 client
.transient_for
= (BlackboxWindow
*) 0;
1237 // register ourselves with our new transient_for
1238 client
.transient_for
->client
.transientList
.push_back(this);
1239 flags
.stuck
= client
.transient_for
->flags
.stuck
;
1243 BlackboxWindow
*BlackboxWindow::getTransientFor(void) const {
1244 if (client
.transient_for
&&
1245 client
.transient_for
!= (BlackboxWindow
*) ~0ul)
1246 return client
.transient_for
;
1251 void BlackboxWindow::configure(int dx
, int dy
,
1252 unsigned int dw
, unsigned int dh
) {
1253 bool send_event
= (frame
.rect
.x() != dx
|| frame
.rect
.y() != dy
);
1255 if ((dw
!= frame
.rect
.width()) || (dh
!= frame
.rect
.height())) {
1256 frame
.rect
.setRect(dx
, dy
, dw
, dh
);
1257 frame
.inside_w
= frame
.rect
.width() - (frame
.border_w
* 2);
1258 frame
.inside_h
= frame
.rect
.height() - (frame
.border_w
* 2);
1260 if (frame
.rect
.right() <= 0 || frame
.rect
.bottom() <= 0)
1261 frame
.rect
.setPos(0, 0);
1263 client
.rect
.setCoords(frame
.rect
.left() + frame
.margin
.left
,
1264 frame
.rect
.top() + frame
.margin
.top
,
1265 frame
.rect
.right() - frame
.margin
.right
,
1266 frame
.rect
.bottom() - frame
.margin
.bottom
);
1269 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
1276 setFocusFlag(flags
.focused
);
1279 frame
.rect
.setPos(dx
, dy
);
1281 XMoveWindow(blackbox
->getXDisplay(), frame
.window
,
1282 frame
.rect
.x(), frame
.rect
.y());
1284 if (! flags
.moving
) send_event
= True
;
1287 if (send_event
&& ! flags
.moving
) {
1288 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1289 frame
.rect
.top() + frame
.margin
.top
);
1292 event
.type
= ConfigureNotify
;
1294 event
.xconfigure
.display
= blackbox
->getXDisplay();
1295 event
.xconfigure
.event
= client
.window
;
1296 event
.xconfigure
.window
= client
.window
;
1297 event
.xconfigure
.x
= client
.rect
.x();
1298 event
.xconfigure
.y
= client
.rect
.y();
1299 event
.xconfigure
.width
= client
.rect
.width();
1300 event
.xconfigure
.height
= client
.rect
.height();
1301 event
.xconfigure
.border_width
= client
.old_bw
;
1302 event
.xconfigure
.above
= frame
.window
;
1303 event
.xconfigure
.override_redirect
= False
;
1305 XSendEvent(blackbox
->getXDisplay(), client
.window
, True
,
1306 NoEventMask
, &event
);
1308 screen
->updateNetizenConfigNotify(&event
);
1314 void BlackboxWindow::configureShape(void) {
1315 XShapeCombineShape(blackbox
->getXDisplay(), frame
.window
, ShapeBounding
,
1316 frame
.margin
.left
- frame
.border_w
,
1317 frame
.margin
.top
- frame
.border_w
,
1318 client
.window
, ShapeBounding
, ShapeSet
);
1321 XRectangle xrect
[2];
1323 if (decorations
& Decor_Titlebar
) {
1324 xrect
[0].x
= xrect
[0].y
= -frame
.border_w
;
1325 xrect
[0].width
= frame
.rect
.width();
1326 xrect
[0].height
= frame
.title_h
+ (frame
.border_w
* 2);
1330 if (decorations
& Decor_Handle
) {
1331 xrect
[1].x
= -frame
.border_w
;
1332 xrect
[1].y
= frame
.rect
.height() - frame
.margin
.bottom
+
1333 frame
.mwm_border_w
- frame
.border_w
;
1334 xrect
[1].width
= frame
.rect
.width();
1335 xrect
[1].height
= frame
.handle_h
+ (frame
.border_w
* 2);
1339 XShapeCombineRectangles(blackbox
->getXDisplay(), frame
.window
,
1340 ShapeBounding
, 0, 0, xrect
, num
,
1341 ShapeUnion
, Unsorted
);
1346 bool BlackboxWindow::setInputFocus(void) {
1347 if (flags
.focused
) return True
;
1349 assert(! flags
.iconic
);
1351 // if the window is not visible, mark the window as wanting focus rather
1352 // than give it focus.
1353 if (! flags
.visible
) {
1354 Workspace
*wkspc
= screen
->getWorkspace(blackbox_attrib
.workspace
);
1355 wkspc
->setLastFocusedWindow(this);
1359 if (! client
.rect
.intersects(screen
->getRect())) {
1360 // client is outside the screen, move it to the center
1361 configure((screen
->getWidth() - frame
.rect
.width()) / 2,
1362 (screen
->getHeight() - frame
.rect
.height()) / 2,
1363 frame
.rect
.width(), frame
.rect
.height());
1366 if (client
.transientList
.size() > 0) {
1367 // transfer focus to any modal transients
1368 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1369 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1370 if ((*it
)->flags
.modal
) return (*it
)->setInputFocus();
1375 if (focus_mode
== F_LocallyActive
|| focus_mode
== F_Passive
) {
1376 XSetInputFocus(blackbox
->getXDisplay(), client
.window
,
1377 RevertToPointerRoot
, CurrentTime
);
1379 blackbox
->setFocusedWindow(this);
1381 /* we could set the focus to none, since the window doesn't accept focus,
1382 * but we shouldn't set focus to nothing since this would surely make
1388 if (flags
.send_focus_message
) {
1390 ce
.xclient
.type
= ClientMessage
;
1391 ce
.xclient
.message_type
= blackbox
->getWMProtocolsAtom();
1392 ce
.xclient
.display
= blackbox
->getXDisplay();
1393 ce
.xclient
.window
= client
.window
;
1394 ce
.xclient
.format
= 32;
1395 ce
.xclient
.data
.l
[0] = blackbox
->getWMTakeFocusAtom();
1396 ce
.xclient
.data
.l
[1] = blackbox
->getLastTime();
1397 ce
.xclient
.data
.l
[2] = 0l;
1398 ce
.xclient
.data
.l
[3] = 0l;
1399 ce
.xclient
.data
.l
[4] = 0l;
1400 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1408 void BlackboxWindow::iconify(void) {
1409 if (flags
.iconic
) return;
1411 if (windowmenu
) windowmenu
->hide();
1413 setState(IconicState
);
1416 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1417 * we need to clear the event mask on client.window for a split second.
1418 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1419 * split second, leaving us with a ghost window... so, we need to do this
1420 * while the X server is grabbed
1422 XGrabServer(blackbox
->getXDisplay());
1423 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
1424 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1425 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1426 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
1427 XUngrabServer(blackbox
->getXDisplay());
1429 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1430 flags
.visible
= False
;
1431 flags
.iconic
= True
;
1433 screen
->getWorkspace(blackbox_attrib
.workspace
)->removeWindow(this);
1435 if (isTransient()) {
1436 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1437 ! client
.transient_for
->flags
.iconic
) {
1438 // iconify our transient_for
1439 client
.transient_for
->iconify();
1443 screen
->addIcon(this);
1445 if (client
.transientList
.size() > 0) {
1446 // iconify all transients
1447 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1448 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1449 if (! (*it
)->flags
.iconic
) (*it
)->iconify();
1455 void BlackboxWindow::show(void) {
1456 current_state
= (flags
.shaded
) ? IconicState
: NormalState
;
1457 setState(current_state
);
1459 XMapWindow(blackbox
->getXDisplay(), client
.window
);
1460 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
1461 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
1463 flags
.visible
= True
;
1464 flags
.iconic
= False
;
1468 void BlackboxWindow::deiconify(bool reassoc
, bool raise
) {
1469 if (flags
.iconic
|| reassoc
)
1470 screen
->reassociateWindow(this, BSENTINEL
, False
);
1471 else if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspace()->getID())
1476 // reassociate and deiconify all transients
1477 if (reassoc
&& client
.transientList
.size() > 0) {
1478 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1479 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1480 (*it
)->deiconify(True
, False
);
1485 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1489 void BlackboxWindow::close(void) {
1491 ce
.xclient
.type
= ClientMessage
;
1492 ce
.xclient
.message_type
= blackbox
->getWMProtocolsAtom();
1493 ce
.xclient
.display
= blackbox
->getXDisplay();
1494 ce
.xclient
.window
= client
.window
;
1495 ce
.xclient
.format
= 32;
1496 ce
.xclient
.data
.l
[0] = blackbox
->getWMDeleteAtom();
1497 ce
.xclient
.data
.l
[1] = CurrentTime
;
1498 ce
.xclient
.data
.l
[2] = 0l;
1499 ce
.xclient
.data
.l
[3] = 0l;
1500 ce
.xclient
.data
.l
[4] = 0l;
1501 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
, NoEventMask
, &ce
);
1505 void BlackboxWindow::withdraw(void) {
1506 setState(current_state
);
1508 flags
.visible
= False
;
1509 flags
.iconic
= False
;
1511 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1513 XGrabServer(blackbox
->getXDisplay());
1515 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
1516 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1517 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1518 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
1520 XUngrabServer(blackbox
->getXDisplay());
1522 if (windowmenu
) windowmenu
->hide();
1526 void BlackboxWindow::maximize(unsigned int button
) {
1527 // handle case where menu is open then the max button is used instead
1528 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
1530 if (flags
.maximized
) {
1531 flags
.maximized
= 0;
1533 blackbox_attrib
.flags
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1534 blackbox_attrib
.attrib
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1537 when a resize is begun, maximize(0) is called to clear any maximization
1538 flags currently set. Otherwise it still thinks it is maximized.
1539 so we do not need to call configure() because resizing will handle it
1541 if (! flags
.resizing
)
1542 configure(blackbox_attrib
.premax_x
, blackbox_attrib
.premax_y
,
1543 blackbox_attrib
.premax_w
, blackbox_attrib
.premax_h
);
1545 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
1546 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
1549 setState(current_state
);
1553 blackbox_attrib
.premax_x
= frame
.rect
.x();
1554 blackbox_attrib
.premax_y
= frame
.rect
.y();
1555 blackbox_attrib
.premax_w
= frame
.rect
.width();
1556 // use client.rect so that clients can be restored even if shaded
1557 blackbox_attrib
.premax_h
=
1558 client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
;
1560 const Rect
&screen_area
= screen
->availableArea();
1561 frame
.changing
= screen_area
;
1566 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1567 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1571 blackbox_attrib
.flags
|= AttribMaxVert
;
1572 blackbox_attrib
.attrib
|= AttribMaxVert
;
1574 frame
.changing
.setX(frame
.rect
.x());
1575 frame
.changing
.setWidth(frame
.rect
.width());
1579 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1580 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1582 frame
.changing
.setY(frame
.rect
.y());
1583 frame
.changing
.setHeight(frame
.rect
.height());
1588 blackbox_attrib
.flags
^= AttribShaded
;
1589 blackbox_attrib
.attrib
^= AttribShaded
;
1590 flags
.shaded
= False
;
1593 flags
.maximized
= button
;
1595 configure(frame
.changing
.x(), frame
.changing
.y(),
1596 frame
.changing
.width(), frame
.changing
.height());
1598 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1600 setState(current_state
);
1604 // re-maximizes the window to take into account availableArea changes
1605 void BlackboxWindow::remaximize(void) {
1606 // save the original dimensions because maximize will wipe them out
1607 int premax_x
= blackbox_attrib
.premax_x
,
1608 premax_y
= blackbox_attrib
.premax_y
,
1609 premax_w
= blackbox_attrib
.premax_w
,
1610 premax_h
= blackbox_attrib
.premax_h
;
1612 unsigned int button
= flags
.maximized
;
1613 flags
.maximized
= 0; // trick maximize() into working
1616 // restore saved values
1617 blackbox_attrib
.premax_x
= premax_x
;
1618 blackbox_attrib
.premax_y
= premax_y
;
1619 blackbox_attrib
.premax_w
= premax_w
;
1620 blackbox_attrib
.premax_h
= premax_h
;
1624 void BlackboxWindow::setWorkspace(unsigned int n
) {
1625 blackbox_attrib
.flags
|= AttribWorkspace
;
1626 blackbox_attrib
.workspace
= n
;
1630 void BlackboxWindow::shade(void) {
1632 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1633 frame
.inside_w
, frame
.inside_h
);
1634 flags
.shaded
= False
;
1635 blackbox_attrib
.flags
^= AttribShaded
;
1636 blackbox_attrib
.attrib
^= AttribShaded
;
1638 setState(NormalState
);
1640 // set the frame rect to the normal size
1641 frame
.rect
.setHeight(client
.rect
.height() + frame
.margin
.top
+
1642 frame
.margin
.bottom
);
1644 if (! (decorations
& Decor_Titlebar
))
1647 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1648 frame
.inside_w
, frame
.title_h
);
1649 flags
.shaded
= True
;
1650 blackbox_attrib
.flags
|= AttribShaded
;
1651 blackbox_attrib
.attrib
|= AttribShaded
;
1653 setState(IconicState
);
1655 // set the frame rect to the shaded size
1656 frame
.rect
.setHeight(frame
.title_h
+ (frame
.border_w
* 2));
1661 void BlackboxWindow::stick(void) {
1663 blackbox_attrib
.flags
^= AttribOmnipresent
;
1664 blackbox_attrib
.attrib
^= AttribOmnipresent
;
1666 flags
.stuck
= False
;
1669 screen
->reassociateWindow(this, BSENTINEL
, True
);
1671 setState(current_state
);
1675 blackbox_attrib
.flags
|= AttribOmnipresent
;
1676 blackbox_attrib
.attrib
|= AttribOmnipresent
;
1678 setState(current_state
);
1683 void BlackboxWindow::setFocusFlag(bool focus
) {
1684 // only focus a window if it is visible
1685 if (focus
&& !flags
.visible
)
1688 flags
.focused
= focus
;
1690 if (decorations
& Decor_Titlebar
) {
1691 if (flags
.focused
) {
1693 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1694 frame
.title
, frame
.ftitle
);
1696 XSetWindowBackground(blackbox
->getXDisplay(),
1697 frame
.title
, frame
.ftitle_pixel
);
1700 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1701 frame
.title
, frame
.utitle
);
1703 XSetWindowBackground(blackbox
->getXDisplay(),
1704 frame
.title
, frame
.utitle_pixel
);
1706 XClearWindow(blackbox
->getXDisplay(), frame
.title
);
1712 if (decorations
& Decor_Handle
) {
1713 if (flags
.focused
) {
1715 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1716 frame
.handle
, frame
.fhandle
);
1718 XSetWindowBackground(blackbox
->getXDisplay(),
1719 frame
.handle
, frame
.fhandle_pixel
);
1722 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1723 frame
.left_grip
, frame
.fgrip
);
1724 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1725 frame
.right_grip
, frame
.fgrip
);
1727 XSetWindowBackground(blackbox
->getXDisplay(),
1728 frame
.left_grip
, frame
.fgrip_pixel
);
1729 XSetWindowBackground(blackbox
->getXDisplay(),
1730 frame
.right_grip
, frame
.fgrip_pixel
);
1734 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1735 frame
.handle
, frame
.uhandle
);
1737 XSetWindowBackground(blackbox
->getXDisplay(),
1738 frame
.handle
, frame
.uhandle_pixel
);
1741 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1742 frame
.left_grip
, frame
.ugrip
);
1743 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1744 frame
.right_grip
, frame
.ugrip
);
1746 XSetWindowBackground(blackbox
->getXDisplay(),
1747 frame
.left_grip
, frame
.ugrip_pixel
);
1748 XSetWindowBackground(blackbox
->getXDisplay(),
1749 frame
.right_grip
, frame
.ugrip_pixel
);
1752 XClearWindow(blackbox
->getXDisplay(), frame
.handle
);
1753 XClearWindow(blackbox
->getXDisplay(), frame
.left_grip
);
1754 XClearWindow(blackbox
->getXDisplay(), frame
.right_grip
);
1757 if (decorations
& Decor_Border
) {
1759 XSetWindowBorder(blackbox
->getXDisplay(),
1760 frame
.plate
, frame
.fborder_pixel
);
1762 XSetWindowBorder(blackbox
->getXDisplay(),
1763 frame
.plate
, frame
.uborder_pixel
);
1766 if (screen
->isSloppyFocus() && screen
->doAutoRaise()) {
1767 if (isFocused()) timer
->start();
1772 blackbox
->setFocusedWindow(this);
1776 void BlackboxWindow::installColormap(bool install
) {
1777 int i
= 0, ncmap
= 0;
1778 Colormap
*cmaps
= XListInstalledColormaps(blackbox
->getXDisplay(),
1779 client
.window
, &ncmap
);
1780 XWindowAttributes wattrib
;
1782 if (XGetWindowAttributes(blackbox
->getXDisplay(),
1783 client
.window
, &wattrib
)) {
1785 // install the window's colormap
1786 for (i
= 0; i
< ncmap
; i
++) {
1787 if (*(cmaps
+ i
) == wattrib
.colormap
)
1788 // this window is using an installed color map... do not install
1791 // otherwise, install the window's colormap
1793 XInstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
1795 // uninstall the window's colormap
1796 for (i
= 0; i
< ncmap
; i
++) {
1797 if (*(cmaps
+ i
) == wattrib
.colormap
)
1798 // we found the colormap to uninstall
1799 XUninstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
1809 void BlackboxWindow::setState(unsigned long new_state
) {
1810 current_state
= new_state
;
1812 unsigned long state
[2];
1813 state
[0] = current_state
;
1815 xatom
->setValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
, state
, 2);
1817 xatom
->setValue(client
.window
, XAtom::blackbox_attributes
,
1818 XAtom::blackbox_attributes
, (unsigned long *)&blackbox_attrib
,
1819 PropBlackboxAttributesElements
);
1823 bool BlackboxWindow::getState(void) {
1828 unsigned long *state
, nitems
;
1830 if (! xatom
->getValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
, nitems
,
1834 current_state
= static_cast<unsigned long>(state
[0]);
1841 void BlackboxWindow::restoreAttributes(void) {
1844 unsigned long ulfoo
, nitems
;
1846 BlackboxAttributes
*net
;
1847 int ret
= XGetWindowProperty(blackbox
->getXDisplay(), client
.window
,
1848 blackbox
->getBlackboxAttributesAtom(), 0l,
1849 PropBlackboxAttributesElements
, False
,
1850 blackbox
->getBlackboxAttributesAtom(),
1851 &atom_return
, &foo
, &nitems
, &ulfoo
,
1852 (unsigned char **) &net
);
1853 if (ret
!= Success
|| ! net
|| nitems
!= PropBlackboxAttributesElements
)
1856 if (net
->flags
& AttribShaded
&& net
->attrib
& AttribShaded
) {
1857 flags
.shaded
= False
;
1861 Because the iconic'ness of shaded windows is lost, we need to set the
1862 state to NormalState so that shaded windows on other workspaces will not
1863 get shown on the first workspace.
1864 At this point in the life of a window, current_state should only be set
1865 to IconicState if the window was an *icon*, not if it was shaded.
1867 current_state
= NormalState
;
1870 if ((net
->workspace
!= screen
->getCurrentWorkspaceID()) &&
1871 (net
->workspace
< screen
->getWorkspaceCount())) {
1872 screen
->reassociateWindow(this, net
->workspace
, True
);
1874 // set to WithdrawnState so it will be mapped on the new workspace
1875 if (current_state
== NormalState
) current_state
= WithdrawnState
;
1876 } else if (current_state
== WithdrawnState
) {
1877 // the window is on this workspace and is Withdrawn, so it is waiting to
1879 current_state
= NormalState
;
1882 if (net
->flags
& AttribOmnipresent
&& net
->attrib
& AttribOmnipresent
) {
1883 flags
.stuck
= False
;
1886 // if the window was on another workspace, it was going to be hidden. this
1887 // specifies that the window should be mapped since it is sticky.
1888 if (current_state
== WithdrawnState
) current_state
= NormalState
;
1891 if (net
->flags
& AttribMaxHoriz
|| net
->flags
& AttribMaxVert
) {
1892 int x
= net
->premax_x
, y
= net
->premax_y
;
1893 unsigned int w
= net
->premax_w
, h
= net
->premax_h
;
1894 flags
.maximized
= 0;
1897 if ((net
->flags
& AttribMaxHoriz
) &&
1898 (net
->flags
& AttribMaxVert
))
1899 m
= (net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1900 else if (net
->flags
& AttribMaxVert
)
1901 m
= (net
->attrib
& AttribMaxVert
) ? 2 : 0;
1902 else if (net
->flags
& AttribMaxHoriz
)
1903 m
= (net
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1907 blackbox_attrib
.premax_x
= x
;
1908 blackbox_attrib
.premax_y
= y
;
1909 blackbox_attrib
.premax_w
= w
;
1910 blackbox_attrib
.premax_h
= h
;
1913 // with the state set it will then be the map events job to read the window's
1914 // state and behave accordingly
1916 XFree((void *) net
);
1921 * Positions the frame according the the client window position and window
1924 void BlackboxWindow::setGravityOffsets(void) {
1925 // x coordinates for each gravity type
1926 const int x_west
= client
.rect
.x();
1927 const int x_east
= client
.rect
.right() - frame
.inside_w
+ 1;
1928 const int x_center
= client
.rect
.left() +
1929 ((client
.rect
.width() - frame
.rect
.width()) / 2);
1930 // y coordinates for each gravity type
1931 const int y_north
= client
.rect
.y();
1932 const int y_south
= client
.rect
.bottom() - frame
.inside_h
+ 1;
1933 const int y_center
= client
.rect
.top() +
1934 ((client
.rect
.height() - frame
.rect
.height()) / 2);
1936 switch (client
.win_gravity
) {
1938 case NorthWestGravity
: frame
.rect
.setPos(x_west
, y_north
); break;
1939 case NorthGravity
: frame
.rect
.setPos(x_center
, y_north
); break;
1940 case NorthEastGravity
: frame
.rect
.setPos(x_east
, y_north
); break;
1941 case SouthWestGravity
: frame
.rect
.setPos(x_west
, y_south
); break;
1942 case SouthGravity
: frame
.rect
.setPos(x_center
, y_south
); break;
1943 case SouthEastGravity
: frame
.rect
.setPos(x_east
, y_south
); break;
1944 case WestGravity
: frame
.rect
.setPos(x_west
, y_center
); break;
1945 case CenterGravity
: frame
.rect
.setPos(x_center
, y_center
); break;
1946 case EastGravity
: frame
.rect
.setPos(x_east
, y_center
); break;
1950 frame
.rect
.setPos(client
.rect
.x() - frame
.margin
.left
,
1951 client
.rect
.y() - frame
.margin
.top
);
1958 * The reverse of the setGravityOffsets function. Uses the frame window's
1959 * position to find the window's reference point.
1961 void BlackboxWindow::restoreGravity(void) {
1962 // x coordinates for each gravity type
1963 const int x_west
= frame
.rect
.x();
1964 const int x_east
= frame
.rect
.x() + frame
.inside_w
- client
.rect
.width();
1965 const int x_center
= frame
.rect
.x() -
1966 ((client
.rect
.width() - frame
.rect
.width()) / 2);
1967 // y coordinates for each gravity type
1968 const int y_north
= frame
.rect
.y();
1969 const int y_south
= frame
.rect
.y() + frame
.inside_h
- client
.rect
.height();
1970 const int y_center
= frame
.rect
.y() -
1971 ((client
.rect
.height() - frame
.rect
.height()) / 2);
1973 switch(client
.win_gravity
) {
1975 case NorthWestGravity
: client
.rect
.setPos(x_west
, y_north
); break;
1976 case NorthGravity
: client
.rect
.setPos(x_center
, y_north
); break;
1977 case NorthEastGravity
: client
.rect
.setPos(x_east
, y_north
); break;
1978 case SouthWestGravity
: client
.rect
.setPos(x_west
, y_south
); break;
1979 case SouthGravity
: client
.rect
.setPos(x_center
, y_south
); break;
1980 case SouthEastGravity
: client
.rect
.setPos(x_east
, y_south
); break;
1981 case WestGravity
: client
.rect
.setPos(x_west
, y_center
); break;
1982 case CenterGravity
: client
.rect
.setPos(x_center
, y_center
); break;
1983 case EastGravity
: client
.rect
.setPos(x_east
, y_center
); break;
1987 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1988 frame
.rect
.top() + frame
.margin
.top
);
1994 void BlackboxWindow::redrawLabel(void) {
1995 if (flags
.focused
) {
1997 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1998 frame
.label
, frame
.flabel
);
2000 XSetWindowBackground(blackbox
->getXDisplay(),
2001 frame
.label
, frame
.flabel_pixel
);
2004 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2005 frame
.label
, frame
.ulabel
);
2007 XSetWindowBackground(blackbox
->getXDisplay(),
2008 frame
.label
, frame
.ulabel_pixel
);
2010 XClearWindow(blackbox
->getXDisplay(), frame
.label
);
2012 WindowStyle
*style
= screen
->getWindowStyle();
2014 int pos
= frame
.bevel_w
* 2,
2015 dlen
= style
->doJustify(client
.title
.c_str(), pos
, frame
.label_w
,
2016 frame
.bevel_w
* 4, i18n
.multibyte());
2018 BPen
pen((flags
.focused
) ? style
->l_text_focus
: style
->l_text_unfocus
,
2020 if (i18n
.multibyte())
2021 XmbDrawString(blackbox
->getXDisplay(), frame
.label
, style
->fontset
,
2023 (1 - style
->fontset_extents
->max_ink_extent
.y
),
2024 client
.title
.c_str(), dlen
);
2026 XDrawString(blackbox
->getXDisplay(), frame
.label
, pen
.gc(), pos
,
2027 (style
->font
->ascent
+ 1), client
.title
.c_str(), dlen
);
2031 void BlackboxWindow::redrawAllButtons(void) {
2032 if (frame
.iconify_button
) redrawIconifyButton(False
);
2033 if (frame
.maximize_button
) redrawMaximizeButton(flags
.maximized
);
2034 if (frame
.close_button
) redrawCloseButton(False
);
2038 void BlackboxWindow::redrawIconifyButton(bool pressed
) {
2040 if (flags
.focused
) {
2042 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2043 frame
.iconify_button
, frame
.fbutton
);
2045 XSetWindowBackground(blackbox
->getXDisplay(),
2046 frame
.iconify_button
, frame
.fbutton_pixel
);
2049 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2050 frame
.iconify_button
, frame
.ubutton
);
2052 XSetWindowBackground(blackbox
->getXDisplay(), frame
.iconify_button
,
2053 frame
.ubutton_pixel
);
2057 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2058 frame
.iconify_button
, frame
.pbutton
);
2060 XSetWindowBackground(blackbox
->getXDisplay(),
2061 frame
.iconify_button
, frame
.pbutton_pixel
);
2063 XClearWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
2065 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2066 screen
->getWindowStyle()->b_pic_unfocus
);
2067 XDrawRectangle(blackbox
->getXDisplay(), frame
.iconify_button
, pen
.gc(),
2068 2, (frame
.button_w
- 5), (frame
.button_w
- 5), 2);
2072 void BlackboxWindow::redrawMaximizeButton(bool pressed
) {
2074 if (flags
.focused
) {
2076 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2077 frame
.maximize_button
, frame
.fbutton
);
2079 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2080 frame
.fbutton_pixel
);
2083 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2084 frame
.maximize_button
, frame
.ubutton
);
2086 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2087 frame
.ubutton_pixel
);
2091 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2092 frame
.maximize_button
, frame
.pbutton
);
2094 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2095 frame
.pbutton_pixel
);
2097 XClearWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
2099 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2100 screen
->getWindowStyle()->b_pic_unfocus
);
2101 XDrawRectangle(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2102 2, 2, (frame
.button_w
- 5), (frame
.button_w
- 5));
2103 XDrawLine(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2104 2, 3, (frame
.button_w
- 3), 3);
2108 void BlackboxWindow::redrawCloseButton(bool pressed
) {
2110 if (flags
.focused
) {
2112 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2115 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2116 frame
.fbutton_pixel
);
2119 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2122 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2123 frame
.ubutton_pixel
);
2127 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2128 frame
.close_button
, frame
.pbutton
);
2130 XSetWindowBackground(blackbox
->getXDisplay(),
2131 frame
.close_button
, frame
.pbutton_pixel
);
2133 XClearWindow(blackbox
->getXDisplay(), frame
.close_button
);
2135 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2136 screen
->getWindowStyle()->b_pic_unfocus
);
2137 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2138 2, 2, (frame
.button_w
- 3), (frame
.button_w
- 3));
2139 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2140 2, (frame
.button_w
- 3), (frame
.button_w
- 3), 2);
2144 void BlackboxWindow::mapRequestEvent(XMapRequestEvent
*re
) {
2145 if (re
->window
!= client
.window
)
2149 fprintf(stderr
, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2153 switch (current_state
) {
2158 case WithdrawnState
:
2167 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2168 if (! blackbox
->isStartup() && (isTransient() || screen
->doFocusNew())) {
2169 XSync(blackbox
->getXDisplay(), False
); // make sure the frame is mapped..
2177 void BlackboxWindow::unmapNotifyEvent(XUnmapEvent
*ue
) {
2178 if (ue
->window
!= client
.window
)
2182 fprintf(stderr
, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2186 screen
->unmanageWindow(this, False
);
2190 void BlackboxWindow::destroyNotifyEvent(XDestroyWindowEvent
*de
) {
2191 if (de
->window
!= client
.window
)
2195 fprintf(stderr
, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2199 screen
->unmanageWindow(this, False
);
2203 void BlackboxWindow::reparentNotifyEvent(XReparentEvent
*re
) {
2204 if (re
->window
!= client
.window
|| re
->parent
== frame
.plate
)
2208 fprintf(stderr
, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2209 "0x%lx.\n", client
.window
, re
->parent
);
2214 XPutBackEvent(blackbox
->getXDisplay(), &ev
);
2215 screen
->unmanageWindow(this, True
);
2219 void BlackboxWindow::propertyNotifyEvent(Atom atom
) {
2222 case XA_WM_CLIENT_MACHINE
:
2226 case XA_WM_TRANSIENT_FOR
: {
2227 // determine if this is a transient window
2230 // adjust the window decorations based on transience
2231 if (isTransient()) {
2232 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2233 functions
&= ~Func_Maximize
;
2244 case XA_WM_ICON_NAME
:
2246 if (flags
.iconic
) screen
->propagateWindowName(this);
2252 if (decorations
& Decor_Titlebar
)
2255 screen
->propagateWindowName(this);
2258 case XA_WM_NORMAL_HINTS
: {
2261 if ((client
.normal_hint_flags
& PMinSize
) &&
2262 (client
.normal_hint_flags
& PMaxSize
)) {
2263 if (client
.max_width
<= client
.min_width
&&
2264 client
.max_height
<= client
.min_height
) {
2265 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2266 functions
&= ~(Func_Resize
| Func_Maximize
);
2268 decorations
|= Decor_Maximize
| Decor_Handle
;
2269 functions
|= Func_Resize
| Func_Maximize
;
2273 Rect old_rect
= frame
.rect
;
2277 if (old_rect
!= frame
.rect
)
2284 if (atom
== blackbox
->getWMProtocolsAtom()) {
2287 if ((decorations
& Decor_Close
) && (! frame
.close_button
)) {
2288 createCloseButton();
2289 if (decorations
& Decor_Titlebar
) {
2290 positionButtons(True
);
2291 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
2293 if (windowmenu
) windowmenu
->reconfigure();
2302 void BlackboxWindow::exposeEvent(XExposeEvent
*ee
) {
2303 if (frame
.label
== ee
->window
&& (decorations
& Decor_Titlebar
))
2305 else if (frame
.close_button
== ee
->window
)
2306 redrawCloseButton(False
);
2307 else if (frame
.maximize_button
== ee
->window
)
2308 redrawMaximizeButton(flags
.maximized
);
2309 else if (frame
.iconify_button
== ee
->window
)
2310 redrawIconifyButton(False
);
2314 void BlackboxWindow::configureRequestEvent(XConfigureRequestEvent
*cr
) {
2315 if (cr
->window
!= client
.window
|| flags
.iconic
)
2318 int cx
= frame
.rect
.x(), cy
= frame
.rect
.y();
2319 unsigned int cw
= frame
.rect
.width(), ch
= frame
.rect
.height();
2321 if (cr
->value_mask
& CWBorderWidth
)
2322 client
.old_bw
= cr
->border_width
;
2324 if (cr
->value_mask
& CWX
)
2325 cx
= cr
->x
- frame
.margin
.left
;
2327 if (cr
->value_mask
& CWY
)
2328 cy
= cr
->y
- frame
.margin
.top
;
2330 if (cr
->value_mask
& CWWidth
)
2331 cw
= cr
->width
+ frame
.margin
.left
+ frame
.margin
.right
;
2333 if (cr
->value_mask
& CWHeight
)
2334 ch
= cr
->height
+ frame
.margin
.top
+ frame
.margin
.bottom
;
2336 if (frame
.rect
!= Rect(cx
, cy
, cw
, ch
))
2337 configure(cx
, cy
, cw
, ch
);
2339 if (cr
->value_mask
& CWStackMode
) {
2340 switch (cr
->detail
) {
2343 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2349 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2356 void BlackboxWindow::buttonPressEvent(XButtonEvent
*be
) {
2357 if (frame
.maximize_button
== be
->window
) {
2358 redrawMaximizeButton(True
);
2359 } else if (be
->button
== 1 || (be
->button
== 3 && be
->state
== Mod1Mask
)) {
2360 if (! flags
.focused
)
2363 if (frame
.iconify_button
== be
->window
) {
2364 redrawIconifyButton(True
);
2365 } else if (frame
.close_button
== be
->window
) {
2366 redrawCloseButton(True
);
2367 } else if (frame
.plate
== be
->window
) {
2368 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2370 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2372 XAllowEvents(blackbox
->getXDisplay(), ReplayPointer
, be
->time
);
2374 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
2375 if (((be
->time
- lastButtonPressTime
) <=
2376 blackbox
->getDoubleClickInterval()) ||
2377 (be
->state
& ControlMask
)) {
2378 lastButtonPressTime
= 0;
2381 lastButtonPressTime
= be
->time
;
2385 frame
.grab_x
= be
->x_root
- frame
.rect
.x() - frame
.border_w
;
2386 frame
.grab_y
= be
->y_root
- frame
.rect
.y() - frame
.border_w
;
2388 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2390 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2392 } else if (be
->button
== 2 && (be
->window
!= frame
.iconify_button
) &&
2393 (be
->window
!= frame
.close_button
)) {
2394 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2395 } else if (windowmenu
&& be
->button
== 3 &&
2396 (frame
.title
== be
->window
|| frame
.label
== be
->window
||
2397 frame
.handle
== be
->window
|| frame
.window
== be
->window
)) {
2400 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
2401 mx
= be
->x_root
- (windowmenu
->getWidth() / 2);
2402 my
= frame
.rect
.y() + frame
.title_h
+ frame
.border_w
;
2403 } else if (frame
.handle
== be
->window
) {
2404 mx
= be
->x_root
- (windowmenu
->getWidth() / 2);
2405 my
= frame
.rect
.bottom() - frame
.handle_h
- (frame
.border_w
* 3) -
2406 windowmenu
->getHeight();
2408 mx
= be
->x_root
- (windowmenu
->getWidth() / 2);
2410 if (be
->y
<= static_cast<signed>(frame
.bevel_w
))
2411 my
= frame
.rect
.y() + frame
.title_h
;
2413 my
= be
->y_root
- (windowmenu
->getHeight() / 2);
2416 // snap the window menu into a corner if necessary - we check the
2417 // position of the menu with the coordinates of the client to
2418 // make the comparisions easier.
2419 // XXX: this needs some work!
2420 if (mx
> client
.rect
.right() -
2421 static_cast<signed>(windowmenu
->getWidth()))
2422 mx
= frame
.rect
.right() - windowmenu
->getWidth() - frame
.border_w
+ 1;
2423 if (mx
< client
.rect
.left())
2424 mx
= frame
.rect
.x();
2426 if (my
> client
.rect
.bottom() -
2427 static_cast<signed>(windowmenu
->getHeight()))
2428 my
= frame
.rect
.bottom() - windowmenu
->getHeight() - frame
.border_w
+ 1;
2429 if (my
< client
.rect
.top())
2430 my
= frame
.rect
.y() + ((decorations
& Decor_Titlebar
) ?
2434 if (! windowmenu
->isVisible()) {
2435 windowmenu
->move(mx
, my
);
2437 XRaiseWindow(blackbox
->getXDisplay(), windowmenu
->getWindowID());
2438 XRaiseWindow(blackbox
->getXDisplay(),
2439 windowmenu
->getSendToMenu()->getWindowID());
2445 } else if (be
->button
== 4) {
2446 if ((be
->window
== frame
.label
||
2447 be
->window
== frame
.title
) &&
2451 } else if (be
->button
== 5) {
2452 if ((be
->window
== frame
.label
||
2453 be
->window
== frame
.title
) &&
2460 void BlackboxWindow::buttonReleaseEvent(XButtonEvent
*re
) {
2461 if (re
->window
== frame
.maximize_button
) {
2462 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2463 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2464 maximize(re
->button
);
2466 redrawMaximizeButton(flags
.maximized
);
2468 } else if (re
->window
== frame
.iconify_button
) {
2469 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2470 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2473 redrawIconifyButton(False
);
2475 } else if (re
->window
== frame
.close_button
) {
2476 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2477 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
)))
2479 redrawCloseButton(False
);
2480 } else if (flags
.moving
) {
2481 flags
.moving
= False
;
2483 if (! screen
->doOpaqueMove()) {
2484 /* when drawing the rubber band, we need to make sure we only draw inside
2485 * the frame... frame.changing_* contain the new coords for the window,
2486 * so we need to subtract 1 from changing_w/changing_h every where we
2487 * draw the rubber band (for both moving and resizing)
2489 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2490 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
2491 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
2492 XUngrabServer(blackbox
->getXDisplay());
2494 configure(frame
.changing
.x(), frame
.changing
.y(),
2495 frame
.changing
.width(), frame
.changing
.height());
2497 configure(frame
.rect
.x(), frame
.rect
.y(),
2498 frame
.rect
.width(), frame
.rect
.height());
2500 screen
->hideGeometry();
2501 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
2502 } else if (flags
.resizing
) {
2503 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2504 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
2505 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
2506 XUngrabServer(blackbox
->getXDisplay());
2508 screen
->hideGeometry();
2510 constrain((re
->window
== frame
.left_grip
) ? TopRight
: TopLeft
);
2512 // unset maximized state when resized after fully maximized
2513 if (flags
.maximized
== 1)
2515 flags
.resizing
= False
;
2516 configure(frame
.changing
.x(), frame
.changing
.y(),
2517 frame
.changing
.width(), frame
.changing
.height());
2519 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
2520 } else if (re
->window
== frame
.window
) {
2521 if (re
->button
== 2 && re
->state
== Mod1Mask
)
2522 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
2527 void BlackboxWindow::motionNotifyEvent(XMotionEvent
*me
) {
2528 if (! flags
.resizing
&& (me
->state
& Button1Mask
) &&
2529 (functions
& Func_Move
) &&
2530 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
2531 frame
.handle
== me
->window
|| frame
.window
== me
->window
)) {
2532 if (! flags
.moving
) {
2533 XGrabPointer(blackbox
->getXDisplay(), me
->window
, False
,
2534 Button1MotionMask
| ButtonReleaseMask
,
2535 GrabModeAsync
, GrabModeAsync
,
2536 None
, blackbox
->getMoveCursor(), CurrentTime
);
2538 if (windowmenu
&& windowmenu
->isVisible())
2541 flags
.moving
= True
;
2543 if (! screen
->doOpaqueMove()) {
2544 XGrabServer(blackbox
->getXDisplay());
2546 frame
.changing
= frame
.rect
;
2547 screen
->showPosition(frame
.changing
.x(), frame
.changing
.y());
2549 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2553 frame
.changing
.width() - 1,
2554 frame
.changing
.height() - 1);
2557 int dx
= me
->x_root
- frame
.grab_x
, dy
= me
->y_root
- frame
.grab_y
;
2558 dx
-= frame
.border_w
;
2559 dy
-= frame
.border_w
;
2561 const int snap_distance
= screen
->getEdgeSnapThreshold();
2563 if (snap_distance
) {
2565 const int wleft
= dx
,
2566 wright
= dx
+ frame
.rect
.width() - 1,
2568 wbottom
= dy
+ frame
.rect
.height() - 1;
2570 // Maybe this should be saved in the class, and set in the setWorkspace
2572 Workspace
*w
= screen
->getWorkspace(getWorkspaceNumber());
2575 if (screen
->getWindowToWindowSnap()) {
2576 // try snap to another window
2577 for (unsigned int i
= 0, c
= w
->getCount(); i
< c
; ++i
) {
2578 BlackboxWindow
*snapwin
= w
->getWindow(i
);
2579 if (snapwin
== this)
2580 continue; // don't snap to self
2582 const Rect
&winrect
= snapwin
->frameRect();
2583 int dleft
= std::abs(wright
- winrect
.left()),
2584 dright
= std::abs(wleft
- winrect
.right()),
2585 dtop
= std::abs(wbottom
- winrect
.top()),
2586 dbottom
= std::abs(wtop
- winrect
.bottom());
2588 // snap top of other window?
2589 if (dtop
< snap_distance
&& dtop
<= dbottom
) {
2590 dy
= winrect
.top() - frame
.rect
.height();
2592 if (screen
->getWindowCornerSnap()) {
2593 // try corner-snap to its other sides
2594 dleft
= std::abs(wleft
- winrect
.left());
2595 dright
= std::abs(wright
- winrect
.right());
2596 if (dleft
< snap_distance
&& dleft
<= dright
)
2597 dx
= winrect
.left();
2598 else if (dright
< snap_distance
)
2599 dx
= winrect
.right() - frame
.rect
.width() + 1;
2604 // snap bottom of other window?
2605 else if (dbottom
< snap_distance
) {
2606 dy
= winrect
.bottom() + 1;
2608 if (screen
->getWindowCornerSnap()) {
2609 // try corner-snap to its other sides
2610 dleft
= std::abs(wleft
- winrect
.left());
2611 dright
= std::abs(wright
- winrect
.right());
2612 if (dleft
< snap_distance
&& dleft
<= dright
)
2613 dx
= winrect
.left();
2614 else if (dright
< snap_distance
)
2615 dx
= winrect
.right() - frame
.rect
.width() + 1;
2621 // snap left of other window?
2622 if (dleft
< snap_distance
&& dleft
<= dright
) {
2623 dx
= winrect
.left() - frame
.rect
.width();
2625 if (screen
->getWindowCornerSnap()) {
2626 // try corner-snap to its other sides
2627 dtop
= std::abs(wtop
- winrect
.top());
2628 dbottom
= std::abs(wbottom
- winrect
.bottom());
2629 if (dtop
< snap_distance
&& dtop
<= dbottom
)
2631 else if (dbottom
< snap_distance
)
2632 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
2637 // snap right of other window?
2638 else if (dright
< snap_distance
) {
2639 dx
= winrect
.right() + 1;
2641 if (screen
->getWindowCornerSnap()) {
2642 // try corner-snap to its other sides
2643 dtop
= std::abs(wtop
- winrect
.top());
2644 dbottom
= std::abs(wbottom
- winrect
.bottom());
2645 if (dtop
< snap_distance
&& dtop
<= dbottom
)
2647 else if (dbottom
< snap_distance
)
2648 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
2656 // try snap to the screen's available area
2657 Rect srect
= screen
->availableArea();
2659 int dleft
= std::abs(wleft
- srect
.left()),
2660 dright
= std::abs(wright
- srect
.right()),
2661 dtop
= std::abs(wtop
- srect
.top()),
2662 dbottom
= std::abs(wbottom
- srect
.bottom());
2665 if (dleft
< snap_distance
&& dleft
<= dright
)
2668 else if (dright
< snap_distance
)
2669 dx
= srect
.right() - frame
.rect
.width() + 1;
2672 if (dtop
< snap_distance
&& dtop
<= dbottom
)
2675 else if (dbottom
< snap_distance
)
2676 dy
= srect
.bottom() - frame
.rect
.height() + 1;
2678 if (! screen
->doFullMax()) {
2679 srect
= screen
->getRect(); // now get the full screen
2681 dleft
= std::abs(wleft
- srect
.left()),
2682 dright
= std::abs(wright
- srect
.right()),
2683 dtop
= std::abs(wtop
- srect
.top()),
2684 dbottom
= std::abs(wbottom
- srect
.bottom());
2687 if (dleft
< snap_distance
&& dleft
<= dright
)
2690 else if (dright
< snap_distance
)
2691 dx
= srect
.right() - frame
.rect
.width() + 1;
2694 if (dtop
< snap_distance
&& dtop
<= dbottom
)
2697 else if (dbottom
< snap_distance
)
2698 dy
= srect
.bottom() - frame
.rect
.height() + 1;
2702 if (screen
->doOpaqueMove()) {
2703 configure(dx
, dy
, frame
.rect
.width(), frame
.rect
.height());
2705 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2709 frame
.changing
.width() - 1,
2710 frame
.changing
.height() - 1);
2712 frame
.changing
.setPos(dx
, dy
);
2714 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2718 frame
.changing
.width() - 1,
2719 frame
.changing
.height() - 1);
2722 screen
->showPosition(dx
, dy
);
2724 } else if ((functions
& Func_Resize
) &&
2725 (((me
->state
& Button1Mask
) &&
2726 (me
->window
== frame
.right_grip
||
2727 me
->window
== frame
.left_grip
)) ||
2728 (me
->state
& (Mod1Mask
| Button3Mask
) &&
2729 me
->window
== frame
.window
))) {
2730 bool left
= (me
->window
== frame
.left_grip
);
2732 if (! flags
.resizing
) {
2733 XGrabServer(blackbox
->getXDisplay());
2734 XGrabPointer(blackbox
->getXDisplay(), me
->window
, False
,
2735 ButtonMotionMask
| ButtonReleaseMask
,
2736 GrabModeAsync
, GrabModeAsync
, None
,
2737 ((left
) ? blackbox
->getLowerLeftAngleCursor() :
2738 blackbox
->getLowerRightAngleCursor()),
2741 flags
.resizing
= True
;
2744 frame
.grab_x
= me
->x
;
2745 frame
.grab_y
= me
->y
;
2746 frame
.changing
= frame
.rect
;
2748 constrain((left
) ? TopRight
: TopLeft
, &gw
, &gh
);
2750 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2751 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
2752 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
2754 screen
->showGeometry(gw
, gh
);
2756 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2757 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
2758 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
2766 frame
.changing
.setCoords(me
->x_root
- frame
.grab_x
, frame
.rect
.top(),
2767 frame
.rect
.right(), frame
.rect
.bottom());
2768 frame
.changing
.setHeight(frame
.rect
.height() + (me
->y
- frame
.grab_y
));
2771 frame
.changing
.setSize(frame
.rect
.width() + (me
->x
- frame
.grab_x
),
2772 frame
.rect
.height() + (me
->y
- frame
.grab_y
));
2775 constrain(anchor
, &gw
, &gh
);
2777 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2778 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
2779 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
2781 screen
->showGeometry(gw
, gh
);
2788 void BlackboxWindow::shapeEvent(XShapeEvent
*) {
2789 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
2796 bool BlackboxWindow::validateClient(void) const {
2797 XSync(blackbox
->getXDisplay(), False
);
2800 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
2801 DestroyNotify
, &e
) ||
2802 XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
2804 XPutBackEvent(blackbox
->getXDisplay(), &e
);
2813 void BlackboxWindow::restore(bool remap
) {
2814 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeDelete
);
2815 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
2816 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, NoEventMask
);
2820 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
2821 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
2823 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, client
.old_bw
);
2826 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
2827 ReparentNotify
, &ev
)) {
2830 // according to the ICCCM - if the client doesn't reparent to
2831 // root, then we have to do it for them
2832 XReparentWindow(blackbox
->getXDisplay(), client
.window
,
2833 screen
->getRootWindow(),
2834 client
.rect
.x(), client
.rect
.y());
2837 if (remap
) XMapWindow(blackbox
->getXDisplay(), client
.window
);
2841 // timer for autoraise
2842 void BlackboxWindow::timeout(void) {
2843 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2847 void BlackboxWindow::changeBlackboxHints(BlackboxHints
*net
) {
2848 if ((net
->flags
& AttribShaded
) &&
2849 ((blackbox_attrib
.attrib
& AttribShaded
) !=
2850 (net
->attrib
& AttribShaded
)))
2853 if (flags
.visible
&& // watch out for requests when we can not be seen
2854 (net
->flags
& (AttribMaxVert
| AttribMaxHoriz
)) &&
2855 ((blackbox_attrib
.attrib
& (AttribMaxVert
| AttribMaxHoriz
)) !=
2856 (net
->attrib
& (AttribMaxVert
| AttribMaxHoriz
)))) {
2857 if (flags
.maximized
) {
2862 if ((net
->flags
& AttribMaxHoriz
) && (net
->flags
& AttribMaxVert
))
2863 button
= ((net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0);
2864 else if (net
->flags
& AttribMaxVert
)
2865 button
= ((net
->attrib
& AttribMaxVert
) ? 2 : 0);
2866 else if (net
->flags
& AttribMaxHoriz
)
2867 button
= ((net
->attrib
& AttribMaxHoriz
) ? 3 : 0);
2873 if ((net
->flags
& AttribOmnipresent
) &&
2874 ((blackbox_attrib
.attrib
& AttribOmnipresent
) !=
2875 (net
->attrib
& AttribOmnipresent
)))
2878 if ((net
->flags
& AttribWorkspace
) &&
2879 (blackbox_attrib
.workspace
!= net
->workspace
)) {
2880 screen
->reassociateWindow(this, net
->workspace
, True
);
2882 if (screen
->getCurrentWorkspaceID() != net
->workspace
) {
2886 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2890 if (net
->flags
& AttribDecoration
) {
2891 switch (net
->decoration
) {
2893 // clear all decorations except close
2894 decorations
&= Decor_Close
;
2900 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Iconify
;
2902 decorations
= ((functions
& Func_Resize
) && !isTransient() ?
2903 decorations
| Decor_Handle
:
2904 decorations
&= ~Decor_Handle
);
2905 decorations
= (functions
& Func_Maximize
?
2906 decorations
| Decor_Maximize
:
2907 decorations
&= ~Decor_Maximize
);
2912 decorations
|= Decor_Titlebar
| Decor_Iconify
;
2913 decorations
&= ~(Decor_Border
| Decor_Handle
);
2915 decorations
= (functions
& Func_Maximize
?
2916 decorations
| Decor_Maximize
:
2917 decorations
&= ~Decor_Maximize
);
2922 decorations
|= Decor_Titlebar
;
2923 decorations
&= ~(Decor_Iconify
| Decor_Border
);
2925 decorations
= ((functions
& Func_Resize
) && !isTransient() ?
2926 decorations
| Decor_Handle
:
2927 decorations
&= ~Decor_Handle
);
2928 decorations
= (functions
& Func_Maximize
?
2929 decorations
| Decor_Maximize
:
2930 decorations
&= ~Decor_Maximize
);
2935 // we can not be shaded if we lack a titlebar
2936 if (flags
.shaded
&& ! (decorations
& Decor_Titlebar
))
2940 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
2941 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
2945 setState(current_state
);
2951 * Set the sizes of all components of the window frame
2952 * (the window decorations).
2953 * These values are based upon the current style settings and the client
2954 * window's dimensions.
2956 void BlackboxWindow::upsize(void) {
2957 frame
.bevel_w
= screen
->getBevelWidth();
2959 if (decorations
& Decor_Border
) {
2960 frame
.border_w
= screen
->getBorderWidth();
2961 if (! isTransient())
2962 frame
.mwm_border_w
= screen
->getFrameWidth();
2964 frame
.mwm_border_w
= 0;
2966 frame
.mwm_border_w
= frame
.border_w
= 0;
2969 if (decorations
& Decor_Titlebar
) {
2970 // the height of the titlebar is based upon the height of the font being
2971 // used to display the window's title
2972 WindowStyle
*style
= screen
->getWindowStyle();
2973 if (i18n
.multibyte())
2974 frame
.title_h
= (style
->fontset_extents
->max_ink_extent
.height
+
2975 (frame
.bevel_w
* 2) + 2);
2977 frame
.title_h
= (style
->font
->ascent
+ style
->font
->descent
+
2978 (frame
.bevel_w
* 2) + 2);
2980 frame
.label_h
= frame
.title_h
- (frame
.bevel_w
* 2);
2981 frame
.button_w
= (frame
.label_h
- 2);
2983 // set the top frame margin
2984 frame
.margin
.top
= frame
.border_w
+ frame
.title_h
+
2985 frame
.border_w
+ frame
.mwm_border_w
;
2991 // set the top frame margin
2992 frame
.margin
.top
= frame
.border_w
+ frame
.mwm_border_w
;
2995 // set the left/right frame margin
2996 frame
.margin
.left
= frame
.margin
.right
= frame
.border_w
+ frame
.mwm_border_w
;
2998 if (decorations
& Decor_Handle
) {
2999 frame
.grip_w
= frame
.button_w
* 2;
3000 frame
.handle_h
= screen
->getHandleWidth();
3002 // set the bottom frame margin
3003 frame
.margin
.bottom
= frame
.border_w
+ frame
.handle_h
+
3004 frame
.border_w
+ frame
.mwm_border_w
;
3009 // set the bottom frame margin
3010 frame
.margin
.bottom
= frame
.border_w
+ frame
.mwm_border_w
;
3014 We first get the normal dimensions and use this to define the inside_w/h
3015 then we modify the height if shading is in effect.
3016 If the shade state is not considered then frame.rect gets reset to the
3017 normal window size on a reconfigure() call resulting in improper
3018 dimensions appearing in move/resize and other events.
3021 height
= client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
,
3022 width
= client
.rect
.width() + frame
.margin
.left
+ frame
.margin
.right
;
3024 frame
.inside_w
= width
- (frame
.border_w
* 2);
3025 frame
.inside_h
= height
- (frame
.border_w
* 2);
3028 height
= frame
.title_h
+ (frame
.border_w
* 2);
3029 frame
.rect
.setSize(width
, height
);
3034 * Calculate the size of the client window and constrain it to the
3035 * size specified by the size hints of the client window.
3037 * The logical width and height are placed into pw and ph, if they
3038 * are non-zero. Logical size refers to the users perception of
3039 * the window size (for example an xterm resizes in cells, not in pixels).
3041 * The physical geometry is placed into frame.changing_{x,y,width,height}.
3042 * Physical geometry refers to the geometry of the window in pixels.
3044 void BlackboxWindow::constrain(Corner anchor
, int *pw
, int *ph
) {
3045 // frame.changing represents the requested frame size, we need to
3046 // strip the frame margin off and constrain the client size
3047 frame
.changing
.setCoords(frame
.changing
.left() + frame
.margin
.left
,
3048 frame
.changing
.top() + frame
.margin
.top
,
3049 frame
.changing
.right() - frame
.margin
.right
,
3050 frame
.changing
.bottom() - frame
.margin
.bottom
);
3052 int dw
= frame
.changing
.width(), dh
= frame
.changing
.height(),
3053 base_width
= (client
.base_width
) ? client
.base_width
: client
.min_width
,
3054 base_height
= (client
.base_height
) ? client
.base_height
:
3058 if (dw
< static_cast<signed>(client
.min_width
)) dw
= client
.min_width
;
3059 if (dh
< static_cast<signed>(client
.min_height
)) dh
= client
.min_height
;
3060 if (dw
> static_cast<signed>(client
.max_width
)) dw
= client
.max_width
;
3061 if (dh
> static_cast<signed>(client
.max_height
)) dh
= client
.max_height
;
3064 dw
/= client
.width_inc
;
3066 dh
/= client
.height_inc
;
3071 dw
*= client
.width_inc
;
3073 dh
*= client
.height_inc
;
3076 frame
.changing
.setSize(dw
, dh
);
3078 // add the frame margin back onto frame.changing
3079 frame
.changing
.setCoords(frame
.changing
.left() - frame
.margin
.left
,
3080 frame
.changing
.top() - frame
.margin
.top
,
3081 frame
.changing
.right() + frame
.margin
.right
,
3082 frame
.changing
.bottom() + frame
.margin
.bottom
);
3084 // move frame.changing to the specified anchor
3091 int dx
= frame
.rect
.right() - frame
.changing
.right();
3092 frame
.changing
.setPos(frame
.changing
.x() + dx
, frame
.changing
.y());
3098 int WindowStyle::doJustify(const char *text
, int &start_pos
,
3099 unsigned int max_length
, unsigned int modifier
,
3100 bool multibyte
) const {
3101 size_t text_len
= strlen(text
);
3102 unsigned int length
;
3106 XRectangle ink
, logical
;
3107 XmbTextExtents(fontset
, text
, text_len
, &ink
, &logical
);
3108 length
= logical
.width
;
3110 length
= XTextWidth(font
, text
, text_len
);
3113 } while (length
> max_length
&& text_len
-- > 0);
3117 start_pos
+= max_length
- length
;
3121 start_pos
+= (max_length
- length
) / 2;
3133 BWindowGroup::BWindowGroup(Blackbox
*b
, Window _group
)
3134 : blackbox(b
), group(_group
) {
3135 XWindowAttributes wattrib
;
3136 if (! XGetWindowAttributes(blackbox
->getXDisplay(), group
, &wattrib
)) {
3137 // group window doesn't seem to exist anymore
3143 watch for destroy notify on the group window (in addition to
3144 any other events we are looking for)
3146 since some managed windows can also be window group controllers,
3147 we need to make sure that we don't clobber the event mask for the
3150 XSelectInput(blackbox
->getXDisplay(), group
,
3151 wattrib
.your_event_mask
| StructureNotifyMask
);
3153 blackbox
->saveGroupSearch(group
, this);
3157 BWindowGroup::~BWindowGroup(void) {
3158 blackbox
->removeGroupSearch(group
);
3163 BWindowGroup::find(BScreen
*screen
, bool allow_transients
) const {
3164 BlackboxWindow
*ret
= blackbox
->getFocusedWindow();
3166 // does the focus window match (or any transient_fors)?
3168 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3169 if (ret
->isTransient() && allow_transients
) break;
3170 else if (! ret
->isTransient()) break;
3173 ret
= ret
->getTransientFor();
3176 if (ret
) return ret
;
3178 // the focus window didn't match, look in the group's window list
3179 BlackboxWindowList::const_iterator it
, end
= windowList
.end();
3180 for (it
= windowList
.begin(); it
!= end
; ++it
) {
3182 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3183 if (ret
->isTransient() && allow_transients
) break;
3184 else if (! ret
->isTransient()) break;