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
);
71 // set timer to zero... it is initialized properly later, so we check
72 // if timer is zero in the destructor, and assume that the window is not
73 // fully constructed if timer is zero...
78 xatom
= blackbox
->getXAtom();
80 if (! validateClient()) {
85 // set the eventmask early in the game so that we make sure we get
86 // all the events we are interested in
87 XSetWindowAttributes attrib_set
;
88 attrib_set
.event_mask
= PropertyChangeMask
| FocusChangeMask
|
90 attrib_set
.do_not_propagate_mask
= ButtonPressMask
| ButtonReleaseMask
|
92 XChangeWindowAttributes(blackbox
->getXDisplay(), client
.window
,
93 CWEventMask
|CWDontPropagate
, &attrib_set
);
95 // fetch client size and placement
96 XWindowAttributes wattrib
;
97 if ((! XGetWindowAttributes(blackbox
->getXDisplay(),
98 client
.window
, &wattrib
)) ||
99 (! wattrib
.screen
) || wattrib
.override_redirect
) {
102 "BlackboxWindow::BlackboxWindow(): XGetWindowAttributes failed\n");
109 flags
.moving
= flags
.resizing
= flags
.shaded
= flags
.visible
=
110 flags
.iconic
= flags
.focused
= flags
.stuck
= flags
.modal
=
111 flags
.send_focus_message
= flags
.shaped
= False
;
114 blackbox_attrib
.workspace
= window_number
= BSENTINEL
;
116 blackbox_attrib
.flags
= blackbox_attrib
.attrib
= blackbox_attrib
.stack
117 = blackbox_attrib
.decoration
= 0l;
118 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
119 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
122 frame
.window
= frame
.plate
= frame
.title
= frame
.handle
= None
;
123 frame
.close_button
= frame
.iconify_button
= frame
.maximize_button
= None
;
124 frame
.right_grip
= frame
.left_grip
= None
;
126 frame
.ulabel_pixel
= frame
.flabel_pixel
= frame
.utitle_pixel
=
127 frame
.ftitle_pixel
= frame
.uhandle_pixel
= frame
.fhandle_pixel
=
128 frame
.ubutton_pixel
= frame
.fbutton_pixel
= frame
.pbutton_pixel
=
129 frame
.uborder_pixel
= frame
.fborder_pixel
= frame
.ugrip_pixel
=
130 frame
.fgrip_pixel
= 0;
131 frame
.utitle
= frame
.ftitle
= frame
.uhandle
= frame
.fhandle
= None
;
132 frame
.ulabel
= frame
.flabel
= frame
.ubutton
= frame
.fbutton
= None
;
133 frame
.pbutton
= frame
.ugrip
= frame
.fgrip
= decorations
;
135 decorations
= Decor_Titlebar
| Decor_Border
| Decor_Handle
|
136 Decor_Iconify
| Decor_Maximize
;
137 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
139 client
.wm_hint_flags
= client
.normal_hint_flags
= 0;
140 client
.transient_for
= 0;
142 // get the initial size and location of client window (relative to the
143 // _root window_). This position is the reference point used with the
144 // window's gravity to find the window's initial position.
145 client
.rect
.setRect(wattrib
.x
, wattrib
.y
, wattrib
.width
, wattrib
.height
);
146 client
.old_bw
= wattrib
.border_width
;
149 lastButtonPressTime
= 0;
151 timer
= new BTimer(blackbox
, this);
152 timer
->setTimeout(blackbox
->getAutoRaiseDelay());
154 if (! getBlackboxHints())
157 // get size, aspect, minimum/maximum size and other hints set by the
163 if (client
.initial_state
== WithdrawnState
) {
164 screen
->getSlit()->addClient(client
.window
);
169 frame
.window
= createToplevelWindow();
170 frame
.plate
= createChildWindow(frame
.window
);
171 associateClientWindow();
173 blackbox
->saveWindowSearch(frame
.window
, this);
174 blackbox
->saveWindowSearch(frame
.plate
, this);
175 blackbox
->saveWindowSearch(client
.window
, this);
177 // determine if this is a transient window
180 // adjust the window decorations based on transience and window sizes
182 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
183 functions
&= ~Func_Maximize
;
186 if ((client
.normal_hint_flags
& PMinSize
) &&
187 (client
.normal_hint_flags
& PMaxSize
) &&
188 client
.max_width
<= client
.min_width
&&
189 client
.max_height
<= client
.min_height
) {
190 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
191 functions
&= ~(Func_Resize
| Func_Maximize
);
195 bool place_window
= True
;
196 if (blackbox
->isStartup() || isTransient() ||
197 client
.normal_hint_flags
& (PPosition
|USPosition
)) {
201 if (blackbox
->isStartup() ||
202 client
.rect
.intersects(screen
->availableArea()))
203 place_window
= False
;
206 if (decorations
& Decor_Titlebar
)
209 if (decorations
& Decor_Handle
)
213 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
218 if ((! screen
->isSloppyFocus()) || screen
->doClickRaise()) {
219 // grab button 1 for changing focus/raising
220 blackbox
->grabButton(Button1
, 0, frame
.plate
, True
, ButtonPressMask
,
221 GrabModeSync
, GrabModeSync
, frame
.plate
, None
);
224 blackbox
->grabButton(Button1
, Mod1Mask
, frame
.window
, True
,
225 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
226 GrabModeAsync
, frame
.window
, blackbox
->getMoveCursor());
227 blackbox
->grabButton(Button2
, Mod1Mask
, frame
.window
, True
,
228 ButtonReleaseMask
, GrabModeAsync
, GrabModeAsync
,
230 blackbox
->grabButton(Button3
, Mod1Mask
, frame
.window
, True
,
231 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
232 GrabModeAsync
, frame
.window
,
233 blackbox
->getLowerRightAngleCursor());
238 if (decorations
& Decor_Titlebar
)
239 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
240 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
242 windowmenu
= new Windowmenu(this);
244 if (blackbox_attrib
.workspace
>= screen
->getWorkspaceCount())
245 screen
->getCurrentWorkspace()->addWindow(this, place_window
);
247 screen
->getWorkspace(blackbox_attrib
.workspace
)->
248 addWindow(this, place_window
);
250 if (! place_window
) {
251 // don't need to call configure if we are letting the workspace
253 configure(frame
.rect
.x(), frame
.rect
.y(),
254 frame
.rect
.width(), frame
.rect
.height());
258 flags
.shaded
= False
;
262 if (flags
.maximized
&& (functions
& Func_Maximize
)) {
270 BlackboxWindow::~BlackboxWindow(void) {
273 fprintf(stderr
, "BlackboxWindow::~BlackboxWindow: destroying 0x%lx\n",
277 if (! timer
) // window not managed...
280 if (flags
.moving
|| flags
.resizing
) {
281 screen
->hideGeometry();
282 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
289 if (client
.window_group
) {
290 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
291 if (group
) group
->removeWindow(this);
294 // remove ourselves from our transient_for
296 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
297 client
.transient_for
->client
.transientList
.remove(this);
299 client
.transient_for
= (BlackboxWindow
*) 0;
302 if (client
.transientList
.size() > 0) {
303 // reset transient_for for all transients
304 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
305 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
306 (*it
)->client
.transient_for
= (BlackboxWindow
*) 0;
317 blackbox
->removeWindowSearch(frame
.plate
);
318 XDestroyWindow(blackbox
->getXDisplay(), frame
.plate
);
322 blackbox
->removeWindowSearch(frame
.window
);
323 XDestroyWindow(blackbox
->getXDisplay(), frame
.window
);
326 blackbox
->removeWindowSearch(client
.window
);
331 * Creates a new top level window, with a given location, size, and border
333 * Returns: the newly created window
335 Window
BlackboxWindow::createToplevelWindow(void) {
336 XSetWindowAttributes attrib_create
;
337 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
| CWColormap
|
338 CWOverrideRedirect
| CWEventMask
;
340 attrib_create
.background_pixmap
= None
;
341 attrib_create
.colormap
= screen
->getColormap();
342 attrib_create
.override_redirect
= True
;
343 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
344 ButtonMotionMask
| EnterWindowMask
;
346 return XCreateWindow(blackbox
->getXDisplay(), screen
->getRootWindow(),
347 -1, -1, 1, 1, frame
.border_w
, screen
->getDepth(),
348 InputOutput
, screen
->getVisual(), create_mask
,
354 * Creates a child window, and optionally associates a given cursor with
357 Window
BlackboxWindow::createChildWindow(Window parent
, Cursor cursor
) {
358 XSetWindowAttributes attrib_create
;
359 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
|
362 attrib_create
.background_pixmap
= None
;
363 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
364 ButtonMotionMask
| ExposureMask
;
367 create_mask
|= CWCursor
;
368 attrib_create
.cursor
= cursor
;
371 return XCreateWindow(blackbox
->getXDisplay(), parent
, 0, 0, 1, 1, 0,
372 screen
->getDepth(), InputOutput
, screen
->getVisual(),
373 create_mask
, &attrib_create
);
377 void BlackboxWindow::associateClientWindow(void) {
378 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, 0);
382 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeInsert
);
384 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, SubstructureRedirectMask
);
386 XGrabServer(blackbox
->getXDisplay());
387 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
388 XReparentWindow(blackbox
->getXDisplay(), client
.window
, frame
.plate
, 0, 0);
389 XSelectInput(blackbox
->getXDisplay(), client
.window
,
390 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
391 XUngrabServer(blackbox
->getXDisplay());
393 XRaiseWindow(blackbox
->getXDisplay(), frame
.plate
);
394 XMapSubwindows(blackbox
->getXDisplay(), frame
.plate
);
398 if (blackbox
->hasShapeExtensions()) {
399 XShapeSelectInput(blackbox
->getXDisplay(), client
.window
,
406 XShapeQueryExtents(blackbox
->getXDisplay(), client
.window
, &shaped
,
407 &foo
, &foo
, &ufoo
, &ufoo
, &foo
, &foo
, &foo
,
409 flags
.shaped
= shaped
;
415 void BlackboxWindow::decorate(void) {
418 texture
= &(screen
->getWindowStyle()->b_focus
);
419 frame
.fbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
422 frame
.fbutton_pixel
= texture
->color().pixel();
424 texture
= &(screen
->getWindowStyle()->b_unfocus
);
425 frame
.ubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
428 frame
.ubutton_pixel
= texture
->color().pixel();
430 texture
= &(screen
->getWindowStyle()->b_pressed
);
431 frame
.pbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
434 frame
.pbutton_pixel
= texture
->color().pixel();
436 if (decorations
& Decor_Titlebar
) {
437 texture
= &(screen
->getWindowStyle()->t_focus
);
438 frame
.ftitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
441 frame
.ftitle_pixel
= texture
->color().pixel();
443 texture
= &(screen
->getWindowStyle()->t_unfocus
);
444 frame
.utitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
447 frame
.utitle_pixel
= texture
->color().pixel();
449 XSetWindowBorder(blackbox
->getXDisplay(), frame
.title
,
450 screen
->getBorderColor()->pixel());
455 if (decorations
& Decor_Border
) {
456 frame
.fborder_pixel
= screen
->getWindowStyle()->f_focus
.pixel();
457 frame
.uborder_pixel
= screen
->getWindowStyle()->f_unfocus
.pixel();
458 blackbox_attrib
.flags
|= AttribDecoration
;
459 blackbox_attrib
.decoration
= DecorNormal
;
461 blackbox_attrib
.flags
|= AttribDecoration
;
462 blackbox_attrib
.decoration
= DecorNone
;
465 if (decorations
& Decor_Handle
) {
466 texture
= &(screen
->getWindowStyle()->h_focus
);
467 frame
.fhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
470 frame
.fhandle_pixel
= texture
->color().pixel();
472 texture
= &(screen
->getWindowStyle()->h_unfocus
);
473 frame
.uhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
476 frame
.uhandle_pixel
= texture
->color().pixel();
478 texture
= &(screen
->getWindowStyle()->g_focus
);
479 frame
.fgrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.fgrip
);
481 frame
.fgrip_pixel
= texture
->color().pixel();
483 texture
= &(screen
->getWindowStyle()->g_unfocus
);
484 frame
.ugrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.ugrip
);
486 frame
.ugrip_pixel
= texture
->color().pixel();
488 XSetWindowBorder(blackbox
->getXDisplay(), frame
.handle
,
489 screen
->getBorderColor()->pixel());
490 XSetWindowBorder(blackbox
->getXDisplay(), frame
.left_grip
,
491 screen
->getBorderColor()->pixel());
492 XSetWindowBorder(blackbox
->getXDisplay(), frame
.right_grip
,
493 screen
->getBorderColor()->pixel());
496 XSetWindowBorder(blackbox
->getXDisplay(), frame
.window
,
497 screen
->getBorderColor()->pixel());
501 void BlackboxWindow::decorateLabel(void) {
504 texture
= &(screen
->getWindowStyle()->l_focus
);
505 frame
.flabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.flabel
);
507 frame
.flabel_pixel
= texture
->color().pixel();
509 texture
= &(screen
->getWindowStyle()->l_unfocus
);
510 frame
.ulabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.ulabel
);
512 frame
.ulabel_pixel
= texture
->color().pixel();
516 void BlackboxWindow::createHandle(void) {
517 frame
.handle
= createChildWindow(frame
.window
);
518 blackbox
->saveWindowSearch(frame
.handle
, this);
521 createChildWindow(frame
.handle
, blackbox
->getLowerLeftAngleCursor());
522 blackbox
->saveWindowSearch(frame
.left_grip
, this);
525 createChildWindow(frame
.handle
, blackbox
->getLowerRightAngleCursor());
526 blackbox
->saveWindowSearch(frame
.right_grip
, this);
530 void BlackboxWindow::destroyHandle(void) {
532 screen
->getImageControl()->removeImage(frame
.fhandle
);
535 screen
->getImageControl()->removeImage(frame
.uhandle
);
538 screen
->getImageControl()->removeImage(frame
.fgrip
);
541 screen
->getImageControl()->removeImage(frame
.ugrip
);
543 blackbox
->removeWindowSearch(frame
.left_grip
);
544 blackbox
->removeWindowSearch(frame
.right_grip
);
546 XDestroyWindow(blackbox
->getXDisplay(), frame
.left_grip
);
547 XDestroyWindow(blackbox
->getXDisplay(), frame
.right_grip
);
548 frame
.left_grip
= frame
.right_grip
= None
;
550 blackbox
->removeWindowSearch(frame
.handle
);
551 XDestroyWindow(blackbox
->getXDisplay(), frame
.handle
);
556 void BlackboxWindow::createTitlebar(void) {
557 frame
.title
= createChildWindow(frame
.window
);
558 frame
.label
= createChildWindow(frame
.title
);
559 blackbox
->saveWindowSearch(frame
.title
, this);
560 blackbox
->saveWindowSearch(frame
.label
, this);
562 if (decorations
& Decor_Iconify
) createIconifyButton();
563 if (decorations
& Decor_Maximize
) createMaximizeButton();
564 if (decorations
& Decor_Close
) createCloseButton();
568 void BlackboxWindow::destroyTitlebar(void) {
569 if (frame
.close_button
)
570 destroyCloseButton();
572 if (frame
.iconify_button
)
573 destroyIconifyButton();
575 if (frame
.maximize_button
)
576 destroyMaximizeButton();
579 screen
->getImageControl()->removeImage(frame
.ftitle
);
582 screen
->getImageControl()->removeImage(frame
.utitle
);
585 screen
->getImageControl()->removeImage(frame
.flabel
);
588 screen
->getImageControl()->removeImage(frame
.ulabel
);
591 screen
->getImageControl()->removeImage(frame
.fbutton
);
594 screen
->getImageControl()->removeImage(frame
.ubutton
);
597 screen
->getImageControl()->removeImage(frame
.pbutton
);
599 blackbox
->removeWindowSearch(frame
.title
);
600 blackbox
->removeWindowSearch(frame
.label
);
602 XDestroyWindow(blackbox
->getXDisplay(), frame
.label
);
603 XDestroyWindow(blackbox
->getXDisplay(), frame
.title
);
604 frame
.title
= frame
.label
= None
;
608 void BlackboxWindow::createCloseButton(void) {
609 if (frame
.title
!= None
) {
610 frame
.close_button
= createChildWindow(frame
.title
);
611 blackbox
->saveWindowSearch(frame
.close_button
, this);
616 void BlackboxWindow::destroyCloseButton(void) {
617 blackbox
->removeWindowSearch(frame
.close_button
);
618 XDestroyWindow(blackbox
->getXDisplay(), frame
.close_button
);
619 frame
.close_button
= None
;
623 void BlackboxWindow::createIconifyButton(void) {
624 if (frame
.title
!= None
) {
625 frame
.iconify_button
= createChildWindow(frame
.title
);
626 blackbox
->saveWindowSearch(frame
.iconify_button
, this);
631 void BlackboxWindow::destroyIconifyButton(void) {
632 blackbox
->removeWindowSearch(frame
.iconify_button
);
633 XDestroyWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
634 frame
.iconify_button
= None
;
638 void BlackboxWindow::createMaximizeButton(void) {
639 if (frame
.title
!= None
) {
640 frame
.maximize_button
= createChildWindow(frame
.title
);
641 blackbox
->saveWindowSearch(frame
.maximize_button
, this);
646 void BlackboxWindow::destroyMaximizeButton(void) {
647 blackbox
->removeWindowSearch(frame
.maximize_button
);
648 XDestroyWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
649 frame
.maximize_button
= None
;
653 void BlackboxWindow::positionButtons(bool redecorate_label
) {
654 string layout
= blackbox
->getTitlebarLayout();
657 bool hasclose
, hasiconify
, hasmaximize
, haslabel
;
658 hasclose
= hasiconify
= hasmaximize
= haslabel
= false;
660 string::const_iterator it
, end
;
661 for (it
= layout
.begin(), end
= layout
.end(); it
!= end
; ++it
) {
664 if (! hasclose
&& (decorations
& Decor_Close
)) {
670 if (! hasiconify
&& (decorations
& Decor_Iconify
)) {
676 if (! hasmaximize
&& (decorations
& Decor_Maximize
)) {
688 if (! hasclose
&& frame
.close_button
)
689 destroyCloseButton();
690 if (! hasiconify
&& frame
.iconify_button
)
691 destroyIconifyButton();
692 if (! hasmaximize
&& frame
.maximize_button
)
693 destroyMaximizeButton();
695 parsed
+= 'L'; // require that the label be in the layout
697 const unsigned int bsep
= frame
.bevel_w
+ 1; // separation between elements
698 const unsigned int by
= frame
.bevel_w
+ 1;
699 const unsigned int ty
= frame
.bevel_w
;
701 frame
.label_w
= frame
.inside_w
- bsep
* 2 -
702 (frame
.button_w
+ bsep
) * (parsed
.size() - 1);
704 unsigned int x
= bsep
;
705 for (it
= parsed
.begin(), end
= parsed
.end(); it
!= end
; ++it
) {
708 if (!frame
.close_button
) createCloseButton();
709 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.close_button
, x
, by
,
710 frame
.button_w
, frame
.button_w
);
711 x
+= frame
.button_w
+ bsep
;
714 if (!frame
.iconify_button
) createIconifyButton();
715 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.iconify_button
, x
, by
,
716 frame
.button_w
, frame
.button_w
);
717 x
+= frame
.button_w
+ bsep
;
720 if (!frame
.maximize_button
) createMaximizeButton();
721 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.maximize_button
, x
, by
,
722 frame
.button_w
, frame
.button_w
);
723 x
+= frame
.button_w
+ bsep
;
726 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.label
, x
, ty
,
727 frame
.label_w
, frame
.label_h
);
728 x
+= frame
.label_w
+ bsep
;
733 if (redecorate_label
) decorateLabel();
739 void BlackboxWindow::reconfigure(void) {
742 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
743 frame
.rect
.top() + frame
.margin
.top
);
748 XClearWindow(blackbox
->getXDisplay(), frame
.window
);
749 setFocusFlag(flags
.focused
);
751 configure(frame
.rect
.x(), frame
.rect
.y(),
752 frame
.rect
.width(), frame
.rect
.height());
755 windowmenu
->move(windowmenu
->getX(), frame
.rect
.y() + frame
.title_h
);
756 windowmenu
->reconfigure();
761 void BlackboxWindow::updateFocusModel(void) {
762 if ((! screen
->isSloppyFocus()) || screen
->doClickRaise()) {
763 // grab button 1 for changing focus/raising
764 blackbox
->grabButton(Button1
, 0, frame
.plate
, True
, ButtonPressMask
,
765 GrabModeSync
, GrabModeSync
, None
, None
);
767 blackbox
->ungrabButton(Button1
, 0, frame
.plate
);
772 void BlackboxWindow::positionWindows(void) {
773 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.window
,
774 frame
.rect
.x(), frame
.rect
.y(), frame
.inside_w
,
775 (flags
.shaded
) ? frame
.title_h
: frame
.inside_h
);
776 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.window
, frame
.border_w
);
777 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.plate
,
779 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.plate
,
780 frame
.margin
.left
- frame
.mwm_border_w
- frame
.border_w
,
781 frame
.margin
.top
- frame
.mwm_border_w
- frame
.border_w
,
782 client
.rect
.width(), client
.rect
.height());
783 XMoveResizeWindow(blackbox
->getXDisplay(), client
.window
,
784 0, 0, client
.rect
.width(), client
.rect
.height());
786 if (decorations
& Decor_Titlebar
) {
787 if (frame
.title
== None
) createTitlebar();
789 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.title
,
791 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.title
, -frame
.border_w
,
792 -frame
.border_w
, frame
.inside_w
, frame
.title_h
);
795 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
796 XMapWindow(blackbox
->getXDisplay(), frame
.title
);
797 } else if (frame
.title
) {
800 if (decorations
& Decor_Handle
) {
801 if (frame
.handle
== None
) createHandle();
802 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.handle
,
804 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.left_grip
,
806 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.right_grip
,
809 // use client.rect here so the value is correct even if shaded
810 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.handle
,
812 client
.rect
.height() + frame
.margin
.top
+
813 frame
.mwm_border_w
- frame
.border_w
,
814 frame
.inside_w
, frame
.handle_h
);
815 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.left_grip
,
816 -frame
.border_w
, -frame
.border_w
,
817 frame
.grip_w
, frame
.handle_h
);
818 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.right_grip
,
819 frame
.inside_w
- frame
.grip_w
- frame
.border_w
,
820 -frame
.border_w
, frame
.grip_w
, frame
.handle_h
);
822 XMapSubwindows(blackbox
->getXDisplay(), frame
.handle
);
823 XMapWindow(blackbox
->getXDisplay(), frame
.handle
);
824 } else if (frame
.handle
) {
830 void BlackboxWindow::getWMName(void) {
831 XTextProperty text_prop
;
833 if (XGetWMName(blackbox
->getXDisplay(), client
.window
, &text_prop
)) {
834 client
.title
= textPropertyToString(blackbox
->getXDisplay(), text_prop
);
835 if (client
.title
.empty())
836 client
.title
= i18n(WindowSet
, WindowUnnamed
, "Unnamed");
837 XFree((char *) text_prop
.value
);
839 client
.title
= i18n(WindowSet
, WindowUnnamed
, "Unnamed");
844 void BlackboxWindow::getWMIconName(void) {
845 XTextProperty text_prop
;
847 if (XGetWMIconName(blackbox
->getXDisplay(), client
.window
, &text_prop
)) {
849 textPropertyToString(blackbox
->getXDisplay(), text_prop
);
850 if (client
.icon_title
.empty())
851 client
.icon_title
= client
.title
;
852 XFree((char *) text_prop
.value
);
854 client
.icon_title
= client
.title
;
860 * Retrieve which WM Protocols are supported by the client window.
861 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
862 * window's decorations and allow the close behavior.
863 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
866 void BlackboxWindow::getWMProtocols(void) {
870 if (XGetWMProtocols(blackbox
->getXDisplay(), client
.window
,
871 &proto
, &num_return
)) {
872 for (int i
= 0; i
< num_return
; ++i
) {
873 if (proto
[i
] == blackbox
->getWMDeleteAtom()) {
874 decorations
|= Decor_Close
;
875 functions
|= Func_Close
;
876 } else if (proto
[i
] == blackbox
->getWMTakeFocusAtom())
877 flags
.send_focus_message
= True
;
878 else if (proto
[i
] == blackbox
->getBlackboxStructureMessagesAtom())
879 screen
->addNetizen(new Netizen(screen
, client
.window
));
888 * Gets the value of the WM_HINTS property.
889 * If the property is not set, then use a set of default values.
891 void BlackboxWindow::getWMHints(void) {
892 focus_mode
= F_Passive
;
893 client
.initial_state
= NormalState
;
895 // remove from current window group
896 if (client
.window_group
) {
897 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
898 if (group
) group
->removeWindow(this);
900 client
.window_group
= None
;
902 XWMHints
*wmhint
= XGetWMHints(blackbox
->getXDisplay(), client
.window
);
907 if (wmhint
->flags
& InputHint
) {
908 if (wmhint
->input
== True
) {
909 if (flags
.send_focus_message
)
910 focus_mode
= F_LocallyActive
;
912 if (flags
.send_focus_message
)
913 focus_mode
= F_GloballyActive
;
915 focus_mode
= F_NoInput
;
919 if (wmhint
->flags
& StateHint
)
920 client
.initial_state
= wmhint
->initial_state
;
922 if (wmhint
->flags
& WindowGroupHint
) {
923 client
.window_group
= wmhint
->window_group
;
925 // add window to the appropriate group
926 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
927 if (! group
) // no group found, create it!
928 group
= new BWindowGroup(blackbox
, client
.window_group
);
929 group
->addWindow(this);
932 client
.wm_hint_flags
= wmhint
->flags
;
938 * Gets the value of the WM_NORMAL_HINTS property.
939 * If the property is not set, then use a set of default values.
941 void BlackboxWindow::getWMNormalHints(void) {
945 client
.min_width
= client
.min_height
=
946 client
.width_inc
= client
.height_inc
= 1;
947 client
.base_width
= client
.base_height
= 0;
950 use the full screen, not the strut modified size. otherwise when the
951 availableArea changes max_width/height will be incorrect and lead to odd
954 const Rect
& screen_area
= screen
->getRect();
955 client
.max_width
= screen_area
.width();
957 client
.max_height
= screen_area
.height();
958 client
.min_aspect_x
= client
.min_aspect_y
=
959 client
.max_aspect_x
= client
.max_aspect_y
= 1;
960 client
.win_gravity
= NorthWestGravity
;
962 if (! XGetWMNormalHints(blackbox
->getXDisplay(), client
.window
,
963 &sizehint
, &icccm_mask
))
966 client
.normal_hint_flags
= sizehint
.flags
;
968 if (sizehint
.flags
& PMinSize
) {
969 client
.min_width
= sizehint
.min_width
;
970 client
.min_height
= sizehint
.min_height
;
973 if (sizehint
.flags
& PMaxSize
) {
974 client
.max_width
= sizehint
.max_width
;
975 client
.max_height
= sizehint
.max_height
;
978 if (sizehint
.flags
& PResizeInc
) {
979 client
.width_inc
= sizehint
.width_inc
;
980 client
.height_inc
= sizehint
.height_inc
;
983 if (sizehint
.flags
& PAspect
) {
984 client
.min_aspect_x
= sizehint
.min_aspect
.x
;
985 client
.min_aspect_y
= sizehint
.min_aspect
.y
;
986 client
.max_aspect_x
= sizehint
.max_aspect
.x
;
987 client
.max_aspect_y
= sizehint
.max_aspect
.y
;
990 if (sizehint
.flags
& PBaseSize
) {
991 client
.base_width
= sizehint
.base_width
;
992 client
.base_height
= sizehint
.base_height
;
995 if (sizehint
.flags
& PWinGravity
)
996 client
.win_gravity
= sizehint
.win_gravity
;
1001 * Gets the MWM hints for the class' contained window.
1002 * This is used while initializing the window to its first state, and not
1004 * Returns: true if the MWM hints are successfully retreived and applied;
1005 * false if they are not.
1007 void BlackboxWindow::getMWMHints(void) {
1010 unsigned long num
, len
;
1011 MwmHints
*mwm_hint
= 0;
1013 int ret
= XGetWindowProperty(blackbox
->getXDisplay(), client
.window
,
1014 blackbox
->getMotifWMHintsAtom(), 0,
1015 PropMwmHintsElements
, False
,
1016 blackbox
->getMotifWMHintsAtom(), &atom_return
,
1017 &format
, &num
, &len
,
1018 (unsigned char **) &mwm_hint
);
1020 if (ret
!= Success
|| ! mwm_hint
|| num
!= PropMwmHintsElements
)
1023 if (mwm_hint
->flags
& MwmHintsDecorations
) {
1024 if (mwm_hint
->decorations
& MwmDecorAll
) {
1025 decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
1026 Decor_Iconify
| Decor_Maximize
| Decor_Close
;
1030 if (mwm_hint
->decorations
& MwmDecorBorder
)
1031 decorations
|= Decor_Border
;
1032 if (mwm_hint
->decorations
& MwmDecorHandle
)
1033 decorations
|= Decor_Handle
;
1034 if (mwm_hint
->decorations
& MwmDecorTitle
)
1035 decorations
|= Decor_Titlebar
;
1036 if (mwm_hint
->decorations
& MwmDecorIconify
)
1037 decorations
|= Decor_Iconify
;
1038 if (mwm_hint
->decorations
& MwmDecorMaximize
)
1039 decorations
|= Decor_Maximize
;
1043 if (mwm_hint
->flags
& MwmHintsFunctions
) {
1044 if (mwm_hint
->functions
& MwmFuncAll
) {
1045 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
|
1050 if (mwm_hint
->functions
& MwmFuncResize
)
1051 functions
|= Func_Resize
;
1052 if (mwm_hint
->functions
& MwmFuncMove
)
1053 functions
|= Func_Move
;
1054 if (mwm_hint
->functions
& MwmFuncIconify
)
1055 functions
|= Func_Iconify
;
1056 if (mwm_hint
->functions
& MwmFuncMaximize
)
1057 functions
|= Func_Maximize
;
1058 if (mwm_hint
->functions
& MwmFuncClose
)
1059 functions
|= Func_Close
;
1067 * Gets the blackbox hints from the class' contained window.
1068 * This is used while initializing the window to its first state, and not
1070 * Returns: true if the hints are successfully retreived and applied; false if
1073 bool BlackboxWindow::getBlackboxHints(void) {
1076 unsigned long num
, len
;
1077 BlackboxHints
*blackbox_hint
= 0;
1079 int ret
= XGetWindowProperty(blackbox
->getXDisplay(), client
.window
,
1080 blackbox
->getBlackboxHintsAtom(), 0,
1081 PropBlackboxHintsElements
, False
,
1082 blackbox
->getBlackboxHintsAtom(), &atom_return
,
1083 &format
, &num
, &len
,
1084 (unsigned char **) &blackbox_hint
);
1085 if (ret
!= Success
|| ! blackbox_hint
|| num
!= PropBlackboxHintsElements
)
1088 if (blackbox_hint
->flags
& AttribShaded
)
1089 flags
.shaded
= (blackbox_hint
->attrib
& AttribShaded
);
1091 if ((blackbox_hint
->flags
& AttribMaxHoriz
) &&
1092 (blackbox_hint
->flags
& AttribMaxVert
))
1093 flags
.maximized
= (blackbox_hint
->attrib
&
1094 (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1095 else if (blackbox_hint
->flags
& AttribMaxVert
)
1096 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxVert
) ? 2 : 0;
1097 else if (blackbox_hint
->flags
& AttribMaxHoriz
)
1098 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1100 if (blackbox_hint
->flags
& AttribOmnipresent
)
1101 flags
.stuck
= (blackbox_hint
->attrib
& AttribOmnipresent
);
1103 if (blackbox_hint
->flags
& AttribWorkspace
)
1104 blackbox_attrib
.workspace
= blackbox_hint
->workspace
;
1106 // if (blackbox_hint->flags & AttribStack)
1107 // don't yet have always on top/bottom for blackbox yet... working
1110 if (blackbox_hint
->flags
& AttribDecoration
) {
1111 switch (blackbox_hint
->decoration
) {
1113 // clear all decorations except close
1114 decorations
&= Decor_Close
;
1115 // clear all functions except close
1116 functions
&= Func_Close
;
1121 decorations
|= Decor_Titlebar
| Decor_Iconify
;
1122 decorations
&= ~(Decor_Border
| Decor_Handle
| Decor_Maximize
);
1123 functions
|= Func_Move
| Func_Iconify
;
1124 functions
&= ~(Func_Resize
| Func_Maximize
);
1129 decorations
|= Decor_Titlebar
;
1130 decorations
&= ~(Decor_Iconify
| Decor_Border
| Decor_Handle
);
1131 functions
|= Func_Move
;
1132 functions
&= ~(Func_Resize
| Func_Maximize
| Func_Iconify
);
1138 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Handle
|
1139 Decor_Iconify
| Decor_Maximize
;
1140 functions
|= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
1147 XFree(blackbox_hint
);
1152 void BlackboxWindow::getTransientInfo(void) {
1153 if (client
.transient_for
&&
1154 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1155 // the transient for hint was removed, so we need to tell our
1156 // previous transient_for that we are going away
1157 client
.transient_for
->client
.transientList
.remove(this);
1160 // we have no transient_for until we find a new one
1161 client
.transient_for
= 0;
1164 if (! XGetTransientForHint(blackbox
->getXDisplay(), client
.window
,
1166 // transient_for hint not set
1170 if (trans_for
== client
.window
) {
1171 // wierd client... treat this window as a normal window
1175 if (trans_for
== None
|| trans_for
== screen
->getRootWindow()) {
1176 // this is an undocumented interpretation of the ICCCM. a transient
1177 // associated with None/Root/itself is assumed to be a modal root
1178 // transient. we don't support the concept of a global transient,
1179 // so we just associate this transient with nothing, and perhaps
1180 // we will add support later for global modality.
1181 client
.transient_for
= (BlackboxWindow
*) ~0ul;
1186 client
.transient_for
= blackbox
->searchWindow(trans_for
);
1187 if (! client
.transient_for
&&
1188 client
.window_group
&& trans_for
== client
.window_group
) {
1189 // no direct transient_for, perhaps this is a group transient?
1190 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1191 if (group
) client
.transient_for
= group
->find(screen
);
1194 if (! client
.transient_for
|| client
.transient_for
== this) {
1195 // no transient_for found, or we have a wierd client that wants to be
1196 // a transient for itself, so we treat this window as a normal window
1197 client
.transient_for
= (BlackboxWindow
*) 0;
1201 // register ourselves with our new transient_for
1202 client
.transient_for
->client
.transientList
.push_back(this);
1203 flags
.stuck
= client
.transient_for
->flags
.stuck
;
1207 BlackboxWindow
*BlackboxWindow::getTransientFor(void) const {
1208 if (client
.transient_for
&&
1209 client
.transient_for
!= (BlackboxWindow
*) ~0ul)
1210 return client
.transient_for
;
1215 void BlackboxWindow::configure(int dx
, int dy
,
1216 unsigned int dw
, unsigned int dh
) {
1217 bool send_event
= (frame
.rect
.x() != dx
|| frame
.rect
.y() != dy
);
1219 if ((dw
!= frame
.rect
.width()) || (dh
!= frame
.rect
.height())) {
1220 frame
.rect
.setRect(dx
, dy
, dw
, dh
);
1221 frame
.inside_w
= frame
.rect
.width() - (frame
.border_w
* 2);
1222 frame
.inside_h
= frame
.rect
.height() - (frame
.border_w
* 2);
1224 if (frame
.rect
.right() <= 0 || frame
.rect
.bottom() <= 0)
1225 frame
.rect
.setPos(0, 0);
1227 client
.rect
.setCoords(frame
.rect
.left() + frame
.margin
.left
,
1228 frame
.rect
.top() + frame
.margin
.top
,
1229 frame
.rect
.right() - frame
.margin
.right
,
1230 frame
.rect
.bottom() - frame
.margin
.bottom
);
1233 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
1240 setFocusFlag(flags
.focused
);
1243 frame
.rect
.setPos(dx
, dy
);
1245 XMoveWindow(blackbox
->getXDisplay(), frame
.window
,
1246 frame
.rect
.x(), frame
.rect
.y());
1248 if (! flags
.moving
) send_event
= True
;
1251 if (send_event
&& ! flags
.moving
) {
1252 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1253 frame
.rect
.top() + frame
.margin
.top
);
1256 event
.type
= ConfigureNotify
;
1258 event
.xconfigure
.display
= blackbox
->getXDisplay();
1259 event
.xconfigure
.event
= client
.window
;
1260 event
.xconfigure
.window
= client
.window
;
1261 event
.xconfigure
.x
= client
.rect
.x();
1262 event
.xconfigure
.y
= client
.rect
.y();
1263 event
.xconfigure
.width
= client
.rect
.width();
1264 event
.xconfigure
.height
= client
.rect
.height();
1265 event
.xconfigure
.border_width
= client
.old_bw
;
1266 event
.xconfigure
.above
= frame
.window
;
1267 event
.xconfigure
.override_redirect
= False
;
1269 XSendEvent(blackbox
->getXDisplay(), client
.window
, True
,
1270 NoEventMask
, &event
);
1272 screen
->updateNetizenConfigNotify(&event
);
1278 void BlackboxWindow::configureShape(void) {
1279 XShapeCombineShape(blackbox
->getXDisplay(), frame
.window
, ShapeBounding
,
1280 frame
.margin
.left
- frame
.border_w
,
1281 frame
.margin
.top
- frame
.border_w
,
1282 client
.window
, ShapeBounding
, ShapeSet
);
1285 XRectangle xrect
[2];
1287 if (decorations
& Decor_Titlebar
) {
1288 xrect
[0].x
= xrect
[0].y
= -frame
.border_w
;
1289 xrect
[0].width
= frame
.rect
.width();
1290 xrect
[0].height
= frame
.title_h
+ (frame
.border_w
* 2);
1294 if (decorations
& Decor_Handle
) {
1295 xrect
[1].x
= -frame
.border_w
;
1296 xrect
[1].y
= frame
.rect
.height() - frame
.margin
.bottom
+
1297 frame
.mwm_border_w
- frame
.border_w
;
1298 xrect
[1].width
= frame
.rect
.width();
1299 xrect
[1].height
= frame
.handle_h
+ (frame
.border_w
* 2);
1303 XShapeCombineRectangles(blackbox
->getXDisplay(), frame
.window
,
1304 ShapeBounding
, 0, 0, xrect
, num
,
1305 ShapeUnion
, Unsorted
);
1310 bool BlackboxWindow::setInputFocus(void) {
1311 if (flags
.focused
) return True
;
1313 if (! client
.rect
.intersects(screen
->getRect())) {
1314 // client is outside the screen, move it to the center
1315 configure((screen
->getWidth() - frame
.rect
.width()) / 2,
1316 (screen
->getHeight() - frame
.rect
.height()) / 2,
1317 frame
.rect
.width(), frame
.rect
.height());
1320 if (client
.transientList
.size() > 0) {
1321 // transfer focus to any modal transients
1322 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1323 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1324 if ((*it
)->flags
.modal
) return (*it
)->setInputFocus();
1329 if (focus_mode
== F_LocallyActive
|| focus_mode
== F_Passive
) {
1330 XSetInputFocus(blackbox
->getXDisplay(), client
.window
,
1331 RevertToPointerRoot
, CurrentTime
);
1333 blackbox
->setFocusedWindow(this);
1335 /* we could set the focus to none, since the window doesn't accept focus,
1336 * but we shouldn't set focus to nothing since this would surely make
1342 if (flags
.send_focus_message
) {
1344 ce
.xclient
.type
= ClientMessage
;
1345 ce
.xclient
.message_type
= blackbox
->getWMProtocolsAtom();
1346 ce
.xclient
.display
= blackbox
->getXDisplay();
1347 ce
.xclient
.window
= client
.window
;
1348 ce
.xclient
.format
= 32;
1349 ce
.xclient
.data
.l
[0] = blackbox
->getWMTakeFocusAtom();
1350 ce
.xclient
.data
.l
[1] = blackbox
->getLastTime();
1351 ce
.xclient
.data
.l
[2] = 0l;
1352 ce
.xclient
.data
.l
[3] = 0l;
1353 ce
.xclient
.data
.l
[4] = 0l;
1354 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1362 void BlackboxWindow::iconify(void) {
1363 if (flags
.iconic
) return;
1365 if (windowmenu
) windowmenu
->hide();
1367 setState(IconicState
);
1370 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1371 * we need to clear the event mask on client.window for a split second.
1372 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1373 * split second, leaving us with a ghost window... so, we need to do this
1374 * while the X server is grabbed
1376 XGrabServer(blackbox
->getXDisplay());
1377 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
1378 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1379 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1380 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
1381 XUngrabServer(blackbox
->getXDisplay());
1383 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1384 flags
.visible
= False
;
1385 flags
.iconic
= True
;
1387 screen
->getWorkspace(blackbox_attrib
.workspace
)->removeWindow(this);
1389 if (isTransient()) {
1390 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1391 ! client
.transient_for
->flags
.iconic
) {
1392 // iconify our transient_for
1393 client
.transient_for
->iconify();
1397 screen
->addIcon(this);
1399 if (client
.transientList
.size() > 0) {
1400 // iconify all transients
1401 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1402 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1403 if (! (*it
)->flags
.iconic
) (*it
)->iconify();
1409 void BlackboxWindow::show(void) {
1410 setState(NormalState
);
1412 XMapWindow(blackbox
->getXDisplay(), client
.window
);
1413 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
1414 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
1416 flags
.visible
= True
;
1417 flags
.iconic
= False
;
1421 void BlackboxWindow::deiconify(bool reassoc
, bool raise
) {
1422 if (flags
.iconic
|| reassoc
)
1423 screen
->reassociateWindow(this, BSENTINEL
, False
);
1424 else if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspace()->getID())
1429 // reassociate and deiconify all transients
1430 if (reassoc
&& client
.transientList
.size() > 0) {
1431 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1432 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1433 (*it
)->deiconify(True
, False
);
1438 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1442 void BlackboxWindow::close(void) {
1444 ce
.xclient
.type
= ClientMessage
;
1445 ce
.xclient
.message_type
= blackbox
->getWMProtocolsAtom();
1446 ce
.xclient
.display
= blackbox
->getXDisplay();
1447 ce
.xclient
.window
= client
.window
;
1448 ce
.xclient
.format
= 32;
1449 ce
.xclient
.data
.l
[0] = blackbox
->getWMDeleteAtom();
1450 ce
.xclient
.data
.l
[1] = CurrentTime
;
1451 ce
.xclient
.data
.l
[2] = 0l;
1452 ce
.xclient
.data
.l
[3] = 0l;
1453 ce
.xclient
.data
.l
[4] = 0l;
1454 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
, NoEventMask
, &ce
);
1458 void BlackboxWindow::withdraw(void) {
1459 setState(current_state
);
1461 flags
.visible
= False
;
1462 flags
.iconic
= False
;
1464 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1466 XGrabServer(blackbox
->getXDisplay());
1467 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
1468 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1469 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1470 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
1471 XUngrabServer(blackbox
->getXDisplay());
1473 if (windowmenu
) windowmenu
->hide();
1477 void BlackboxWindow::maximize(unsigned int button
) {
1478 // handle case where menu is open then the max button is used instead
1479 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
1481 if (flags
.maximized
) {
1482 flags
.maximized
= 0;
1484 blackbox_attrib
.flags
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1485 blackbox_attrib
.attrib
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1488 when a resize is begun, maximize(0) is called to clear any maximization
1489 flags currently set. Otherwise it still thinks it is maximized.
1490 so we do not need to call configure() because resizing will handle it
1492 if (! flags
.resizing
)
1493 configure(blackbox_attrib
.premax_x
, blackbox_attrib
.premax_y
,
1494 blackbox_attrib
.premax_w
, blackbox_attrib
.premax_h
);
1496 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
1497 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
1500 setState(current_state
);
1504 blackbox_attrib
.premax_x
= frame
.rect
.x();
1505 blackbox_attrib
.premax_y
= frame
.rect
.y();
1506 blackbox_attrib
.premax_w
= frame
.rect
.width();
1507 // use client.rect so that clients can be restored even if shaded
1508 blackbox_attrib
.premax_h
=
1509 client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
;
1511 const Rect
&screen_area
= screen
->availableArea();
1512 frame
.changing
= screen_area
;
1517 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1518 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1522 blackbox_attrib
.flags
|= AttribMaxVert
;
1523 blackbox_attrib
.attrib
|= AttribMaxVert
;
1525 frame
.changing
.setX(frame
.rect
.x());
1526 frame
.changing
.setWidth(frame
.rect
.width());
1530 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1531 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1533 frame
.changing
.setY(frame
.rect
.y());
1534 frame
.changing
.setHeight(frame
.rect
.height());
1539 blackbox_attrib
.flags
^= AttribShaded
;
1540 blackbox_attrib
.attrib
^= AttribShaded
;
1541 flags
.shaded
= False
;
1544 flags
.maximized
= button
;
1546 configure(frame
.changing
.x(), frame
.changing
.y(),
1547 frame
.changing
.width(), frame
.changing
.height());
1549 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1551 setState(current_state
);
1555 // re-maximizes the window to take into account availableArea changes
1556 void BlackboxWindow::remaximize(void) {
1557 // save the original dimensions because maximize will wipe them out
1558 int premax_x
= blackbox_attrib
.premax_x
,
1559 premax_y
= blackbox_attrib
.premax_y
,
1560 premax_w
= blackbox_attrib
.premax_w
,
1561 premax_h
= blackbox_attrib
.premax_h
;
1563 unsigned int button
= flags
.maximized
;
1564 flags
.maximized
= 0; // trick maximize() into working
1567 // restore saved values
1568 blackbox_attrib
.premax_x
= premax_x
;
1569 blackbox_attrib
.premax_y
= premax_y
;
1570 blackbox_attrib
.premax_w
= premax_w
;
1571 blackbox_attrib
.premax_h
= premax_h
;
1575 void BlackboxWindow::setWorkspace(unsigned int n
) {
1576 blackbox_attrib
.flags
|= AttribWorkspace
;
1577 blackbox_attrib
.workspace
= n
;
1581 void BlackboxWindow::shade(void) {
1583 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1584 frame
.inside_w
, frame
.inside_h
);
1585 flags
.shaded
= False
;
1586 blackbox_attrib
.flags
^= AttribShaded
;
1587 blackbox_attrib
.attrib
^= AttribShaded
;
1589 setState(NormalState
);
1591 // set the frame rect to the normal size
1592 frame
.rect
.setHeight(client
.rect
.height() + frame
.margin
.top
+
1593 frame
.margin
.bottom
);
1595 if (! (decorations
& Decor_Titlebar
))
1598 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1599 frame
.inside_w
, frame
.title_h
);
1600 flags
.shaded
= True
;
1601 blackbox_attrib
.flags
|= AttribShaded
;
1602 blackbox_attrib
.attrib
|= AttribShaded
;
1604 setState(IconicState
);
1606 // set the frame rect to the shaded size
1607 frame
.rect
.setHeight(frame
.title_h
+ (frame
.border_w
* 2));
1612 void BlackboxWindow::stick(void) {
1614 blackbox_attrib
.flags
^= AttribOmnipresent
;
1615 blackbox_attrib
.attrib
^= AttribOmnipresent
;
1617 flags
.stuck
= False
;
1620 screen
->reassociateWindow(this, BSENTINEL
, True
);
1622 setState(current_state
);
1626 blackbox_attrib
.flags
|= AttribOmnipresent
;
1627 blackbox_attrib
.attrib
|= AttribOmnipresent
;
1629 setState(current_state
);
1634 void BlackboxWindow::setFocusFlag(bool focus
) {
1635 flags
.focused
= focus
;
1637 if (decorations
& Decor_Titlebar
) {
1638 if (flags
.focused
) {
1640 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1641 frame
.title
, frame
.ftitle
);
1643 XSetWindowBackground(blackbox
->getXDisplay(),
1644 frame
.title
, frame
.ftitle_pixel
);
1647 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1648 frame
.title
, frame
.utitle
);
1650 XSetWindowBackground(blackbox
->getXDisplay(),
1651 frame
.title
, frame
.utitle_pixel
);
1653 XClearWindow(blackbox
->getXDisplay(), frame
.title
);
1659 if (decorations
& Decor_Handle
) {
1660 if (flags
.focused
) {
1662 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1663 frame
.handle
, frame
.fhandle
);
1665 XSetWindowBackground(blackbox
->getXDisplay(),
1666 frame
.handle
, frame
.fhandle_pixel
);
1669 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1670 frame
.left_grip
, frame
.fgrip
);
1671 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1672 frame
.right_grip
, frame
.fgrip
);
1674 XSetWindowBackground(blackbox
->getXDisplay(),
1675 frame
.left_grip
, frame
.fgrip_pixel
);
1676 XSetWindowBackground(blackbox
->getXDisplay(),
1677 frame
.right_grip
, frame
.fgrip_pixel
);
1681 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1682 frame
.handle
, frame
.uhandle
);
1684 XSetWindowBackground(blackbox
->getXDisplay(),
1685 frame
.handle
, frame
.uhandle_pixel
);
1688 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1689 frame
.left_grip
, frame
.ugrip
);
1690 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1691 frame
.right_grip
, frame
.ugrip
);
1693 XSetWindowBackground(blackbox
->getXDisplay(),
1694 frame
.left_grip
, frame
.ugrip_pixel
);
1695 XSetWindowBackground(blackbox
->getXDisplay(),
1696 frame
.right_grip
, frame
.ugrip_pixel
);
1699 XClearWindow(blackbox
->getXDisplay(), frame
.handle
);
1700 XClearWindow(blackbox
->getXDisplay(), frame
.left_grip
);
1701 XClearWindow(blackbox
->getXDisplay(), frame
.right_grip
);
1704 if (decorations
& Decor_Border
) {
1706 XSetWindowBorder(blackbox
->getXDisplay(),
1707 frame
.plate
, frame
.fborder_pixel
);
1709 XSetWindowBorder(blackbox
->getXDisplay(),
1710 frame
.plate
, frame
.uborder_pixel
);
1713 if (screen
->isSloppyFocus() && screen
->doAutoRaise()) {
1714 if (isFocused()) timer
->start();
1719 blackbox
->setFocusedWindow(this);
1723 void BlackboxWindow::installColormap(bool install
) {
1724 int i
= 0, ncmap
= 0;
1725 Colormap
*cmaps
= XListInstalledColormaps(blackbox
->getXDisplay(),
1726 client
.window
, &ncmap
);
1727 XWindowAttributes wattrib
;
1729 if (XGetWindowAttributes(blackbox
->getXDisplay(),
1730 client
.window
, &wattrib
)) {
1732 // install the window's colormap
1733 for (i
= 0; i
< ncmap
; i
++) {
1734 if (*(cmaps
+ i
) == wattrib
.colormap
)
1735 // this window is using an installed color map... do not install
1738 // otherwise, install the window's colormap
1740 XInstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
1742 // uninstall the window's colormap
1743 for (i
= 0; i
< ncmap
; i
++) {
1744 if (*(cmaps
+ i
) == wattrib
.colormap
)
1745 // we found the colormap to uninstall
1746 XUninstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
1756 void BlackboxWindow::setState(unsigned long new_state
) {
1757 current_state
= new_state
;
1759 unsigned long state
[2];
1760 state
[0] = current_state
;
1762 xatom
->setValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
, state
, 2);
1764 xatom
->setValue(client
.window
, XAtom::blackbox_attributes
,
1765 XAtom::blackbox_attributes
, (unsigned long *)&blackbox_attrib
,
1766 PropBlackboxAttributesElements
);
1770 bool BlackboxWindow::getState(void) {
1775 unsigned long *state
, nitems
;
1777 if (! xatom
->getValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
, nitems
,
1781 current_state
= static_cast<unsigned long>(state
[0]);
1788 void BlackboxWindow::restoreAttributes(void) {
1789 if (! getState()) current_state
= NormalState
;
1793 unsigned long ulfoo
, nitems
;
1795 BlackboxAttributes
*net
;
1796 int ret
= XGetWindowProperty(blackbox
->getXDisplay(), client
.window
,
1797 blackbox
->getBlackboxAttributesAtom(), 0l,
1798 PropBlackboxAttributesElements
, False
,
1799 blackbox
->getBlackboxAttributesAtom(),
1800 &atom_return
, &foo
, &nitems
, &ulfoo
,
1801 (unsigned char **) &net
);
1802 if (ret
!= Success
|| ! net
|| nitems
!= PropBlackboxAttributesElements
)
1805 if (net
->flags
& AttribShaded
&&
1806 net
->attrib
& AttribShaded
) {
1808 ((current_state
== IconicState
) ? NormalState
: current_state
);
1810 flags
.shaded
= False
;
1813 current_state
= save_state
;
1816 if ((net
->workspace
!= screen
->getCurrentWorkspaceID()) &&
1817 (net
->workspace
< screen
->getWorkspaceCount())) {
1818 screen
->reassociateWindow(this, net
->workspace
, True
);
1820 if (current_state
== NormalState
) current_state
= WithdrawnState
;
1821 } else if (current_state
== WithdrawnState
) {
1822 current_state
= NormalState
;
1825 if (net
->flags
& AttribOmnipresent
&&
1826 net
->attrib
& AttribOmnipresent
) {
1827 flags
.stuck
= False
;
1830 current_state
= NormalState
;
1833 if ((net
->flags
& AttribMaxHoriz
) ||
1834 (net
->flags
& AttribMaxVert
)) {
1835 int x
= net
->premax_x
, y
= net
->premax_y
;
1836 unsigned int w
= net
->premax_w
, h
= net
->premax_h
;
1837 flags
.maximized
= 0;
1840 if ((net
->flags
& AttribMaxHoriz
) &&
1841 (net
->flags
& AttribMaxVert
))
1842 m
= (net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1843 else if (net
->flags
& AttribMaxVert
)
1844 m
= (net
->attrib
& AttribMaxVert
) ? 2 : 0;
1845 else if (net
->flags
& AttribMaxHoriz
)
1846 m
= (net
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1850 blackbox_attrib
.premax_x
= x
;
1851 blackbox_attrib
.premax_y
= y
;
1852 blackbox_attrib
.premax_w
= w
;
1853 blackbox_attrib
.premax_h
= h
;
1856 setState(current_state
);
1858 XFree((void *) net
);
1863 * Positions the frame according the the client window position and window
1866 void BlackboxWindow::setGravityOffsets(void) {
1867 // x coordinates for each gravity type
1868 const int x_west
= client
.rect
.x();
1869 const int x_east
= client
.rect
.right() - frame
.inside_w
+ 1;
1870 const int x_center
= client
.rect
.left() +
1871 ((client
.rect
.width() - frame
.rect
.width()) / 2);
1872 // y coordinates for each gravity type
1873 const int y_north
= client
.rect
.y();
1874 const int y_south
= client
.rect
.bottom() - frame
.inside_h
+ 1;
1875 const int y_center
= client
.rect
.top() +
1876 ((client
.rect
.height() - frame
.rect
.height()) / 2);
1878 switch (client
.win_gravity
) {
1880 case NorthWestGravity
: frame
.rect
.setPos(x_west
, y_north
); break;
1881 case NorthGravity
: frame
.rect
.setPos(x_center
, y_north
); break;
1882 case NorthEastGravity
: frame
.rect
.setPos(x_east
, y_north
); break;
1883 case SouthWestGravity
: frame
.rect
.setPos(x_west
, y_south
); break;
1884 case SouthGravity
: frame
.rect
.setPos(x_center
, y_south
); break;
1885 case SouthEastGravity
: frame
.rect
.setPos(x_east
, y_south
); break;
1886 case WestGravity
: frame
.rect
.setPos(x_west
, y_center
); break;
1887 case CenterGravity
: frame
.rect
.setPos(x_center
, y_center
); break;
1888 case EastGravity
: frame
.rect
.setPos(x_east
, y_center
); break;
1892 frame
.rect
.setPos(client
.rect
.x() - frame
.margin
.left
,
1893 client
.rect
.y() - frame
.margin
.top
);
1900 * The reverse of the setGravityOffsets function. Uses the frame window's
1901 * position to find the window's reference point.
1903 void BlackboxWindow::restoreGravity(void) {
1904 // x coordinates for each gravity type
1905 const int x_west
= frame
.rect
.x();
1906 const int x_east
= frame
.rect
.x() + frame
.inside_w
- client
.rect
.width();
1907 const int x_center
= frame
.rect
.x() -
1908 ((client
.rect
.width() - frame
.rect
.width()) / 2);
1909 // y coordinates for each gravity type
1910 const int y_north
= frame
.rect
.y();
1911 const int y_south
= frame
.rect
.y() + frame
.inside_h
- client
.rect
.height();
1912 const int y_center
= frame
.rect
.y() -
1913 ((client
.rect
.height() - frame
.rect
.height()) / 2);
1915 switch(client
.win_gravity
) {
1917 case NorthWestGravity
: client
.rect
.setPos(x_west
, y_north
); break;
1918 case NorthGravity
: client
.rect
.setPos(x_center
, y_north
); break;
1919 case NorthEastGravity
: client
.rect
.setPos(x_east
, y_north
); break;
1920 case SouthWestGravity
: client
.rect
.setPos(x_west
, y_south
); break;
1921 case SouthGravity
: client
.rect
.setPos(x_center
, y_south
); break;
1922 case SouthEastGravity
: client
.rect
.setPos(x_east
, y_south
); break;
1923 case WestGravity
: client
.rect
.setPos(x_west
, y_center
); break;
1924 case CenterGravity
: client
.rect
.setPos(x_center
, y_center
); break;
1925 case EastGravity
: client
.rect
.setPos(x_east
, y_center
); break;
1929 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1930 frame
.rect
.top() + frame
.margin
.top
);
1936 void BlackboxWindow::redrawLabel(void) {
1937 if (flags
.focused
) {
1939 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1940 frame
.label
, frame
.flabel
);
1942 XSetWindowBackground(blackbox
->getXDisplay(),
1943 frame
.label
, frame
.flabel_pixel
);
1946 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1947 frame
.label
, frame
.ulabel
);
1949 XSetWindowBackground(blackbox
->getXDisplay(),
1950 frame
.label
, frame
.ulabel_pixel
);
1952 XClearWindow(blackbox
->getXDisplay(), frame
.label
);
1954 WindowStyle
*style
= screen
->getWindowStyle();
1956 int pos
= frame
.bevel_w
* 2,
1957 dlen
= style
->doJustify(client
.title
.c_str(), pos
, frame
.label_w
,
1958 frame
.bevel_w
* 4, i18n
.multibyte());
1960 BPen
pen((flags
.focused
) ? style
->l_text_focus
: style
->l_text_unfocus
,
1962 if (i18n
.multibyte())
1963 XmbDrawString(blackbox
->getXDisplay(), frame
.label
, style
->fontset
,
1965 (1 - style
->fontset_extents
->max_ink_extent
.y
),
1966 client
.title
.c_str(), dlen
);
1968 XDrawString(blackbox
->getXDisplay(), frame
.label
, pen
.gc(), pos
,
1969 (style
->font
->ascent
+ 1), client
.title
.c_str(), dlen
);
1973 void BlackboxWindow::redrawAllButtons(void) {
1974 if (frame
.iconify_button
) redrawIconifyButton(False
);
1975 if (frame
.maximize_button
) redrawMaximizeButton(flags
.maximized
);
1976 if (frame
.close_button
) redrawCloseButton(False
);
1980 void BlackboxWindow::redrawIconifyButton(bool pressed
) {
1982 if (flags
.focused
) {
1984 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1985 frame
.iconify_button
, frame
.fbutton
);
1987 XSetWindowBackground(blackbox
->getXDisplay(),
1988 frame
.iconify_button
, frame
.fbutton_pixel
);
1991 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1992 frame
.iconify_button
, frame
.ubutton
);
1994 XSetWindowBackground(blackbox
->getXDisplay(), frame
.iconify_button
,
1995 frame
.ubutton_pixel
);
1999 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2000 frame
.iconify_button
, frame
.pbutton
);
2002 XSetWindowBackground(blackbox
->getXDisplay(),
2003 frame
.iconify_button
, frame
.pbutton_pixel
);
2005 XClearWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
2007 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2008 screen
->getWindowStyle()->b_pic_unfocus
);
2009 XDrawRectangle(blackbox
->getXDisplay(), frame
.iconify_button
, pen
.gc(),
2010 2, (frame
.button_w
- 5), (frame
.button_w
- 5), 2);
2014 void BlackboxWindow::redrawMaximizeButton(bool pressed
) {
2016 if (flags
.focused
) {
2018 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2019 frame
.maximize_button
, frame
.fbutton
);
2021 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2022 frame
.fbutton_pixel
);
2025 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2026 frame
.maximize_button
, frame
.ubutton
);
2028 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2029 frame
.ubutton_pixel
);
2033 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2034 frame
.maximize_button
, frame
.pbutton
);
2036 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2037 frame
.pbutton_pixel
);
2039 XClearWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
2041 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2042 screen
->getWindowStyle()->b_pic_unfocus
);
2043 XDrawRectangle(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2044 2, 2, (frame
.button_w
- 5), (frame
.button_w
- 5));
2045 XDrawLine(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2046 2, 3, (frame
.button_w
- 3), 3);
2050 void BlackboxWindow::redrawCloseButton(bool pressed
) {
2052 if (flags
.focused
) {
2054 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2057 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2058 frame
.fbutton_pixel
);
2061 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2064 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2065 frame
.ubutton_pixel
);
2069 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2070 frame
.close_button
, frame
.pbutton
);
2072 XSetWindowBackground(blackbox
->getXDisplay(),
2073 frame
.close_button
, frame
.pbutton_pixel
);
2075 XClearWindow(blackbox
->getXDisplay(), frame
.close_button
);
2077 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2078 screen
->getWindowStyle()->b_pic_unfocus
);
2079 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2080 2, 2, (frame
.button_w
- 3), (frame
.button_w
- 3));
2081 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2082 2, (frame
.button_w
- 3), (frame
.button_w
- 3), 2);
2086 void BlackboxWindow::mapRequestEvent(XMapRequestEvent
*re
) {
2087 if (re
->window
!= client
.window
)
2091 fprintf(stderr
, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2095 bool get_state_ret
= getState();
2096 if (! (get_state_ret
&& blackbox
->isStartup())) {
2097 if ((client
.wm_hint_flags
& StateHint
) &&
2098 (! (current_state
== NormalState
|| current_state
== IconicState
)))
2099 current_state
= client
.initial_state
;
2101 current_state
= NormalState
;
2102 } else if (flags
.iconic
) {
2103 current_state
= NormalState
;
2106 switch (current_state
) {
2111 case WithdrawnState
:
2120 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2121 if (! blackbox
->isStartup() && (isTransient() || screen
->doFocusNew())) {
2122 XSync(blackbox
->getXDisplay(), False
); // make sure the frame is mapped..
2130 void BlackboxWindow::unmapNotifyEvent(XUnmapEvent
*ue
) {
2131 if (ue
->window
!= client
.window
)
2135 fprintf(stderr
, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2139 screen
->unmanageWindow(this, False
);
2143 void BlackboxWindow::destroyNotifyEvent(XDestroyWindowEvent
*de
) {
2144 if (de
->window
!= client
.window
)
2148 fprintf(stderr
, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2152 screen
->unmanageWindow(this, False
);
2156 void BlackboxWindow::reparentNotifyEvent(XReparentEvent
*re
) {
2157 if (re
->window
!= client
.window
|| re
->parent
== frame
.plate
)
2161 fprintf(stderr
, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2162 "0x%lx.\n", client
.window
, re
->parent
);
2167 XPutBackEvent(blackbox
->getXDisplay(), &ev
);
2168 screen
->unmanageWindow(this, True
);
2172 void BlackboxWindow::propertyNotifyEvent(Atom atom
) {
2175 case XA_WM_CLIENT_MACHINE
:
2179 case XA_WM_TRANSIENT_FOR
: {
2180 // determine if this is a transient window
2183 // adjust the window decorations based on transience
2184 if (isTransient()) {
2185 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2186 functions
&= ~Func_Maximize
;
2197 case XA_WM_ICON_NAME
:
2199 if (flags
.iconic
) screen
->propagateWindowName(this);
2205 if (decorations
& Decor_Titlebar
)
2208 screen
->propagateWindowName(this);
2211 case XA_WM_NORMAL_HINTS
: {
2214 if ((client
.normal_hint_flags
& PMinSize
) &&
2215 (client
.normal_hint_flags
& PMaxSize
)) {
2216 if (client
.max_width
<= client
.min_width
&&
2217 client
.max_height
<= client
.min_height
) {
2218 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2219 functions
&= ~(Func_Resize
| Func_Maximize
);
2221 decorations
|= Decor_Maximize
| Decor_Handle
;
2222 functions
|= Func_Resize
| Func_Maximize
;
2226 Rect old_rect
= frame
.rect
;
2230 if (old_rect
!= frame
.rect
)
2237 if (atom
== blackbox
->getWMProtocolsAtom()) {
2240 if ((decorations
& Decor_Close
) && (! frame
.close_button
)) {
2241 createCloseButton();
2242 if (decorations
& Decor_Titlebar
) {
2243 positionButtons(True
);
2244 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
2246 if (windowmenu
) windowmenu
->reconfigure();
2255 void BlackboxWindow::exposeEvent(XExposeEvent
*ee
) {
2256 if (frame
.label
== ee
->window
&& (decorations
& Decor_Titlebar
))
2258 else if (frame
.close_button
== ee
->window
)
2259 redrawCloseButton(False
);
2260 else if (frame
.maximize_button
== ee
->window
)
2261 redrawMaximizeButton(flags
.maximized
);
2262 else if (frame
.iconify_button
== ee
->window
)
2263 redrawIconifyButton(False
);
2267 void BlackboxWindow::configureRequestEvent(XConfigureRequestEvent
*cr
) {
2268 if (cr
->window
!= client
.window
|| flags
.iconic
)
2271 int cx
= frame
.rect
.x(), cy
= frame
.rect
.y();
2272 unsigned int cw
= frame
.rect
.width(), ch
= frame
.rect
.height();
2274 if (cr
->value_mask
& CWBorderWidth
)
2275 client
.old_bw
= cr
->border_width
;
2277 if (cr
->value_mask
& CWX
)
2278 cx
= cr
->x
- frame
.margin
.left
;
2280 if (cr
->value_mask
& CWY
)
2281 cy
= cr
->y
- frame
.margin
.top
;
2283 if (cr
->value_mask
& CWWidth
)
2284 cw
= cr
->width
+ frame
.margin
.left
+ frame
.margin
.right
;
2286 if (cr
->value_mask
& CWHeight
)
2287 ch
= cr
->height
+ frame
.margin
.top
+ frame
.margin
.bottom
;
2289 if (frame
.rect
!= Rect(cx
, cy
, cw
, ch
))
2290 configure(cx
, cy
, cw
, ch
);
2292 if (cr
->value_mask
& CWStackMode
) {
2293 switch (cr
->detail
) {
2296 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2302 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2309 void BlackboxWindow::buttonPressEvent(XButtonEvent
*be
) {
2310 if (frame
.maximize_button
== be
->window
) {
2311 redrawMaximizeButton(True
);
2312 } else if (be
->button
== 1 || (be
->button
== 3 && be
->state
== Mod1Mask
)) {
2313 if (! flags
.focused
)
2316 if (frame
.iconify_button
== be
->window
) {
2317 redrawIconifyButton(True
);
2318 } else if (frame
.close_button
== be
->window
) {
2319 redrawCloseButton(True
);
2320 } else if (frame
.plate
== be
->window
) {
2321 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2323 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2325 XAllowEvents(blackbox
->getXDisplay(), ReplayPointer
, be
->time
);
2327 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
2328 if (((be
->time
- lastButtonPressTime
) <=
2329 blackbox
->getDoubleClickInterval()) ||
2330 (be
->state
& ControlMask
)) {
2331 lastButtonPressTime
= 0;
2334 lastButtonPressTime
= be
->time
;
2338 frame
.grab_x
= be
->x_root
- frame
.rect
.x() - frame
.border_w
;
2339 frame
.grab_y
= be
->y_root
- frame
.rect
.y() - frame
.border_w
;
2341 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2343 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2345 } else if (be
->button
== 2 && (be
->window
!= frame
.iconify_button
) &&
2346 (be
->window
!= frame
.close_button
)) {
2347 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2348 } else if (windowmenu
&& be
->button
== 3 &&
2349 (frame
.title
== be
->window
|| frame
.label
== be
->window
||
2350 frame
.handle
== be
->window
|| frame
.window
== be
->window
)) {
2353 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
2354 mx
= be
->x_root
- (windowmenu
->getWidth() / 2);
2355 my
= frame
.rect
.y() + frame
.title_h
+ frame
.border_w
;
2356 } else if (frame
.handle
== be
->window
) {
2357 mx
= be
->x_root
- (windowmenu
->getWidth() / 2);
2358 my
= frame
.rect
.bottom() - frame
.handle_h
- (frame
.border_w
* 3) -
2359 windowmenu
->getHeight();
2361 mx
= be
->x_root
- (windowmenu
->getWidth() / 2);
2363 if (be
->y
<= static_cast<signed>(frame
.bevel_w
))
2364 my
= frame
.rect
.y() + frame
.title_h
;
2366 my
= be
->y_root
- (windowmenu
->getHeight() / 2);
2369 // snap the window menu into a corner if necessary - we check the
2370 // position of the menu with the coordinates of the client to
2371 // make the comparisions easier.
2372 // XXX: this needs some work!
2373 if (mx
> client
.rect
.right() -
2374 static_cast<signed>(windowmenu
->getWidth()))
2375 mx
= frame
.rect
.right() - windowmenu
->getWidth() - frame
.border_w
+ 1;
2376 if (mx
< client
.rect
.left())
2377 mx
= frame
.rect
.x();
2379 if (my
> client
.rect
.bottom() -
2380 static_cast<signed>(windowmenu
->getHeight()))
2381 my
= frame
.rect
.bottom() - windowmenu
->getHeight() - frame
.border_w
+ 1;
2382 if (my
< client
.rect
.top())
2383 my
= frame
.rect
.y() + ((decorations
& Decor_Titlebar
) ?
2387 if (! windowmenu
->isVisible()) {
2388 windowmenu
->move(mx
, my
);
2390 XRaiseWindow(blackbox
->getXDisplay(), windowmenu
->getWindowID());
2391 XRaiseWindow(blackbox
->getXDisplay(),
2392 windowmenu
->getSendToMenu()->getWindowID());
2398 } else if (be
->button
== 4) {
2399 if ((be
->window
== frame
.label
||
2400 be
->window
== frame
.title
) &&
2404 } else if (be
->button
== 5) {
2405 if ((be
->window
== frame
.label
||
2406 be
->window
== frame
.title
) &&
2413 void BlackboxWindow::buttonReleaseEvent(XButtonEvent
*re
) {
2414 if (re
->window
== frame
.maximize_button
) {
2415 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2416 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2417 maximize(re
->button
);
2419 redrawMaximizeButton(flags
.maximized
);
2421 } else if (re
->window
== frame
.iconify_button
) {
2422 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2423 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2426 redrawIconifyButton(False
);
2428 } else if (re
->window
== frame
.close_button
) {
2429 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2430 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
)))
2432 redrawCloseButton(False
);
2433 } else if (flags
.moving
) {
2434 flags
.moving
= False
;
2436 if (! screen
->doOpaqueMove()) {
2437 /* when drawing the rubber band, we need to make sure we only draw inside
2438 * the frame... frame.changing_* contain the new coords for the window,
2439 * so we need to subtract 1 from changing_w/changing_h every where we
2440 * draw the rubber band (for both moving and resizing)
2442 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2443 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
2444 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
2445 XUngrabServer(blackbox
->getXDisplay());
2447 configure(frame
.changing
.x(), frame
.changing
.y(),
2448 frame
.changing
.width(), frame
.changing
.height());
2450 configure(frame
.rect
.x(), frame
.rect
.y(),
2451 frame
.rect
.width(), frame
.rect
.height());
2453 screen
->hideGeometry();
2454 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
2455 } else if (flags
.resizing
) {
2456 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2457 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
2458 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
2459 XUngrabServer(blackbox
->getXDisplay());
2461 screen
->hideGeometry();
2463 constrain((re
->window
== frame
.left_grip
) ? TopRight
: TopLeft
);
2465 // unset maximized state when resized after fully maximized
2466 if (flags
.maximized
== 1)
2468 flags
.resizing
= False
;
2469 configure(frame
.changing
.x(), frame
.changing
.y(),
2470 frame
.changing
.width(), frame
.changing
.height());
2472 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
2473 } else if (re
->window
== frame
.window
) {
2474 if (re
->button
== 2 && re
->state
== Mod1Mask
)
2475 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
2480 void BlackboxWindow::motionNotifyEvent(XMotionEvent
*me
) {
2481 if (! flags
.resizing
&& (me
->state
& Button1Mask
) &&
2482 (functions
& Func_Move
) &&
2483 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
2484 frame
.handle
== me
->window
|| frame
.window
== me
->window
)) {
2485 if (! flags
.moving
) {
2486 XGrabPointer(blackbox
->getXDisplay(), me
->window
, False
,
2487 Button1MotionMask
| ButtonReleaseMask
,
2488 GrabModeAsync
, GrabModeAsync
,
2489 None
, blackbox
->getMoveCursor(), CurrentTime
);
2491 if (windowmenu
&& windowmenu
->isVisible())
2494 flags
.moving
= True
;
2496 if (! screen
->doOpaqueMove()) {
2497 XGrabServer(blackbox
->getXDisplay());
2499 frame
.changing
= frame
.rect
;
2500 screen
->showPosition(frame
.changing
.x(), frame
.changing
.y());
2502 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2506 frame
.changing
.width() - 1,
2507 frame
.changing
.height() - 1);
2510 int dx
= me
->x_root
- frame
.grab_x
, dy
= me
->y_root
- frame
.grab_y
;
2511 dx
-= frame
.border_w
;
2512 dy
-= frame
.border_w
;
2514 const int snap_distance
= screen
->getEdgeSnapThreshold();
2516 if (snap_distance
) {
2518 const int wleft
= dx
,
2519 wright
= dx
+ frame
.rect
.width() - 1,
2521 wbottom
= dy
+ frame
.rect
.height() - 1;
2523 // Maybe this should be saved in the class, and set in the setWorkspace
2525 Workspace
*w
= screen
->getWorkspace(getWorkspaceNumber());
2528 // try snap to another window
2529 for (unsigned int i
= 0, c
= w
->getCount(); i
< c
; ++i
) {
2530 BlackboxWindow
*snapwin
= w
->getWindow(i
);
2531 if (snapwin
== this)
2532 continue; // don't snap to self
2534 const Rect
&winrect
= snapwin
->frameRect();
2535 int dleft
= std::abs(wright
- winrect
.left()),
2536 dright
= std::abs(wleft
- winrect
.right()),
2537 dtop
= std::abs(wbottom
- winrect
.top()),
2538 dbottom
= std::abs(wtop
- winrect
.bottom());
2541 if (dleft
< snap_distance
&& dleft
<= dright
) {
2542 dx
= winrect
.left() - frame
.rect
.width();
2546 else if (dright
< snap_distance
) {
2547 dx
= winrect
.right() + 1;
2552 if (dtop
< snap_distance
&& dtop
<= dbottom
) {
2553 dy
= winrect
.top() - frame
.rect
.height();
2557 else if (dbottom
< snap_distance
) {
2558 dy
= winrect
.bottom() + 1;
2563 // try snap to the screen's available area
2564 Rect srect
= screen
->availableArea();
2566 int dleft
= std::abs(wleft
- srect
.left()),
2567 dright
= std::abs(wright
- srect
.right()),
2568 dtop
= std::abs(wtop
- srect
.top()),
2569 dbottom
= std::abs(wbottom
- srect
.bottom());
2572 if (dleft
< snap_distance
&& dleft
<= dright
)
2575 else if (dright
< snap_distance
)
2576 dx
= srect
.right() - frame
.rect
.width() + 1;
2579 if (dtop
< snap_distance
&& dtop
<= dbottom
)
2582 else if (dbottom
< snap_distance
)
2583 dy
= srect
.bottom() - frame
.rect
.height() + 1;
2585 srect
= screen
->getRect(); // now get the full screen
2587 dleft
= std::abs(wleft
- srect
.left()),
2588 dright
= std::abs(wright
- srect
.right()),
2589 dtop
= std::abs(wtop
- srect
.top()),
2590 dbottom
= std::abs(wbottom
- srect
.bottom());
2593 if (dleft
< snap_distance
&& dleft
<= dright
)
2596 else if (dright
< snap_distance
)
2597 dx
= srect
.right() - frame
.rect
.width() + 1;
2600 if (dtop
< snap_distance
&& dtop
<= dbottom
)
2603 else if (dbottom
< snap_distance
)
2604 dy
= srect
.bottom() - frame
.rect
.height() + 1;
2607 if (screen
->doOpaqueMove()) {
2608 configure(dx
, dy
, frame
.rect
.width(), frame
.rect
.height());
2610 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2614 frame
.changing
.width() - 1,
2615 frame
.changing
.height() - 1);
2617 frame
.changing
.setPos(dx
, dy
);
2619 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2623 frame
.changing
.width() - 1,
2624 frame
.changing
.height() - 1);
2627 screen
->showPosition(dx
, dy
);
2629 } else if ((functions
& Func_Resize
) &&
2630 (((me
->state
& Button1Mask
) &&
2631 (me
->window
== frame
.right_grip
||
2632 me
->window
== frame
.left_grip
)) ||
2633 (me
->state
& (Mod1Mask
| Button3Mask
) &&
2634 me
->window
== frame
.window
))) {
2635 bool left
= (me
->window
== frame
.left_grip
);
2637 if (! flags
.resizing
) {
2638 XGrabServer(blackbox
->getXDisplay());
2639 XGrabPointer(blackbox
->getXDisplay(), me
->window
, False
,
2640 ButtonMotionMask
| ButtonReleaseMask
,
2641 GrabModeAsync
, GrabModeAsync
, None
,
2642 ((left
) ? blackbox
->getLowerLeftAngleCursor() :
2643 blackbox
->getLowerRightAngleCursor()),
2646 flags
.resizing
= True
;
2649 frame
.grab_x
= me
->x
;
2650 frame
.grab_y
= me
->y
;
2651 frame
.changing
= frame
.rect
;
2653 constrain((left
) ? TopRight
: TopLeft
, &gw
, &gh
);
2655 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2656 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
2657 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
2659 screen
->showGeometry(gw
, gh
);
2661 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2662 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
2663 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
2671 frame
.changing
.setCoords(me
->x_root
- frame
.grab_x
, frame
.rect
.top(),
2672 frame
.rect
.right(), frame
.rect
.bottom());
2673 frame
.changing
.setHeight(frame
.rect
.height() + (me
->y
- frame
.grab_y
));
2676 frame
.changing
.setSize(frame
.rect
.width() + (me
->x
- frame
.grab_x
),
2677 frame
.rect
.height() + (me
->y
- frame
.grab_y
));
2680 constrain(anchor
, &gw
, &gh
);
2682 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2683 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
2684 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
2686 screen
->showGeometry(gw
, gh
);
2693 void BlackboxWindow::shapeEvent(XShapeEvent
*) {
2694 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
2701 bool BlackboxWindow::validateClient(void) {
2702 XSync(blackbox
->getXDisplay(), False
);
2705 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
2706 DestroyNotify
, &e
) ||
2707 XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
2709 XPutBackEvent(blackbox
->getXDisplay(), &e
);
2718 void BlackboxWindow::restore(bool remap
) {
2719 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeDelete
);
2720 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
2721 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, NoEventMask
);
2725 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
2726 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
2728 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, client
.old_bw
);
2731 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
2732 ReparentNotify
, &ev
)) {
2735 // according to the ICCCM - if the client doesn't reparent to
2736 // root, then we have to do it for them
2737 XReparentWindow(blackbox
->getXDisplay(), client
.window
,
2738 screen
->getRootWindow(),
2739 client
.rect
.x(), client
.rect
.y());
2742 if (remap
) XMapWindow(blackbox
->getXDisplay(), client
.window
);
2746 // timer for autoraise
2747 void BlackboxWindow::timeout(void) {
2748 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2752 void BlackboxWindow::changeBlackboxHints(BlackboxHints
*net
) {
2753 if ((net
->flags
& AttribShaded
) &&
2754 ((blackbox_attrib
.attrib
& AttribShaded
) !=
2755 (net
->attrib
& AttribShaded
)))
2758 if (flags
.visible
&& // watch out for requests when we can not be seen
2759 (net
->flags
& (AttribMaxVert
| AttribMaxHoriz
)) &&
2760 ((blackbox_attrib
.attrib
& (AttribMaxVert
| AttribMaxHoriz
)) !=
2761 (net
->attrib
& (AttribMaxVert
| AttribMaxHoriz
)))) {
2762 if (flags
.maximized
) {
2767 if ((net
->flags
& AttribMaxHoriz
) && (net
->flags
& AttribMaxVert
))
2768 button
= ((net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0);
2769 else if (net
->flags
& AttribMaxVert
)
2770 button
= ((net
->attrib
& AttribMaxVert
) ? 2 : 0);
2771 else if (net
->flags
& AttribMaxHoriz
)
2772 button
= ((net
->attrib
& AttribMaxHoriz
) ? 3 : 0);
2778 if ((net
->flags
& AttribOmnipresent
) &&
2779 ((blackbox_attrib
.attrib
& AttribOmnipresent
) !=
2780 (net
->attrib
& AttribOmnipresent
)))
2783 if ((net
->flags
& AttribWorkspace
) &&
2784 (blackbox_attrib
.workspace
!= net
->workspace
)) {
2785 screen
->reassociateWindow(this, net
->workspace
, True
);
2787 if (screen
->getCurrentWorkspaceID() != net
->workspace
) {
2791 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2795 if (net
->flags
& AttribDecoration
) {
2796 switch (net
->decoration
) {
2798 // clear all decorations except close
2799 decorations
&= Decor_Close
;
2805 decorations
|= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
2806 Decor_Iconify
| Decor_Maximize
;
2811 decorations
|= Decor_Titlebar
| Decor_Iconify
;
2812 decorations
&= ~(Decor_Border
| Decor_Handle
| Decor_Maximize
);
2817 decorations
|= Decor_Titlebar
;
2818 decorations
&= ~(Decor_Iconify
| Decor_Border
| Decor_Handle
);
2819 functions
|= Func_Move
;
2824 // we can not be shaded if we lack a titlebar
2825 if (flags
.shaded
&& ! (decorations
& Decor_Titlebar
))
2829 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
2830 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
2834 setState(current_state
);
2840 * Set the sizes of all components of the window frame
2841 * (the window decorations).
2842 * These values are based upon the current style settings and the client
2843 * window's dimensions.
2845 void BlackboxWindow::upsize(void) {
2846 frame
.bevel_w
= screen
->getBevelWidth();
2848 if (decorations
& Decor_Border
) {
2849 frame
.border_w
= screen
->getBorderWidth();
2850 if (! isTransient())
2851 frame
.mwm_border_w
= screen
->getFrameWidth();
2853 frame
.mwm_border_w
= 0;
2855 frame
.mwm_border_w
= frame
.border_w
= 0;
2858 if (decorations
& Decor_Titlebar
) {
2859 // the height of the titlebar is based upon the height of the font being
2860 // used to display the window's title
2861 WindowStyle
*style
= screen
->getWindowStyle();
2862 if (i18n
.multibyte())
2863 frame
.title_h
= (style
->fontset_extents
->max_ink_extent
.height
+
2864 (frame
.bevel_w
* 2) + 2);
2866 frame
.title_h
= (style
->font
->ascent
+ style
->font
->descent
+
2867 (frame
.bevel_w
* 2) + 2);
2869 frame
.label_h
= frame
.title_h
- (frame
.bevel_w
* 2);
2870 frame
.button_w
= (frame
.label_h
- 2);
2872 // set the top frame margin
2873 frame
.margin
.top
= frame
.border_w
+ frame
.title_h
+
2874 frame
.border_w
+ frame
.mwm_border_w
;
2880 // set the top frame margin
2881 frame
.margin
.top
= frame
.border_w
+ frame
.mwm_border_w
;
2884 // set the left/right frame margin
2885 frame
.margin
.left
= frame
.margin
.right
= frame
.border_w
+ frame
.mwm_border_w
;
2887 if (decorations
& Decor_Handle
) {
2888 frame
.grip_w
= frame
.button_w
* 2;
2889 frame
.handle_h
= screen
->getHandleWidth();
2891 // set the bottom frame margin
2892 frame
.margin
.bottom
= frame
.border_w
+ frame
.handle_h
+
2893 frame
.border_w
+ frame
.mwm_border_w
;
2898 // set the bottom frame margin
2899 frame
.margin
.bottom
= frame
.border_w
+ frame
.mwm_border_w
;
2903 We first get the normal dimensions and use this to define the inside_w/h
2904 then we modify the height if shading is in effect.
2905 If the shade state is not considered then frame.rect gets reset to the
2906 normal window size on a reconfigure() call resulting in improper
2907 dimensions appearing in move/resize and other events.
2910 height
= client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
,
2911 width
= client
.rect
.width() + frame
.margin
.left
+ frame
.margin
.right
;
2913 frame
.inside_w
= width
- (frame
.border_w
* 2);
2914 frame
.inside_h
= height
- (frame
.border_w
* 2);
2917 height
= frame
.title_h
+ (frame
.border_w
* 2);
2918 frame
.rect
.setSize(width
, height
);
2923 * Calculate the size of the client window and constrain it to the
2924 * size specified by the size hints of the client window.
2926 * The logical width and height are placed into pw and ph, if they
2927 * are non-zero. Logical size refers to the users perception of
2928 * the window size (for example an xterm resizes in cells, not in pixels).
2930 * The physical geometry is placed into frame.changing_{x,y,width,height}.
2931 * Physical geometry refers to the geometry of the window in pixels.
2933 void BlackboxWindow::constrain(Corner anchor
, int *pw
, int *ph
) {
2934 // frame.changing represents the requested frame size, we need to
2935 // strip the frame margin off and constrain the client size
2936 frame
.changing
.setCoords(frame
.changing
.left() + frame
.margin
.left
,
2937 frame
.changing
.top() + frame
.margin
.top
,
2938 frame
.changing
.right() - frame
.margin
.right
,
2939 frame
.changing
.bottom() - frame
.margin
.bottom
);
2941 int dw
= frame
.changing
.width(), dh
= frame
.changing
.height(),
2942 base_width
= (client
.base_width
) ? client
.base_width
: client
.min_width
,
2943 base_height
= (client
.base_height
) ? client
.base_height
:
2947 if (dw
< static_cast<signed>(client
.min_width
)) dw
= client
.min_width
;
2948 if (dh
< static_cast<signed>(client
.min_height
)) dh
= client
.min_height
;
2949 if (dw
> static_cast<signed>(client
.max_width
)) dw
= client
.max_width
;
2950 if (dh
> static_cast<signed>(client
.max_height
)) dh
= client
.max_height
;
2953 dw
/= client
.width_inc
;
2955 dh
/= client
.height_inc
;
2960 dw
*= client
.width_inc
;
2962 dh
*= client
.height_inc
;
2965 frame
.changing
.setSize(dw
, dh
);
2967 // add the frame margin back onto frame.changing
2968 frame
.changing
.setCoords(frame
.changing
.left() - frame
.margin
.left
,
2969 frame
.changing
.top() - frame
.margin
.top
,
2970 frame
.changing
.right() + frame
.margin
.right
,
2971 frame
.changing
.bottom() + frame
.margin
.bottom
);
2973 // move frame.changing to the specified anchor
2980 int dx
= frame
.rect
.right() - frame
.changing
.right();
2981 frame
.changing
.setPos(frame
.changing
.x() + dx
, frame
.changing
.y());
2987 int WindowStyle::doJustify(const char *text
, int &start_pos
,
2988 unsigned int max_length
, unsigned int modifier
,
2989 bool multibyte
) const {
2990 size_t text_len
= strlen(text
);
2991 unsigned int length
;
2995 XRectangle ink
, logical
;
2996 XmbTextExtents(fontset
, text
, text_len
, &ink
, &logical
);
2997 length
= logical
.width
;
2999 length
= XTextWidth(font
, text
, text_len
);
3002 } while (length
> max_length
&& text_len
-- > 0);
3006 start_pos
+= max_length
- length
;
3010 start_pos
+= (max_length
- length
) / 2;
3022 BWindowGroup::BWindowGroup(Blackbox
*b
, Window _group
)
3023 : blackbox(b
), group(_group
) {
3024 XWindowAttributes wattrib
;
3025 if (! XGetWindowAttributes(blackbox
->getXDisplay(), group
, &wattrib
)) {
3026 // group window doesn't seem to exist anymore
3032 watch for destroy notify on the group window (in addition to
3033 any other events we are looking for)
3035 since some managed windows can also be window group controllers,
3036 we need to make sure that we don't clobber the event mask for the
3039 XSelectInput(blackbox
->getXDisplay(), group
,
3040 wattrib
.your_event_mask
| StructureNotifyMask
);
3042 blackbox
->saveGroupSearch(group
, this);
3046 BWindowGroup::~BWindowGroup(void) {
3047 blackbox
->removeGroupSearch(group
);
3052 BWindowGroup::find(BScreen
*screen
, bool allow_transients
) const {
3053 BlackboxWindow
*ret
= blackbox
->getFocusedWindow();
3055 // does the focus window match (or any transient_fors)?
3057 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3058 if (ret
->isTransient() && allow_transients
) break;
3059 else if (! ret
->isTransient()) break;
3062 ret
= ret
->getTransientFor();
3065 if (ret
) return ret
;
3067 // the focus window didn't match, look in the group's window list
3068 BlackboxWindowList::const_iterator it
, end
= windowList
.end();
3069 for (it
= windowList
.begin(); it
!= end
; ++it
) {
3071 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3072 if (ret
->isTransient() && allow_transients
) break;
3073 else if (! ret
->isTransient()) break;