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...
79 if (! validateClient()) {
84 // set the eventmask early in the game so that we make sure we get
85 // all the events we are interested in
86 XSetWindowAttributes attrib_set
;
87 attrib_set
.event_mask
= PropertyChangeMask
| FocusChangeMask
|
89 attrib_set
.do_not_propagate_mask
= ButtonPressMask
| ButtonReleaseMask
|
91 XChangeWindowAttributes(blackbox
->getXDisplay(), client
.window
,
92 CWEventMask
|CWDontPropagate
, &attrib_set
);
94 // fetch client size and placement
95 XWindowAttributes wattrib
;
96 if ((! XGetWindowAttributes(blackbox
->getXDisplay(),
97 client
.window
, &wattrib
)) ||
98 (! wattrib
.screen
) || wattrib
.override_redirect
) {
101 "BlackboxWindow::BlackboxWindow(): XGetWindowAttributes failed\n");
108 flags
.moving
= flags
.resizing
= flags
.shaded
= flags
.visible
=
109 flags
.iconic
= flags
.focused
= flags
.stuck
= flags
.modal
=
110 flags
.send_focus_message
= flags
.shaped
= False
;
113 blackbox_attrib
.workspace
= window_number
= BSENTINEL
;
115 blackbox_attrib
.flags
= blackbox_attrib
.attrib
= blackbox_attrib
.stack
116 = blackbox_attrib
.decoration
= 0l;
117 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
118 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
121 frame
.window
= frame
.plate
= frame
.title
= frame
.handle
= None
;
122 frame
.close_button
= frame
.iconify_button
= frame
.maximize_button
= None
;
123 frame
.right_grip
= frame
.left_grip
= None
;
125 frame
.ulabel_pixel
= frame
.flabel_pixel
= frame
.utitle_pixel
=
126 frame
.ftitle_pixel
= frame
.uhandle_pixel
= frame
.fhandle_pixel
=
127 frame
.ubutton_pixel
= frame
.fbutton_pixel
= frame
.pbutton_pixel
=
128 frame
.uborder_pixel
= frame
.fborder_pixel
= frame
.ugrip_pixel
=
129 frame
.fgrip_pixel
= 0;
130 frame
.utitle
= frame
.ftitle
= frame
.uhandle
= frame
.fhandle
= None
;
131 frame
.ulabel
= frame
.flabel
= frame
.ubutton
= frame
.fbutton
= None
;
132 frame
.pbutton
= frame
.ugrip
= frame
.fgrip
= decorations
;
134 decorations
= Decor_Titlebar
| Decor_Border
| Decor_Handle
|
135 Decor_Iconify
| Decor_Maximize
;
136 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
138 client
.wm_hint_flags
= client
.normal_hint_flags
= 0;
139 client
.transient_for
= 0;
141 // get the initial size and location of client window (relative to the
142 // _root window_). This position is the reference point used with the
143 // window's gravity to find the window's initial position.
144 client
.rect
.setRect(wattrib
.x
, wattrib
.y
, wattrib
.width
, wattrib
.height
);
145 client
.old_bw
= wattrib
.border_width
;
148 lastButtonPressTime
= 0;
150 timer
= new BTimer(blackbox
, this);
151 timer
->setTimeout(blackbox
->getAutoRaiseDelay());
153 if (! getBlackboxHints())
156 // get size, aspect, minimum/maximum size and other hints set by the
162 if (client
.initial_state
== WithdrawnState
) {
163 screen
->getSlit()->addClient(client
.window
);
168 frame
.window
= createToplevelWindow();
169 frame
.plate
= createChildWindow(frame
.window
);
170 associateClientWindow();
172 blackbox
->saveWindowSearch(frame
.window
, this);
173 blackbox
->saveWindowSearch(frame
.plate
, this);
174 blackbox
->saveWindowSearch(client
.window
, this);
176 // determine if this is a transient window
179 // adjust the window decorations based on transience and window sizes
181 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
182 functions
&= ~Func_Maximize
;
185 if ((client
.normal_hint_flags
& PMinSize
) &&
186 (client
.normal_hint_flags
& PMaxSize
) &&
187 client
.max_width
<= client
.min_width
&&
188 client
.max_height
<= client
.min_height
) {
189 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
190 functions
&= ~(Func_Resize
| Func_Maximize
);
194 bool place_window
= True
;
195 if (blackbox
->isStartup() || isTransient() ||
196 client
.normal_hint_flags
& (PPosition
|USPosition
)) {
200 if (blackbox
->isStartup() ||
201 client
.rect
.intersects(screen
->availableArea()))
202 place_window
= False
;
205 if (decorations
& Decor_Titlebar
)
208 if (decorations
& Decor_Handle
)
212 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
217 if ((! screen
->isSloppyFocus()) || screen
->doClickRaise()) {
218 // grab button 1 for changing focus/raising
219 blackbox
->grabButton(Button1
, 0, frame
.plate
, True
, ButtonPressMask
,
220 GrabModeSync
, GrabModeSync
, frame
.plate
, None
);
223 blackbox
->grabButton(Button1
, Mod1Mask
, frame
.window
, True
,
224 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
225 GrabModeAsync
, frame
.window
, blackbox
->getMoveCursor());
226 blackbox
->grabButton(Button2
, Mod1Mask
, frame
.window
, True
,
227 ButtonReleaseMask
, GrabModeAsync
, GrabModeAsync
,
229 blackbox
->grabButton(Button3
, Mod1Mask
, frame
.window
, True
,
230 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
231 GrabModeAsync
, frame
.window
,
232 blackbox
->getLowerRightAngleCursor());
237 if (decorations
& Decor_Titlebar
)
238 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
239 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
241 windowmenu
= new Windowmenu(this);
243 if (blackbox_attrib
.workspace
>= screen
->getWorkspaceCount())
244 screen
->getCurrentWorkspace()->addWindow(this, place_window
);
246 screen
->getWorkspace(blackbox_attrib
.workspace
)->
247 addWindow(this, place_window
);
249 if (! place_window
) {
250 // don't need to call configure if we are letting the workspace
252 configure(frame
.rect
.x(), frame
.rect
.y(),
253 frame
.rect
.width(), frame
.rect
.height());
257 flags
.shaded
= False
;
261 if (flags
.maximized
&& (functions
& Func_Maximize
)) {
269 BlackboxWindow::~BlackboxWindow(void) {
272 fprintf(stderr
, "BlackboxWindow::~BlackboxWindow: destroying 0x%lx\n",
276 if (! timer
) // window not managed...
279 if (flags
.moving
|| flags
.resizing
) {
280 screen
->hideGeometry();
281 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
288 if (client
.window_group
) {
289 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
290 if (group
) group
->removeWindow(this);
293 // remove ourselves from our transient_for
295 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
296 client
.transient_for
->client
.transientList
.remove(this);
298 client
.transient_for
= (BlackboxWindow
*) 0;
301 if (client
.transientList
.size() > 0) {
302 // reset transient_for for all transients
303 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
304 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
305 (*it
)->client
.transient_for
= (BlackboxWindow
*) 0;
316 blackbox
->removeWindowSearch(frame
.plate
);
317 XDestroyWindow(blackbox
->getXDisplay(), frame
.plate
);
321 blackbox
->removeWindowSearch(frame
.window
);
322 XDestroyWindow(blackbox
->getXDisplay(), frame
.window
);
325 blackbox
->removeWindowSearch(client
.window
);
330 * Creates a new top level window, with a given location, size, and border
332 * Returns: the newly created window
334 Window
BlackboxWindow::createToplevelWindow(void) {
335 XSetWindowAttributes attrib_create
;
336 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
| CWColormap
|
337 CWOverrideRedirect
| CWEventMask
;
339 attrib_create
.background_pixmap
= None
;
340 attrib_create
.colormap
= screen
->getColormap();
341 attrib_create
.override_redirect
= True
;
342 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
343 ButtonMotionMask
| EnterWindowMask
;
345 return XCreateWindow(blackbox
->getXDisplay(), screen
->getRootWindow(),
346 -1, -1, 1, 1, frame
.border_w
, screen
->getDepth(),
347 InputOutput
, screen
->getVisual(), create_mask
,
353 * Creates a child window, and optionally associates a given cursor with
356 Window
BlackboxWindow::createChildWindow(Window parent
, Cursor cursor
) {
357 XSetWindowAttributes attrib_create
;
358 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
|
361 attrib_create
.background_pixmap
= None
;
362 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
363 ButtonMotionMask
| ExposureMask
;
366 create_mask
|= CWCursor
;
367 attrib_create
.cursor
= cursor
;
370 return XCreateWindow(blackbox
->getXDisplay(), parent
, 0, 0, 1, 1, 0,
371 screen
->getDepth(), InputOutput
, screen
->getVisual(),
372 create_mask
, &attrib_create
);
376 void BlackboxWindow::associateClientWindow(void) {
377 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, 0);
381 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeInsert
);
383 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, SubstructureRedirectMask
);
385 XGrabServer(blackbox
->getXDisplay());
386 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
387 XReparentWindow(blackbox
->getXDisplay(), client
.window
, frame
.plate
, 0, 0);
388 XSelectInput(blackbox
->getXDisplay(), client
.window
,
389 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
390 XUngrabServer(blackbox
->getXDisplay());
392 XRaiseWindow(blackbox
->getXDisplay(), frame
.plate
);
393 XMapSubwindows(blackbox
->getXDisplay(), frame
.plate
);
397 if (blackbox
->hasShapeExtensions()) {
398 XShapeSelectInput(blackbox
->getXDisplay(), client
.window
,
405 XShapeQueryExtents(blackbox
->getXDisplay(), client
.window
, &shaped
,
406 &foo
, &foo
, &ufoo
, &ufoo
, &foo
, &foo
, &foo
,
408 flags
.shaped
= shaped
;
414 void BlackboxWindow::decorate(void) {
417 texture
= &(screen
->getWindowStyle()->b_focus
);
418 frame
.fbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
421 frame
.fbutton_pixel
= texture
->color().pixel();
423 texture
= &(screen
->getWindowStyle()->b_unfocus
);
424 frame
.ubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
427 frame
.ubutton_pixel
= texture
->color().pixel();
429 texture
= &(screen
->getWindowStyle()->b_pressed
);
430 frame
.pbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
433 frame
.pbutton_pixel
= texture
->color().pixel();
435 if (decorations
& Decor_Titlebar
) {
436 texture
= &(screen
->getWindowStyle()->t_focus
);
437 frame
.ftitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
440 frame
.ftitle_pixel
= texture
->color().pixel();
442 texture
= &(screen
->getWindowStyle()->t_unfocus
);
443 frame
.utitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
446 frame
.utitle_pixel
= texture
->color().pixel();
448 XSetWindowBorder(blackbox
->getXDisplay(), frame
.title
,
449 screen
->getBorderColor()->pixel());
454 if (decorations
& Decor_Border
) {
455 frame
.fborder_pixel
= screen
->getWindowStyle()->f_focus
.pixel();
456 frame
.uborder_pixel
= screen
->getWindowStyle()->f_unfocus
.pixel();
457 blackbox_attrib
.flags
|= AttribDecoration
;
458 blackbox_attrib
.decoration
= DecorNormal
;
460 blackbox_attrib
.flags
|= AttribDecoration
;
461 blackbox_attrib
.decoration
= DecorNone
;
464 if (decorations
& Decor_Handle
) {
465 texture
= &(screen
->getWindowStyle()->h_focus
);
466 frame
.fhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
469 frame
.fhandle_pixel
= texture
->color().pixel();
471 texture
= &(screen
->getWindowStyle()->h_unfocus
);
472 frame
.uhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
475 frame
.uhandle_pixel
= texture
->color().pixel();
477 texture
= &(screen
->getWindowStyle()->g_focus
);
478 frame
.fgrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.fgrip
);
480 frame
.fgrip_pixel
= texture
->color().pixel();
482 texture
= &(screen
->getWindowStyle()->g_unfocus
);
483 frame
.ugrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.ugrip
);
485 frame
.ugrip_pixel
= texture
->color().pixel();
487 XSetWindowBorder(blackbox
->getXDisplay(), frame
.handle
,
488 screen
->getBorderColor()->pixel());
489 XSetWindowBorder(blackbox
->getXDisplay(), frame
.left_grip
,
490 screen
->getBorderColor()->pixel());
491 XSetWindowBorder(blackbox
->getXDisplay(), frame
.right_grip
,
492 screen
->getBorderColor()->pixel());
495 XSetWindowBorder(blackbox
->getXDisplay(), frame
.window
,
496 screen
->getBorderColor()->pixel());
500 void BlackboxWindow::decorateLabel(void) {
503 texture
= &(screen
->getWindowStyle()->l_focus
);
504 frame
.flabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.flabel
);
506 frame
.flabel_pixel
= texture
->color().pixel();
508 texture
= &(screen
->getWindowStyle()->l_unfocus
);
509 frame
.ulabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.ulabel
);
511 frame
.ulabel_pixel
= texture
->color().pixel();
515 void BlackboxWindow::createHandle(void) {
516 frame
.handle
= createChildWindow(frame
.window
);
517 blackbox
->saveWindowSearch(frame
.handle
, this);
520 createChildWindow(frame
.handle
, blackbox
->getLowerLeftAngleCursor());
521 blackbox
->saveWindowSearch(frame
.left_grip
, this);
524 createChildWindow(frame
.handle
, blackbox
->getLowerRightAngleCursor());
525 blackbox
->saveWindowSearch(frame
.right_grip
, this);
529 void BlackboxWindow::destroyHandle(void) {
531 screen
->getImageControl()->removeImage(frame
.fhandle
);
534 screen
->getImageControl()->removeImage(frame
.uhandle
);
537 screen
->getImageControl()->removeImage(frame
.fgrip
);
540 screen
->getImageControl()->removeImage(frame
.ugrip
);
542 blackbox
->removeWindowSearch(frame
.left_grip
);
543 blackbox
->removeWindowSearch(frame
.right_grip
);
545 XDestroyWindow(blackbox
->getXDisplay(), frame
.left_grip
);
546 XDestroyWindow(blackbox
->getXDisplay(), frame
.right_grip
);
547 frame
.left_grip
= frame
.right_grip
= None
;
549 blackbox
->removeWindowSearch(frame
.handle
);
550 XDestroyWindow(blackbox
->getXDisplay(), frame
.handle
);
555 void BlackboxWindow::createTitlebar(void) {
556 frame
.title
= createChildWindow(frame
.window
);
557 frame
.label
= createChildWindow(frame
.title
);
558 blackbox
->saveWindowSearch(frame
.title
, this);
559 blackbox
->saveWindowSearch(frame
.label
, this);
561 if (decorations
& Decor_Iconify
) createIconifyButton();
562 if (decorations
& Decor_Maximize
) createMaximizeButton();
563 if (decorations
& Decor_Close
) createCloseButton();
567 void BlackboxWindow::destroyTitlebar(void) {
568 if (frame
.close_button
)
569 destroyCloseButton();
571 if (frame
.iconify_button
)
572 destroyIconifyButton();
574 if (frame
.maximize_button
)
575 destroyMaximizeButton();
578 screen
->getImageControl()->removeImage(frame
.ftitle
);
581 screen
->getImageControl()->removeImage(frame
.utitle
);
584 screen
->getImageControl()->removeImage(frame
.flabel
);
587 screen
->getImageControl()->removeImage(frame
.ulabel
);
590 screen
->getImageControl()->removeImage(frame
.fbutton
);
593 screen
->getImageControl()->removeImage(frame
.ubutton
);
596 screen
->getImageControl()->removeImage(frame
.pbutton
);
598 blackbox
->removeWindowSearch(frame
.title
);
599 blackbox
->removeWindowSearch(frame
.label
);
601 XDestroyWindow(blackbox
->getXDisplay(), frame
.label
);
602 XDestroyWindow(blackbox
->getXDisplay(), frame
.title
);
603 frame
.title
= frame
.label
= None
;
607 void BlackboxWindow::createCloseButton(void) {
608 if (frame
.title
!= None
) {
609 frame
.close_button
= createChildWindow(frame
.title
);
610 blackbox
->saveWindowSearch(frame
.close_button
, this);
615 void BlackboxWindow::destroyCloseButton(void) {
616 blackbox
->removeWindowSearch(frame
.close_button
);
617 XDestroyWindow(blackbox
->getXDisplay(), frame
.close_button
);
618 frame
.close_button
= None
;
622 void BlackboxWindow::createIconifyButton(void) {
623 if (frame
.title
!= None
) {
624 frame
.iconify_button
= createChildWindow(frame
.title
);
625 blackbox
->saveWindowSearch(frame
.iconify_button
, this);
630 void BlackboxWindow::destroyIconifyButton(void) {
631 blackbox
->removeWindowSearch(frame
.iconify_button
);
632 XDestroyWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
633 frame
.iconify_button
= None
;
637 void BlackboxWindow::createMaximizeButton(void) {
638 if (frame
.title
!= None
) {
639 frame
.maximize_button
= createChildWindow(frame
.title
);
640 blackbox
->saveWindowSearch(frame
.maximize_button
, this);
645 void BlackboxWindow::destroyMaximizeButton(void) {
646 blackbox
->removeWindowSearch(frame
.maximize_button
);
647 XDestroyWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
648 frame
.maximize_button
= None
;
652 void BlackboxWindow::positionButtons(bool redecorate_label
) {
653 string layout
= blackbox
->getTitlebarLayout();
656 bool hasclose
, hasiconify
, hasmaximize
, haslabel
;
657 hasclose
= hasiconify
= hasmaximize
= haslabel
= false;
659 string::const_iterator it
, end
;
660 for (it
= layout
.begin(), end
= layout
.end(); it
!= end
; ++it
) {
663 if (! hasclose
&& (decorations
& Decor_Close
)) {
669 if (! hasiconify
&& (decorations
& Decor_Iconify
)) {
675 if (! hasmaximize
&& (decorations
& Decor_Maximize
)) {
687 if (! hasclose
&& frame
.close_button
)
688 destroyCloseButton();
689 if (! hasiconify
&& frame
.iconify_button
)
690 destroyIconifyButton();
691 if (! hasmaximize
&& frame
.maximize_button
)
692 destroyMaximizeButton();
694 parsed
+= 'L'; // require that the label be in the layout
696 const unsigned int bsep
= frame
.bevel_w
+ 1; // separation between elements
697 const unsigned int by
= frame
.bevel_w
+ 1;
698 const unsigned int ty
= frame
.bevel_w
;
700 frame
.label_w
= frame
.inside_w
- bsep
* 2 -
701 (frame
.button_w
+ bsep
) * (parsed
.size() - 1);
703 unsigned int x
= bsep
;
704 for (it
= parsed
.begin(), end
= parsed
.end(); it
!= end
; ++it
) {
707 if (!frame
.close_button
) createCloseButton();
708 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.close_button
, x
, by
,
709 frame
.button_w
, frame
.button_w
);
710 x
+= frame
.button_w
+ bsep
;
713 if (!frame
.iconify_button
) createIconifyButton();
714 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.iconify_button
, x
, by
,
715 frame
.button_w
, frame
.button_w
);
716 x
+= frame
.button_w
+ bsep
;
719 if (!frame
.maximize_button
) createMaximizeButton();
720 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.maximize_button
, x
, by
,
721 frame
.button_w
, frame
.button_w
);
722 x
+= frame
.button_w
+ bsep
;
725 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.label
, x
, ty
,
726 frame
.label_w
, frame
.label_h
);
727 x
+= frame
.label_w
+ bsep
;
732 if (redecorate_label
) decorateLabel();
738 void BlackboxWindow::reconfigure(void) {
741 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
742 frame
.rect
.top() + frame
.margin
.top
);
747 XClearWindow(blackbox
->getXDisplay(), frame
.window
);
748 setFocusFlag(flags
.focused
);
750 configure(frame
.rect
.x(), frame
.rect
.y(),
751 frame
.rect
.width(), frame
.rect
.height());
754 windowmenu
->move(windowmenu
->getX(), frame
.rect
.y() + frame
.title_h
);
755 windowmenu
->reconfigure();
760 void BlackboxWindow::updateFocusModel(void) {
761 if ((! screen
->isSloppyFocus()) || screen
->doClickRaise()) {
762 // grab button 1 for changing focus/raising
763 blackbox
->grabButton(Button1
, 0, frame
.plate
, True
, ButtonPressMask
,
764 GrabModeSync
, GrabModeSync
, None
, None
);
766 blackbox
->ungrabButton(Button1
, 0, frame
.plate
);
771 void BlackboxWindow::positionWindows(void) {
772 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.window
,
773 frame
.rect
.x(), frame
.rect
.y(), frame
.inside_w
,
774 (flags
.shaded
) ? frame
.title_h
: frame
.inside_h
);
775 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.window
, frame
.border_w
);
776 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.plate
,
778 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.plate
,
779 frame
.margin
.left
- frame
.mwm_border_w
- frame
.border_w
,
780 frame
.margin
.top
- frame
.mwm_border_w
- frame
.border_w
,
781 client
.rect
.width(), client
.rect
.height());
782 XMoveResizeWindow(blackbox
->getXDisplay(), client
.window
,
783 0, 0, client
.rect
.width(), client
.rect
.height());
785 if (decorations
& Decor_Titlebar
) {
786 if (frame
.title
== None
) createTitlebar();
788 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.title
,
790 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.title
, -frame
.border_w
,
791 -frame
.border_w
, frame
.inside_w
, frame
.title_h
);
794 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
795 XMapWindow(blackbox
->getXDisplay(), frame
.title
);
796 } else if (frame
.title
) {
799 if (decorations
& Decor_Handle
) {
800 if (frame
.handle
== None
) createHandle();
801 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.handle
,
803 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.left_grip
,
805 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.right_grip
,
808 // use client.rect here so the value is correct even if shaded
809 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.handle
,
811 client
.rect
.height() + frame
.margin
.top
+
812 frame
.mwm_border_w
- frame
.border_w
,
813 frame
.inside_w
, frame
.handle_h
);
814 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.left_grip
,
815 -frame
.border_w
, -frame
.border_w
,
816 frame
.grip_w
, frame
.handle_h
);
817 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.right_grip
,
818 frame
.inside_w
- frame
.grip_w
- frame
.border_w
,
819 -frame
.border_w
, frame
.grip_w
, frame
.handle_h
);
821 XMapSubwindows(blackbox
->getXDisplay(), frame
.handle
);
822 XMapWindow(blackbox
->getXDisplay(), frame
.handle
);
823 } else if (frame
.handle
) {
829 void BlackboxWindow::getWMName(void) {
830 XTextProperty text_prop
;
832 if (XGetWMName(blackbox
->getXDisplay(), client
.window
, &text_prop
)) {
833 client
.title
= textPropertyToString(blackbox
->getXDisplay(), text_prop
);
834 if (client
.title
.empty())
835 client
.title
= i18n(WindowSet
, WindowUnnamed
, "Unnamed");
836 XFree((char *) text_prop
.value
);
838 client
.title
= i18n(WindowSet
, WindowUnnamed
, "Unnamed");
843 void BlackboxWindow::getWMIconName(void) {
844 XTextProperty text_prop
;
846 if (XGetWMIconName(blackbox
->getXDisplay(), client
.window
, &text_prop
)) {
848 textPropertyToString(blackbox
->getXDisplay(), text_prop
);
849 if (client
.icon_title
.empty())
850 client
.icon_title
= client
.title
;
851 XFree((char *) text_prop
.value
);
853 client
.icon_title
= client
.title
;
859 * Retrieve which WM Protocols are supported by the client window.
860 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
861 * window's decorations and allow the close behavior.
862 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
865 void BlackboxWindow::getWMProtocols(void) {
869 if (XGetWMProtocols(blackbox
->getXDisplay(), client
.window
,
870 &proto
, &num_return
)) {
871 for (int i
= 0; i
< num_return
; ++i
) {
872 if (proto
[i
] == blackbox
->getWMDeleteAtom()) {
873 decorations
|= Decor_Close
;
874 functions
|= Func_Close
;
875 } else if (proto
[i
] == blackbox
->getWMTakeFocusAtom())
876 flags
.send_focus_message
= True
;
877 else if (proto
[i
] == blackbox
->getBlackboxStructureMessagesAtom())
878 screen
->addNetizen(new Netizen(screen
, client
.window
));
887 * Gets the value of the WM_HINTS property.
888 * If the property is not set, then use a set of default values.
890 void BlackboxWindow::getWMHints(void) {
891 focus_mode
= F_Passive
;
892 client
.initial_state
= NormalState
;
894 // remove from current window group
895 if (client
.window_group
) {
896 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
897 if (group
) group
->removeWindow(this);
899 client
.window_group
= None
;
901 XWMHints
*wmhint
= XGetWMHints(blackbox
->getXDisplay(), client
.window
);
906 if (wmhint
->flags
& InputHint
) {
907 if (wmhint
->input
== True
) {
908 if (flags
.send_focus_message
)
909 focus_mode
= F_LocallyActive
;
911 if (flags
.send_focus_message
)
912 focus_mode
= F_GloballyActive
;
914 focus_mode
= F_NoInput
;
918 if (wmhint
->flags
& StateHint
)
919 client
.initial_state
= wmhint
->initial_state
;
921 if (wmhint
->flags
& WindowGroupHint
) {
922 client
.window_group
= wmhint
->window_group
;
924 // add window to the appropriate group
925 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
926 if (! group
) // no group found, create it!
927 group
= new BWindowGroup(blackbox
, client
.window_group
);
928 group
->addWindow(this);
931 client
.wm_hint_flags
= wmhint
->flags
;
937 * Gets the value of the WM_NORMAL_HINTS property.
938 * If the property is not set, then use a set of default values.
940 void BlackboxWindow::getWMNormalHints(void) {
944 client
.min_width
= client
.min_height
=
945 client
.width_inc
= client
.height_inc
= 1;
946 client
.base_width
= client
.base_height
= 0;
949 use the full screen, not the strut modified size. otherwise when the
950 availableArea changes max_width/height will be incorrect and lead to odd
953 const Rect
& screen_area
= screen
->getRect();
954 client
.max_width
= screen_area
.width();
956 client
.max_height
= screen_area
.height();
957 client
.min_aspect_x
= client
.min_aspect_y
=
958 client
.max_aspect_x
= client
.max_aspect_y
= 1;
959 client
.win_gravity
= NorthWestGravity
;
961 if (! XGetWMNormalHints(blackbox
->getXDisplay(), client
.window
,
962 &sizehint
, &icccm_mask
))
965 client
.normal_hint_flags
= sizehint
.flags
;
967 if (sizehint
.flags
& PMinSize
) {
968 client
.min_width
= sizehint
.min_width
;
969 client
.min_height
= sizehint
.min_height
;
972 if (sizehint
.flags
& PMaxSize
) {
973 client
.max_width
= sizehint
.max_width
;
974 client
.max_height
= sizehint
.max_height
;
977 if (sizehint
.flags
& PResizeInc
) {
978 client
.width_inc
= sizehint
.width_inc
;
979 client
.height_inc
= sizehint
.height_inc
;
982 if (sizehint
.flags
& PAspect
) {
983 client
.min_aspect_x
= sizehint
.min_aspect
.x
;
984 client
.min_aspect_y
= sizehint
.min_aspect
.y
;
985 client
.max_aspect_x
= sizehint
.max_aspect
.x
;
986 client
.max_aspect_y
= sizehint
.max_aspect
.y
;
989 if (sizehint
.flags
& PBaseSize
) {
990 client
.base_width
= sizehint
.base_width
;
991 client
.base_height
= sizehint
.base_height
;
994 if (sizehint
.flags
& PWinGravity
)
995 client
.win_gravity
= sizehint
.win_gravity
;
1000 * Gets the MWM hints for the class' contained window.
1001 * This is used while initializing the window to its first state, and not
1003 * Returns: true if the MWM hints are successfully retreived and applied;
1004 * false if they are not.
1006 void BlackboxWindow::getMWMHints(void) {
1009 unsigned long num
, len
;
1010 MwmHints
*mwm_hint
= 0;
1012 int ret
= XGetWindowProperty(blackbox
->getXDisplay(), client
.window
,
1013 blackbox
->getMotifWMHintsAtom(), 0,
1014 PropMwmHintsElements
, False
,
1015 blackbox
->getMotifWMHintsAtom(), &atom_return
,
1016 &format
, &num
, &len
,
1017 (unsigned char **) &mwm_hint
);
1019 if (ret
!= Success
|| ! mwm_hint
|| num
!= PropMwmHintsElements
)
1022 if (mwm_hint
->flags
& MwmHintsDecorations
) {
1023 if (mwm_hint
->decorations
& MwmDecorAll
) {
1024 decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
1025 Decor_Iconify
| Decor_Maximize
| Decor_Close
;
1029 if (mwm_hint
->decorations
& MwmDecorBorder
)
1030 decorations
|= Decor_Border
;
1031 if (mwm_hint
->decorations
& MwmDecorHandle
)
1032 decorations
|= Decor_Handle
;
1033 if (mwm_hint
->decorations
& MwmDecorTitle
)
1034 decorations
|= Decor_Titlebar
;
1035 if (mwm_hint
->decorations
& MwmDecorIconify
)
1036 decorations
|= Decor_Iconify
;
1037 if (mwm_hint
->decorations
& MwmDecorMaximize
)
1038 decorations
|= Decor_Maximize
;
1042 if (mwm_hint
->flags
& MwmHintsFunctions
) {
1043 if (mwm_hint
->functions
& MwmFuncAll
) {
1044 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
|
1049 if (mwm_hint
->functions
& MwmFuncResize
)
1050 functions
|= Func_Resize
;
1051 if (mwm_hint
->functions
& MwmFuncMove
)
1052 functions
|= Func_Move
;
1053 if (mwm_hint
->functions
& MwmFuncIconify
)
1054 functions
|= Func_Iconify
;
1055 if (mwm_hint
->functions
& MwmFuncMaximize
)
1056 functions
|= Func_Maximize
;
1057 if (mwm_hint
->functions
& MwmFuncClose
)
1058 functions
|= Func_Close
;
1066 * Gets the blackbox hints from the class' contained window.
1067 * This is used while initializing the window to its first state, and not
1069 * Returns: true if the hints are successfully retreived and applied; false if
1072 bool BlackboxWindow::getBlackboxHints(void) {
1075 unsigned long num
, len
;
1076 BlackboxHints
*blackbox_hint
= 0;
1078 int ret
= XGetWindowProperty(blackbox
->getXDisplay(), client
.window
,
1079 blackbox
->getBlackboxHintsAtom(), 0,
1080 PropBlackboxHintsElements
, False
,
1081 blackbox
->getBlackboxHintsAtom(), &atom_return
,
1082 &format
, &num
, &len
,
1083 (unsigned char **) &blackbox_hint
);
1084 if (ret
!= Success
|| ! blackbox_hint
|| num
!= PropBlackboxHintsElements
)
1087 if (blackbox_hint
->flags
& AttribShaded
)
1088 flags
.shaded
= (blackbox_hint
->attrib
& AttribShaded
);
1090 if ((blackbox_hint
->flags
& AttribMaxHoriz
) &&
1091 (blackbox_hint
->flags
& AttribMaxVert
))
1092 flags
.maximized
= (blackbox_hint
->attrib
&
1093 (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1094 else if (blackbox_hint
->flags
& AttribMaxVert
)
1095 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxVert
) ? 2 : 0;
1096 else if (blackbox_hint
->flags
& AttribMaxHoriz
)
1097 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1099 if (blackbox_hint
->flags
& AttribOmnipresent
)
1100 flags
.stuck
= (blackbox_hint
->attrib
& AttribOmnipresent
);
1102 if (blackbox_hint
->flags
& AttribWorkspace
)
1103 blackbox_attrib
.workspace
= blackbox_hint
->workspace
;
1105 // if (blackbox_hint->flags & AttribStack)
1106 // don't yet have always on top/bottom for blackbox yet... working
1109 if (blackbox_hint
->flags
& AttribDecoration
) {
1110 switch (blackbox_hint
->decoration
) {
1112 // clear all decorations except close
1113 decorations
&= Decor_Close
;
1114 // clear all functions except close
1115 functions
&= Func_Close
;
1120 decorations
|= Decor_Titlebar
| Decor_Iconify
;
1121 decorations
&= ~(Decor_Border
| Decor_Handle
| Decor_Maximize
);
1122 functions
|= Func_Move
| Func_Iconify
;
1123 functions
&= ~(Func_Resize
| Func_Maximize
);
1128 decorations
|= Decor_Titlebar
;
1129 decorations
&= ~(Decor_Iconify
| Decor_Border
| Decor_Handle
);
1130 functions
|= Func_Move
;
1131 functions
&= ~(Func_Resize
| Func_Maximize
| Func_Iconify
);
1137 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Handle
|
1138 Decor_Iconify
| Decor_Maximize
;
1139 functions
|= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
1146 XFree(blackbox_hint
);
1151 void BlackboxWindow::getTransientInfo(void) {
1152 if (client
.transient_for
&&
1153 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1154 // the transient for hint was removed, so we need to tell our
1155 // previous transient_for that we are going away
1156 client
.transient_for
->client
.transientList
.remove(this);
1159 // we have no transient_for until we find a new one
1160 client
.transient_for
= 0;
1163 if (! XGetTransientForHint(blackbox
->getXDisplay(), client
.window
,
1165 // transient_for hint not set
1169 if (trans_for
== client
.window
) {
1170 // wierd client... treat this window as a normal window
1174 if (trans_for
== None
|| trans_for
== screen
->getRootWindow()) {
1175 // this is an undocumented interpretation of the ICCCM. a transient
1176 // associated with None/Root/itself is assumed to be a modal root
1177 // transient. we don't support the concept of a global transient,
1178 // so we just associate this transient with nothing, and perhaps
1179 // we will add support later for global modality.
1180 client
.transient_for
= (BlackboxWindow
*) ~0ul;
1185 client
.transient_for
= blackbox
->searchWindow(trans_for
);
1186 if (! client
.transient_for
&&
1187 client
.window_group
&& trans_for
== client
.window_group
) {
1188 // no direct transient_for, perhaps this is a group transient?
1189 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1190 if (group
) client
.transient_for
= group
->find(screen
);
1193 if (! client
.transient_for
|| client
.transient_for
== this) {
1194 // no transient_for found, or we have a wierd client that wants to be
1195 // a transient for itself, so we treat this window as a normal window
1196 client
.transient_for
= (BlackboxWindow
*) 0;
1200 // register ourselves with our new transient_for
1201 client
.transient_for
->client
.transientList
.push_back(this);
1202 flags
.stuck
= client
.transient_for
->flags
.stuck
;
1206 BlackboxWindow
*BlackboxWindow::getTransientFor(void) const {
1207 if (client
.transient_for
&&
1208 client
.transient_for
!= (BlackboxWindow
*) ~0ul)
1209 return client
.transient_for
;
1214 void BlackboxWindow::configure(int dx
, int dy
,
1215 unsigned int dw
, unsigned int dh
) {
1216 bool send_event
= (frame
.rect
.x() != dx
|| frame
.rect
.y() != dy
);
1218 if ((dw
!= frame
.rect
.width()) || (dh
!= frame
.rect
.height())) {
1219 frame
.rect
.setRect(dx
, dy
, dw
, dh
);
1220 frame
.inside_w
= frame
.rect
.width() - (frame
.border_w
* 2);
1221 frame
.inside_h
= frame
.rect
.height() - (frame
.border_w
* 2);
1223 if (frame
.rect
.right() <= 0 || frame
.rect
.bottom() <= 0)
1224 frame
.rect
.setPos(0, 0);
1226 client
.rect
.setCoords(frame
.rect
.left() + frame
.margin
.left
,
1227 frame
.rect
.top() + frame
.margin
.top
,
1228 frame
.rect
.right() - frame
.margin
.right
,
1229 frame
.rect
.bottom() - frame
.margin
.bottom
);
1232 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
1239 setFocusFlag(flags
.focused
);
1242 frame
.rect
.setPos(dx
, dy
);
1244 XMoveWindow(blackbox
->getXDisplay(), frame
.window
,
1245 frame
.rect
.x(), frame
.rect
.y());
1247 if (! flags
.moving
) send_event
= True
;
1250 if (send_event
&& ! flags
.moving
) {
1251 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1252 frame
.rect
.top() + frame
.margin
.top
);
1255 event
.type
= ConfigureNotify
;
1257 event
.xconfigure
.display
= blackbox
->getXDisplay();
1258 event
.xconfigure
.event
= client
.window
;
1259 event
.xconfigure
.window
= client
.window
;
1260 event
.xconfigure
.x
= client
.rect
.x();
1261 event
.xconfigure
.y
= client
.rect
.y();
1262 event
.xconfigure
.width
= client
.rect
.width();
1263 event
.xconfigure
.height
= client
.rect
.height();
1264 event
.xconfigure
.border_width
= client
.old_bw
;
1265 event
.xconfigure
.above
= frame
.window
;
1266 event
.xconfigure
.override_redirect
= False
;
1268 XSendEvent(blackbox
->getXDisplay(), client
.window
, True
,
1269 NoEventMask
, &event
);
1271 screen
->updateNetizenConfigNotify(&event
);
1277 void BlackboxWindow::configureShape(void) {
1278 XShapeCombineShape(blackbox
->getXDisplay(), frame
.window
, ShapeBounding
,
1279 frame
.margin
.left
- frame
.border_w
,
1280 frame
.margin
.top
- frame
.border_w
,
1281 client
.window
, ShapeBounding
, ShapeSet
);
1284 XRectangle xrect
[2];
1286 if (decorations
& Decor_Titlebar
) {
1287 xrect
[0].x
= xrect
[0].y
= -frame
.border_w
;
1288 xrect
[0].width
= frame
.rect
.width();
1289 xrect
[0].height
= frame
.title_h
+ (frame
.border_w
* 2);
1293 if (decorations
& Decor_Handle
) {
1294 xrect
[1].x
= -frame
.border_w
;
1295 xrect
[1].y
= frame
.rect
.height() - frame
.margin
.bottom
+
1296 frame
.mwm_border_w
- frame
.border_w
;
1297 xrect
[1].width
= frame
.rect
.width();
1298 xrect
[1].height
= frame
.handle_h
+ (frame
.border_w
* 2);
1302 XShapeCombineRectangles(blackbox
->getXDisplay(), frame
.window
,
1303 ShapeBounding
, 0, 0, xrect
, num
,
1304 ShapeUnion
, Unsorted
);
1309 bool BlackboxWindow::setInputFocus(void) {
1310 if (flags
.focused
) return True
;
1312 if (! client
.rect
.intersects(screen
->getRect())) {
1313 // client is outside the screen, move it to the center
1314 configure((screen
->getWidth() - frame
.rect
.width()) / 2,
1315 (screen
->getHeight() - frame
.rect
.height()) / 2,
1316 frame
.rect
.width(), frame
.rect
.height());
1319 if (client
.transientList
.size() > 0) {
1320 // transfer focus to any modal transients
1321 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1322 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1323 if ((*it
)->flags
.modal
) return (*it
)->setInputFocus();
1328 if (focus_mode
== F_LocallyActive
|| focus_mode
== F_Passive
) {
1329 XSetInputFocus(blackbox
->getXDisplay(), client
.window
,
1330 RevertToPointerRoot
, CurrentTime
);
1332 blackbox
->setFocusedWindow(this);
1334 /* we could set the focus to none, since the window doesn't accept focus,
1335 * but we shouldn't set focus to nothing since this would surely make
1341 if (flags
.send_focus_message
) {
1343 ce
.xclient
.type
= ClientMessage
;
1344 ce
.xclient
.message_type
= blackbox
->getWMProtocolsAtom();
1345 ce
.xclient
.display
= blackbox
->getXDisplay();
1346 ce
.xclient
.window
= client
.window
;
1347 ce
.xclient
.format
= 32;
1348 ce
.xclient
.data
.l
[0] = blackbox
->getWMTakeFocusAtom();
1349 ce
.xclient
.data
.l
[1] = blackbox
->getLastTime();
1350 ce
.xclient
.data
.l
[2] = 0l;
1351 ce
.xclient
.data
.l
[3] = 0l;
1352 ce
.xclient
.data
.l
[4] = 0l;
1353 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1361 void BlackboxWindow::iconify(void) {
1362 if (flags
.iconic
) return;
1364 if (windowmenu
) windowmenu
->hide();
1366 setState(IconicState
);
1369 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1370 * we need to clear the event mask on client.window for a split second.
1371 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1372 * split second, leaving us with a ghost window... so, we need to do this
1373 * while the X server is grabbed
1375 XGrabServer(blackbox
->getXDisplay());
1376 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
1377 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1378 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1379 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
1380 XUngrabServer(blackbox
->getXDisplay());
1382 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1383 flags
.visible
= False
;
1384 flags
.iconic
= True
;
1386 screen
->getWorkspace(blackbox_attrib
.workspace
)->removeWindow(this);
1388 if (isTransient()) {
1389 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1390 ! client
.transient_for
->flags
.iconic
) {
1391 // iconify our transient_for
1392 client
.transient_for
->iconify();
1396 screen
->addIcon(this);
1398 if (client
.transientList
.size() > 0) {
1399 // iconify all transients
1400 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1401 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1402 if (! (*it
)->flags
.iconic
) (*it
)->iconify();
1408 void BlackboxWindow::show(void) {
1409 setState(NormalState
);
1411 XMapWindow(blackbox
->getXDisplay(), client
.window
);
1412 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
1413 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
1415 flags
.visible
= True
;
1416 flags
.iconic
= False
;
1420 void BlackboxWindow::deiconify(bool reassoc
, bool raise
) {
1421 if (flags
.iconic
|| reassoc
)
1422 screen
->reassociateWindow(this, BSENTINEL
, False
);
1423 else if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspace()->getID())
1428 // reassociate and deiconify all transients
1429 if (reassoc
&& client
.transientList
.size() > 0) {
1430 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1431 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1432 (*it
)->deiconify(True
, False
);
1437 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1441 void BlackboxWindow::close(void) {
1443 ce
.xclient
.type
= ClientMessage
;
1444 ce
.xclient
.message_type
= blackbox
->getWMProtocolsAtom();
1445 ce
.xclient
.display
= blackbox
->getXDisplay();
1446 ce
.xclient
.window
= client
.window
;
1447 ce
.xclient
.format
= 32;
1448 ce
.xclient
.data
.l
[0] = blackbox
->getWMDeleteAtom();
1449 ce
.xclient
.data
.l
[1] = CurrentTime
;
1450 ce
.xclient
.data
.l
[2] = 0l;
1451 ce
.xclient
.data
.l
[3] = 0l;
1452 ce
.xclient
.data
.l
[4] = 0l;
1453 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
, NoEventMask
, &ce
);
1457 void BlackboxWindow::withdraw(void) {
1458 setState(current_state
);
1460 flags
.visible
= False
;
1461 flags
.iconic
= False
;
1463 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1465 XGrabServer(blackbox
->getXDisplay());
1466 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
1467 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1468 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1469 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
1470 XUngrabServer(blackbox
->getXDisplay());
1472 if (windowmenu
) windowmenu
->hide();
1476 void BlackboxWindow::maximize(unsigned int button
) {
1477 // handle case where menu is open then the max button is used instead
1478 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
1480 if (flags
.maximized
) {
1481 flags
.maximized
= 0;
1483 blackbox_attrib
.flags
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1484 blackbox_attrib
.attrib
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1487 when a resize is begun, maximize(0) is called to clear any maximization
1488 flags currently set. Otherwise it still thinks it is maximized.
1489 so we do not need to call configure() because resizing will handle it
1491 if (! flags
.resizing
)
1492 configure(blackbox_attrib
.premax_x
, blackbox_attrib
.premax_y
,
1493 blackbox_attrib
.premax_w
, blackbox_attrib
.premax_h
);
1495 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
1496 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
1499 setState(current_state
);
1503 blackbox_attrib
.premax_x
= frame
.rect
.x();
1504 blackbox_attrib
.premax_y
= frame
.rect
.y();
1505 blackbox_attrib
.premax_w
= frame
.rect
.width();
1506 // use client.rect so that clients can be restored even if shaded
1507 blackbox_attrib
.premax_h
=
1508 client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
;
1510 const Rect
&screen_area
= screen
->availableArea();
1511 frame
.changing
= screen_area
;
1516 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1517 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1521 blackbox_attrib
.flags
|= AttribMaxVert
;
1522 blackbox_attrib
.attrib
|= AttribMaxVert
;
1524 frame
.changing
.setX(frame
.rect
.x());
1525 frame
.changing
.setWidth(frame
.rect
.width());
1529 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1530 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1532 frame
.changing
.setY(frame
.rect
.y());
1533 frame
.changing
.setHeight(frame
.rect
.height());
1538 blackbox_attrib
.flags
^= AttribShaded
;
1539 blackbox_attrib
.attrib
^= AttribShaded
;
1540 flags
.shaded
= False
;
1543 flags
.maximized
= button
;
1545 configure(frame
.changing
.x(), frame
.changing
.y(),
1546 frame
.changing
.width(), frame
.changing
.height());
1548 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1550 setState(current_state
);
1554 // re-maximizes the window to take into account availableArea changes
1555 void BlackboxWindow::remaximize(void) {
1556 // save the original dimensions because maximize will wipe them out
1557 int premax_x
= blackbox_attrib
.premax_x
,
1558 premax_y
= blackbox_attrib
.premax_y
,
1559 premax_w
= blackbox_attrib
.premax_w
,
1560 premax_h
= blackbox_attrib
.premax_h
;
1562 unsigned int button
= flags
.maximized
;
1563 flags
.maximized
= 0; // trick maximize() into working
1566 // restore saved values
1567 blackbox_attrib
.premax_x
= premax_x
;
1568 blackbox_attrib
.premax_y
= premax_y
;
1569 blackbox_attrib
.premax_w
= premax_w
;
1570 blackbox_attrib
.premax_h
= premax_h
;
1574 void BlackboxWindow::setWorkspace(unsigned int n
) {
1575 blackbox_attrib
.flags
|= AttribWorkspace
;
1576 blackbox_attrib
.workspace
= n
;
1580 void BlackboxWindow::shade(void) {
1582 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1583 frame
.inside_w
, frame
.inside_h
);
1584 flags
.shaded
= False
;
1585 blackbox_attrib
.flags
^= AttribShaded
;
1586 blackbox_attrib
.attrib
^= AttribShaded
;
1588 setState(NormalState
);
1590 // set the frame rect to the normal size
1591 frame
.rect
.setHeight(client
.rect
.height() + frame
.margin
.top
+
1592 frame
.margin
.bottom
);
1594 if (! (decorations
& Decor_Titlebar
))
1597 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1598 frame
.inside_w
, frame
.title_h
);
1599 flags
.shaded
= True
;
1600 blackbox_attrib
.flags
|= AttribShaded
;
1601 blackbox_attrib
.attrib
|= AttribShaded
;
1603 setState(IconicState
);
1605 // set the frame rect to the shaded size
1606 frame
.rect
.setHeight(frame
.title_h
+ (frame
.border_w
* 2));
1611 void BlackboxWindow::stick(void) {
1613 blackbox_attrib
.flags
^= AttribOmnipresent
;
1614 blackbox_attrib
.attrib
^= AttribOmnipresent
;
1616 flags
.stuck
= False
;
1619 screen
->reassociateWindow(this, BSENTINEL
, True
);
1621 setState(current_state
);
1625 blackbox_attrib
.flags
|= AttribOmnipresent
;
1626 blackbox_attrib
.attrib
|= AttribOmnipresent
;
1628 setState(current_state
);
1633 void BlackboxWindow::setFocusFlag(bool focus
) {
1634 flags
.focused
= focus
;
1636 if (decorations
& Decor_Titlebar
) {
1637 if (flags
.focused
) {
1639 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1640 frame
.title
, frame
.ftitle
);
1642 XSetWindowBackground(blackbox
->getXDisplay(),
1643 frame
.title
, frame
.ftitle_pixel
);
1646 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1647 frame
.title
, frame
.utitle
);
1649 XSetWindowBackground(blackbox
->getXDisplay(),
1650 frame
.title
, frame
.utitle_pixel
);
1652 XClearWindow(blackbox
->getXDisplay(), frame
.title
);
1658 if (decorations
& Decor_Handle
) {
1659 if (flags
.focused
) {
1661 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1662 frame
.handle
, frame
.fhandle
);
1664 XSetWindowBackground(blackbox
->getXDisplay(),
1665 frame
.handle
, frame
.fhandle_pixel
);
1668 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1669 frame
.left_grip
, frame
.fgrip
);
1670 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1671 frame
.right_grip
, frame
.fgrip
);
1673 XSetWindowBackground(blackbox
->getXDisplay(),
1674 frame
.left_grip
, frame
.fgrip_pixel
);
1675 XSetWindowBackground(blackbox
->getXDisplay(),
1676 frame
.right_grip
, frame
.fgrip_pixel
);
1680 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1681 frame
.handle
, frame
.uhandle
);
1683 XSetWindowBackground(blackbox
->getXDisplay(),
1684 frame
.handle
, frame
.uhandle_pixel
);
1687 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1688 frame
.left_grip
, frame
.ugrip
);
1689 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1690 frame
.right_grip
, frame
.ugrip
);
1692 XSetWindowBackground(blackbox
->getXDisplay(),
1693 frame
.left_grip
, frame
.ugrip_pixel
);
1694 XSetWindowBackground(blackbox
->getXDisplay(),
1695 frame
.right_grip
, frame
.ugrip_pixel
);
1698 XClearWindow(blackbox
->getXDisplay(), frame
.handle
);
1699 XClearWindow(blackbox
->getXDisplay(), frame
.left_grip
);
1700 XClearWindow(blackbox
->getXDisplay(), frame
.right_grip
);
1703 if (decorations
& Decor_Border
) {
1705 XSetWindowBorder(blackbox
->getXDisplay(),
1706 frame
.plate
, frame
.fborder_pixel
);
1708 XSetWindowBorder(blackbox
->getXDisplay(),
1709 frame
.plate
, frame
.uborder_pixel
);
1712 if (screen
->isSloppyFocus() && screen
->doAutoRaise()) {
1713 if (isFocused()) timer
->start();
1718 blackbox
->setFocusedWindow(this);
1722 void BlackboxWindow::installColormap(bool install
) {
1723 int i
= 0, ncmap
= 0;
1724 Colormap
*cmaps
= XListInstalledColormaps(blackbox
->getXDisplay(),
1725 client
.window
, &ncmap
);
1726 XWindowAttributes wattrib
;
1728 if (XGetWindowAttributes(blackbox
->getXDisplay(),
1729 client
.window
, &wattrib
)) {
1731 // install the window's colormap
1732 for (i
= 0; i
< ncmap
; i
++) {
1733 if (*(cmaps
+ i
) == wattrib
.colormap
)
1734 // this window is using an installed color map... do not install
1737 // otherwise, install the window's colormap
1739 XInstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
1741 // uninstall the window's colormap
1742 for (i
= 0; i
< ncmap
; i
++) {
1743 if (*(cmaps
+ i
) == wattrib
.colormap
)
1744 // we found the colormap to uninstall
1745 XUninstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
1755 void BlackboxWindow::setState(unsigned long new_state
) {
1756 current_state
= new_state
;
1758 unsigned long state
[2];
1759 state
[0] = current_state
;
1761 XChangeProperty(blackbox
->getXDisplay(), client
.window
,
1762 blackbox
->getWMStateAtom(), blackbox
->getWMStateAtom(), 32,
1763 PropModeReplace
, (unsigned char *) state
, 2);
1765 XChangeProperty(blackbox
->getXDisplay(), client
.window
,
1766 blackbox
->getBlackboxAttributesAtom(),
1767 blackbox
->getBlackboxAttributesAtom(), 32, PropModeReplace
,
1768 (unsigned char *) &blackbox_attrib
,
1769 PropBlackboxAttributesElements
);
1773 bool BlackboxWindow::getState(void) {
1779 unsigned long *state
, ulfoo
, nitems
;
1781 if ((XGetWindowProperty(blackbox
->getXDisplay(), client
.window
,
1782 blackbox
->getWMStateAtom(),
1783 0l, 2l, False
, blackbox
->getWMStateAtom(),
1784 &atom_return
, &foo
, &nitems
, &ulfoo
,
1785 (unsigned char **) &state
) != Success
) ||
1791 current_state
= static_cast<unsigned long>(state
[0]);
1796 XFree((void *) state
);
1802 void BlackboxWindow::restoreAttributes(void) {
1803 if (! getState()) current_state
= NormalState
;
1807 unsigned long ulfoo
, nitems
;
1809 BlackboxAttributes
*net
;
1810 int ret
= XGetWindowProperty(blackbox
->getXDisplay(), client
.window
,
1811 blackbox
->getBlackboxAttributesAtom(), 0l,
1812 PropBlackboxAttributesElements
, False
,
1813 blackbox
->getBlackboxAttributesAtom(),
1814 &atom_return
, &foo
, &nitems
, &ulfoo
,
1815 (unsigned char **) &net
);
1816 if (ret
!= Success
|| ! net
|| nitems
!= PropBlackboxAttributesElements
)
1819 if (net
->flags
& AttribShaded
&&
1820 net
->attrib
& AttribShaded
) {
1822 ((current_state
== IconicState
) ? NormalState
: current_state
);
1824 flags
.shaded
= False
;
1827 current_state
= save_state
;
1830 if ((net
->workspace
!= screen
->getCurrentWorkspaceID()) &&
1831 (net
->workspace
< screen
->getWorkspaceCount())) {
1832 screen
->reassociateWindow(this, net
->workspace
, True
);
1834 if (current_state
== NormalState
) current_state
= WithdrawnState
;
1835 } else if (current_state
== WithdrawnState
) {
1836 current_state
= NormalState
;
1839 if (net
->flags
& AttribOmnipresent
&&
1840 net
->attrib
& AttribOmnipresent
) {
1841 flags
.stuck
= False
;
1844 current_state
= NormalState
;
1847 if ((net
->flags
& AttribMaxHoriz
) ||
1848 (net
->flags
& AttribMaxVert
)) {
1849 int x
= net
->premax_x
, y
= net
->premax_y
;
1850 unsigned int w
= net
->premax_w
, h
= net
->premax_h
;
1851 flags
.maximized
= 0;
1854 if ((net
->flags
& AttribMaxHoriz
) &&
1855 (net
->flags
& AttribMaxVert
))
1856 m
= (net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1857 else if (net
->flags
& AttribMaxVert
)
1858 m
= (net
->attrib
& AttribMaxVert
) ? 2 : 0;
1859 else if (net
->flags
& AttribMaxHoriz
)
1860 m
= (net
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1864 blackbox_attrib
.premax_x
= x
;
1865 blackbox_attrib
.premax_y
= y
;
1866 blackbox_attrib
.premax_w
= w
;
1867 blackbox_attrib
.premax_h
= h
;
1870 setState(current_state
);
1872 XFree((void *) net
);
1877 * Positions the frame according the the client window position and window
1880 void BlackboxWindow::setGravityOffsets(void) {
1881 // x coordinates for each gravity type
1882 const int x_west
= client
.rect
.x();
1883 const int x_east
= client
.rect
.right() - frame
.inside_w
+ 1;
1884 const int x_center
= client
.rect
.right() - (frame
.rect
.width()/2) + 1;
1885 // y coordinates for each gravity type
1886 const int y_north
= client
.rect
.y();
1887 const int y_south
= client
.rect
.bottom() - frame
.inside_h
+ 1;
1888 const int y_center
= client
.rect
.bottom() - (frame
.rect
.height()/2) + 1;
1890 switch (client
.win_gravity
) {
1892 case NorthWestGravity
: frame
.rect
.setPos(x_west
, y_north
); break;
1893 case NorthGravity
: frame
.rect
.setPos(x_center
, y_north
); break;
1894 case NorthEastGravity
: frame
.rect
.setPos(x_east
, y_north
); break;
1895 case SouthWestGravity
: frame
.rect
.setPos(x_west
, y_south
); break;
1896 case SouthGravity
: frame
.rect
.setPos(x_center
, y_south
); break;
1897 case SouthEastGravity
: frame
.rect
.setPos(x_east
, y_south
); break;
1898 case WestGravity
: frame
.rect
.setPos(x_west
, y_center
); break;
1899 case CenterGravity
: frame
.rect
.setPos(x_center
, y_center
); break;
1900 case EastGravity
: frame
.rect
.setPos(x_east
, y_center
); break;
1904 frame
.rect
.setPos(client
.rect
.x() - frame
.margin
.left
,
1905 client
.rect
.y() - frame
.margin
.top
);
1912 * The reverse of the setGravityOffsets function. Uses the frame window's
1913 * position to find the window's reference point.
1915 void BlackboxWindow::restoreGravity(void) {
1916 // x coordinates for each gravity type
1917 const int x_west
= frame
.rect
.x();
1918 const int x_east
= frame
.rect
.x() + frame
.inside_w
- client
.rect
.width();
1919 const int x_center
= frame
.rect
.x() + (frame
.rect
.width()/2) -
1920 client
.rect
.width();
1921 // y coordinates for each gravity type
1922 const int y_north
= frame
.rect
.y();
1923 const int y_south
= frame
.rect
.y() + frame
.inside_h
- client
.rect
.height();
1924 const int y_center
= frame
.rect
.y() + (frame
.rect
.height()/2) -
1925 client
.rect
.height();
1927 switch(client
.win_gravity
) {
1929 case NorthWestGravity
: client
.rect
.setPos(x_west
, y_north
); break;
1930 case NorthGravity
: client
.rect
.setPos(x_center
, y_north
); break;
1931 case NorthEastGravity
: client
.rect
.setPos(x_east
, y_north
); break;
1932 case SouthWestGravity
: client
.rect
.setPos(x_west
, y_south
); break;
1933 case SouthGravity
: client
.rect
.setPos(x_center
, y_south
); break;
1934 case SouthEastGravity
: client
.rect
.setPos(x_east
, y_south
); break;
1935 case WestGravity
: client
.rect
.setPos(x_west
, y_center
); break;
1936 case CenterGravity
: client
.rect
.setPos(x_center
, y_center
); break;
1937 case EastGravity
: client
.rect
.setPos(x_east
, y_center
); break;
1941 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1942 frame
.rect
.top() + frame
.margin
.top
);
1948 void BlackboxWindow::redrawLabel(void) {
1949 if (flags
.focused
) {
1951 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1952 frame
.label
, frame
.flabel
);
1954 XSetWindowBackground(blackbox
->getXDisplay(),
1955 frame
.label
, frame
.flabel_pixel
);
1958 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1959 frame
.label
, frame
.ulabel
);
1961 XSetWindowBackground(blackbox
->getXDisplay(),
1962 frame
.label
, frame
.ulabel_pixel
);
1964 XClearWindow(blackbox
->getXDisplay(), frame
.label
);
1966 WindowStyle
*style
= screen
->getWindowStyle();
1968 int pos
= frame
.bevel_w
* 2,
1969 dlen
= style
->doJustify(client
.title
.c_str(), pos
, frame
.label_w
,
1970 frame
.bevel_w
* 4, i18n
.multibyte());
1972 BPen
pen((flags
.focused
) ? style
->l_text_focus
: style
->l_text_unfocus
,
1974 if (i18n
.multibyte())
1975 XmbDrawString(blackbox
->getXDisplay(), frame
.label
, style
->fontset
,
1977 (1 - style
->fontset_extents
->max_ink_extent
.y
),
1978 client
.title
.c_str(), dlen
);
1980 XDrawString(blackbox
->getXDisplay(), frame
.label
, pen
.gc(), pos
,
1981 (style
->font
->ascent
+ 1), client
.title
.c_str(), dlen
);
1985 void BlackboxWindow::redrawAllButtons(void) {
1986 if (frame
.iconify_button
) redrawIconifyButton(False
);
1987 if (frame
.maximize_button
) redrawMaximizeButton(flags
.maximized
);
1988 if (frame
.close_button
) redrawCloseButton(False
);
1992 void BlackboxWindow::redrawIconifyButton(bool pressed
) {
1994 if (flags
.focused
) {
1996 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1997 frame
.iconify_button
, frame
.fbutton
);
1999 XSetWindowBackground(blackbox
->getXDisplay(),
2000 frame
.iconify_button
, frame
.fbutton_pixel
);
2003 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2004 frame
.iconify_button
, frame
.ubutton
);
2006 XSetWindowBackground(blackbox
->getXDisplay(), frame
.iconify_button
,
2007 frame
.ubutton_pixel
);
2011 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2012 frame
.iconify_button
, frame
.pbutton
);
2014 XSetWindowBackground(blackbox
->getXDisplay(),
2015 frame
.iconify_button
, frame
.pbutton_pixel
);
2017 XClearWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
2019 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2020 screen
->getWindowStyle()->b_pic_unfocus
);
2021 XDrawRectangle(blackbox
->getXDisplay(), frame
.iconify_button
, pen
.gc(),
2022 2, (frame
.button_w
- 5), (frame
.button_w
- 5), 2);
2026 void BlackboxWindow::redrawMaximizeButton(bool pressed
) {
2028 if (flags
.focused
) {
2030 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2031 frame
.maximize_button
, frame
.fbutton
);
2033 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2034 frame
.fbutton_pixel
);
2037 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2038 frame
.maximize_button
, frame
.ubutton
);
2040 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2041 frame
.ubutton_pixel
);
2045 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2046 frame
.maximize_button
, frame
.pbutton
);
2048 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2049 frame
.pbutton_pixel
);
2051 XClearWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
2053 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2054 screen
->getWindowStyle()->b_pic_unfocus
);
2055 XDrawRectangle(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2056 2, 2, (frame
.button_w
- 5), (frame
.button_w
- 5));
2057 XDrawLine(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2058 2, 3, (frame
.button_w
- 3), 3);
2062 void BlackboxWindow::redrawCloseButton(bool pressed
) {
2064 if (flags
.focused
) {
2066 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2069 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2070 frame
.fbutton_pixel
);
2073 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2076 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2077 frame
.ubutton_pixel
);
2081 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2082 frame
.close_button
, frame
.pbutton
);
2084 XSetWindowBackground(blackbox
->getXDisplay(),
2085 frame
.close_button
, frame
.pbutton_pixel
);
2087 XClearWindow(blackbox
->getXDisplay(), frame
.close_button
);
2089 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2090 screen
->getWindowStyle()->b_pic_unfocus
);
2091 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2092 2, 2, (frame
.button_w
- 3), (frame
.button_w
- 3));
2093 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2094 2, (frame
.button_w
- 3), (frame
.button_w
- 3), 2);
2098 void BlackboxWindow::mapRequestEvent(XMapRequestEvent
*re
) {
2099 if (re
->window
!= client
.window
)
2103 fprintf(stderr
, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2107 bool get_state_ret
= getState();
2108 if (! (get_state_ret
&& blackbox
->isStartup())) {
2109 if ((client
.wm_hint_flags
& StateHint
) &&
2110 (! (current_state
== NormalState
|| current_state
== IconicState
)))
2111 current_state
= client
.initial_state
;
2113 current_state
= NormalState
;
2114 } else if (flags
.iconic
) {
2115 current_state
= NormalState
;
2118 switch (current_state
) {
2123 case WithdrawnState
:
2132 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2133 if (! blackbox
->isStartup() && (isTransient() || screen
->doFocusNew())) {
2134 XSync(blackbox
->getXDisplay(), False
); // make sure the frame is mapped..
2142 void BlackboxWindow::unmapNotifyEvent(XUnmapEvent
*ue
) {
2143 if (ue
->window
!= client
.window
)
2147 fprintf(stderr
, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2151 screen
->unmanageWindow(this, False
);
2155 void BlackboxWindow::destroyNotifyEvent(XDestroyWindowEvent
*de
) {
2156 if (de
->window
!= client
.window
)
2160 fprintf(stderr
, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2164 screen
->unmanageWindow(this, False
);
2168 void BlackboxWindow::reparentNotifyEvent(XReparentEvent
*re
) {
2169 if (re
->window
!= client
.window
|| re
->parent
== frame
.plate
)
2173 fprintf(stderr
, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2174 "0x%lx.\n", client
.window
, re
->parent
);
2179 XPutBackEvent(blackbox
->getXDisplay(), &ev
);
2180 screen
->unmanageWindow(this, True
);
2184 void BlackboxWindow::propertyNotifyEvent(Atom atom
) {
2187 case XA_WM_CLIENT_MACHINE
:
2191 case XA_WM_TRANSIENT_FOR
: {
2192 // determine if this is a transient window
2195 // adjust the window decorations based on transience
2196 if (isTransient()) {
2197 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2198 functions
&= ~Func_Maximize
;
2209 case XA_WM_ICON_NAME
:
2211 if (flags
.iconic
) screen
->propagateWindowName(this);
2217 if (decorations
& Decor_Titlebar
)
2220 screen
->propagateWindowName(this);
2223 case XA_WM_NORMAL_HINTS
: {
2226 if ((client
.normal_hint_flags
& PMinSize
) &&
2227 (client
.normal_hint_flags
& PMaxSize
)) {
2228 if (client
.max_width
<= client
.min_width
&&
2229 client
.max_height
<= client
.min_height
) {
2230 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2231 functions
&= ~(Func_Resize
| Func_Maximize
);
2233 decorations
|= Decor_Maximize
| Decor_Handle
;
2234 functions
|= Func_Resize
| Func_Maximize
;
2238 Rect old_rect
= frame
.rect
;
2242 if (old_rect
!= frame
.rect
)
2249 if (atom
== blackbox
->getWMProtocolsAtom()) {
2252 if ((decorations
& Decor_Close
) && (! frame
.close_button
)) {
2253 createCloseButton();
2254 if (decorations
& Decor_Titlebar
) {
2255 positionButtons(True
);
2256 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
2258 if (windowmenu
) windowmenu
->reconfigure();
2267 void BlackboxWindow::exposeEvent(XExposeEvent
*ee
) {
2268 if (frame
.label
== ee
->window
&& (decorations
& Decor_Titlebar
))
2270 else if (frame
.close_button
== ee
->window
)
2271 redrawCloseButton(False
);
2272 else if (frame
.maximize_button
== ee
->window
)
2273 redrawMaximizeButton(flags
.maximized
);
2274 else if (frame
.iconify_button
== ee
->window
)
2275 redrawIconifyButton(False
);
2279 void BlackboxWindow::configureRequestEvent(XConfigureRequestEvent
*cr
) {
2280 if (cr
->window
!= client
.window
|| flags
.iconic
)
2283 int cx
= frame
.rect
.x(), cy
= frame
.rect
.y();
2284 unsigned int cw
= frame
.rect
.width(), ch
= frame
.rect
.height();
2286 if (cr
->value_mask
& CWBorderWidth
)
2287 client
.old_bw
= cr
->border_width
;
2289 if (cr
->value_mask
& CWX
)
2290 cx
= cr
->x
- frame
.margin
.left
;
2292 if (cr
->value_mask
& CWY
)
2293 cy
= cr
->y
- frame
.margin
.top
;
2295 if (cr
->value_mask
& CWWidth
)
2296 cw
= cr
->width
+ frame
.margin
.left
+ frame
.margin
.right
;
2298 if (cr
->value_mask
& CWHeight
)
2299 ch
= cr
->height
+ frame
.margin
.top
+ frame
.margin
.bottom
;
2301 if (frame
.rect
!= Rect(cx
, cy
, cw
, ch
))
2302 configure(cx
, cy
, cw
, ch
);
2304 if (cr
->value_mask
& CWStackMode
) {
2305 switch (cr
->detail
) {
2308 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2314 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2321 void BlackboxWindow::buttonPressEvent(XButtonEvent
*be
) {
2322 if (frame
.maximize_button
== be
->window
) {
2323 redrawMaximizeButton(True
);
2324 } else if (be
->button
== 1 || (be
->button
== 3 && be
->state
== Mod1Mask
)) {
2325 if (! flags
.focused
)
2328 if (frame
.iconify_button
== be
->window
) {
2329 redrawIconifyButton(True
);
2330 } else if (frame
.close_button
== be
->window
) {
2331 redrawCloseButton(True
);
2332 } else if (frame
.plate
== be
->window
) {
2333 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2335 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2337 XAllowEvents(blackbox
->getXDisplay(), ReplayPointer
, be
->time
);
2339 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
2340 if (((be
->time
- lastButtonPressTime
) <=
2341 blackbox
->getDoubleClickInterval()) ||
2342 (be
->state
& ControlMask
)) {
2343 lastButtonPressTime
= 0;
2346 lastButtonPressTime
= be
->time
;
2350 frame
.grab_x
= be
->x_root
- frame
.rect
.x() - frame
.border_w
;
2351 frame
.grab_y
= be
->y_root
- frame
.rect
.y() - frame
.border_w
;
2353 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2355 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2357 } else if (be
->button
== 2 && (be
->window
!= frame
.iconify_button
) &&
2358 (be
->window
!= frame
.close_button
)) {
2359 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2360 } else if (windowmenu
&& be
->button
== 3 &&
2361 (frame
.title
== be
->window
|| frame
.label
== be
->window
||
2362 frame
.handle
== be
->window
|| frame
.window
== be
->window
)) {
2365 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
2366 mx
= be
->x_root
- (windowmenu
->getWidth() / 2);
2367 my
= frame
.rect
.y() + frame
.title_h
+ frame
.border_w
;
2368 } else if (frame
.handle
== be
->window
) {
2369 mx
= be
->x_root
- (windowmenu
->getWidth() / 2);
2370 my
= frame
.rect
.bottom() - frame
.handle_h
- (frame
.border_w
* 3) -
2371 windowmenu
->getHeight();
2373 mx
= be
->x_root
- (windowmenu
->getWidth() / 2);
2375 if (be
->y
<= static_cast<signed>(frame
.bevel_w
))
2376 my
= frame
.rect
.y() + frame
.title_h
;
2378 my
= be
->y_root
- (windowmenu
->getHeight() / 2);
2381 // snap the window menu into a corner if necessary - we check the
2382 // position of the menu with the coordinates of the client to
2383 // make the comparisions easier.
2384 // ### this needs some work!
2385 if (mx
> client
.rect
.right() -
2386 static_cast<signed>(windowmenu
->getWidth()))
2387 mx
= frame
.rect
.right() - windowmenu
->getWidth() - frame
.border_w
+ 1;
2388 if (mx
< client
.rect
.left())
2389 mx
= frame
.rect
.x();
2391 if (my
> client
.rect
.bottom() -
2392 static_cast<signed>(windowmenu
->getHeight()))
2393 my
= frame
.rect
.bottom() - windowmenu
->getHeight() - frame
.border_w
+ 1;
2394 if (my
< client
.rect
.top())
2395 my
= frame
.rect
.y() + ((decorations
& Decor_Titlebar
) ?
2399 if (! windowmenu
->isVisible()) {
2400 windowmenu
->move(mx
, my
);
2402 XRaiseWindow(blackbox
->getXDisplay(), windowmenu
->getWindowID());
2403 XRaiseWindow(blackbox
->getXDisplay(),
2404 windowmenu
->getSendToMenu()->getWindowID());
2410 } else if (be
->button
== 4) {
2411 if ((be
->window
== frame
.label
||
2412 be
->window
== frame
.title
) &&
2416 } else if (be
->button
== 5) {
2417 if ((be
->window
== frame
.label
||
2418 be
->window
== frame
.title
) &&
2425 void BlackboxWindow::buttonReleaseEvent(XButtonEvent
*re
) {
2426 if (re
->window
== frame
.maximize_button
) {
2427 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2428 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2429 maximize(re
->button
);
2431 redrawMaximizeButton(flags
.maximized
);
2433 } else if (re
->window
== frame
.iconify_button
) {
2434 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2435 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2438 redrawIconifyButton(False
);
2440 } else if (re
->window
== frame
.close_button
) {
2441 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2442 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
)))
2444 redrawCloseButton(False
);
2445 } else if (flags
.moving
) {
2446 flags
.moving
= False
;
2448 if (! screen
->doOpaqueMove()) {
2449 /* when drawing the rubber band, we need to make sure we only draw inside
2450 * the frame... frame.changing_* contain the new coords for the window,
2451 * so we need to subtract 1 from changing_w/changing_h every where we
2452 * draw the rubber band (for both moving and resizing)
2454 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2455 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
2456 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
2457 XUngrabServer(blackbox
->getXDisplay());
2459 configure(frame
.changing
.x(), frame
.changing
.y(),
2460 frame
.changing
.width(), frame
.changing
.height());
2462 configure(frame
.rect
.x(), frame
.rect
.y(),
2463 frame
.rect
.width(), frame
.rect
.height());
2465 screen
->hideGeometry();
2466 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
2467 } else if (flags
.resizing
) {
2468 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2469 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
2470 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
2471 XUngrabServer(blackbox
->getXDisplay());
2473 screen
->hideGeometry();
2475 constrain((re
->window
== frame
.left_grip
) ? TopRight
: TopLeft
);
2477 // unset maximized state when resized after fully maximized
2478 if (flags
.maximized
== 1)
2480 flags
.resizing
= False
;
2481 configure(frame
.changing
.x(), frame
.changing
.y(),
2482 frame
.changing
.width(), frame
.changing
.height());
2484 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
2485 } else if (re
->window
== frame
.window
) {
2486 if (re
->button
== 2 && re
->state
== Mod1Mask
)
2487 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
2492 void BlackboxWindow::motionNotifyEvent(XMotionEvent
*me
) {
2493 if (! flags
.resizing
&& (me
->state
& Button1Mask
) &&
2494 (functions
& Func_Move
) &&
2495 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
2496 frame
.handle
== me
->window
|| frame
.window
== me
->window
)) {
2497 if (! flags
.moving
) {
2498 XGrabPointer(blackbox
->getXDisplay(), me
->window
, False
,
2499 Button1MotionMask
| ButtonReleaseMask
,
2500 GrabModeAsync
, GrabModeAsync
,
2501 None
, blackbox
->getMoveCursor(), CurrentTime
);
2503 if (windowmenu
&& windowmenu
->isVisible())
2506 flags
.moving
= True
;
2508 if (! screen
->doOpaqueMove()) {
2509 XGrabServer(blackbox
->getXDisplay());
2511 frame
.changing
= frame
.rect
;
2512 screen
->showPosition(frame
.changing
.x(), frame
.changing
.y());
2514 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2518 frame
.changing
.width() - 1,
2519 frame
.changing
.height() - 1);
2522 int dx
= me
->x_root
- frame
.grab_x
, dy
= me
->y_root
- frame
.grab_y
;
2523 dx
-= frame
.border_w
;
2524 dy
-= frame
.border_w
;
2526 const int snap_distance
= screen
->getEdgeSnapThreshold();
2528 if (snap_distance
) {
2530 const int wleft
= dx
,
2531 wright
= dx
+ frame
.rect
.width() - 1,
2533 wbottom
= dy
+ frame
.rect
.height() - 1;
2535 // Maybe this should be saved in the class, and set in the setWorkspace
2537 Workspace
*w
= screen
->getWorkspace(getWorkspaceNumber());
2540 // try snap to another window
2541 for (unsigned int i
= 0, c
= w
->getCount(); i
< c
; ++i
) {
2542 BlackboxWindow
*snapwin
= w
->getWindow(i
);
2543 if (snapwin
== this)
2544 continue; // don't snap to self
2546 const Rect
&winrect
= snapwin
->frameRect();
2547 int dleft
= std::abs(wright
- winrect
.left()),
2548 dright
= std::abs(wleft
- winrect
.right()),
2549 dtop
= std::abs(wbottom
- winrect
.top()),
2550 dbottom
= std::abs(wtop
- winrect
.bottom());
2553 if (dleft
< snap_distance
&& dleft
<= dright
) {
2554 dx
= winrect
.left() - frame
.rect
.width();
2558 else if (dright
< snap_distance
) {
2559 dx
= winrect
.right() + 1;
2564 if (dtop
< snap_distance
&& dtop
<= dbottom
) {
2565 dy
= winrect
.top() - frame
.rect
.height();
2569 else if (dbottom
< snap_distance
) {
2570 dy
= winrect
.bottom() + 1;
2575 // try snap to the screen's available area
2576 Rect srect
= screen
->availableArea();
2578 int dleft
= std::abs(wleft
- srect
.left()),
2579 dright
= std::abs(wright
- srect
.right()),
2580 dtop
= std::abs(wtop
- srect
.top()),
2581 dbottom
= std::abs(wbottom
- srect
.bottom());
2584 if (dleft
< snap_distance
&& dleft
<= dright
)
2587 else if (dright
< snap_distance
)
2588 dx
= srect
.right() - frame
.rect
.width() + 1;
2591 if (dtop
< snap_distance
&& dtop
<= dbottom
)
2594 else if (dbottom
< snap_distance
)
2595 dy
= srect
.bottom() - frame
.rect
.height() + 1;
2597 srect
= screen
->getRect(); // now get the full screen
2599 dleft
= std::abs(wleft
- srect
.left()),
2600 dright
= std::abs(wright
- srect
.right()),
2601 dtop
= std::abs(wtop
- srect
.top()),
2602 dbottom
= std::abs(wbottom
- srect
.bottom());
2605 if (dleft
< snap_distance
&& dleft
<= dright
)
2608 else if (dright
< snap_distance
)
2609 dx
= srect
.right() - frame
.rect
.width() + 1;
2612 if (dtop
< snap_distance
&& dtop
<= dbottom
)
2615 else if (dbottom
< snap_distance
)
2616 dy
= srect
.bottom() - frame
.rect
.height() + 1;
2619 if (screen
->doOpaqueMove()) {
2620 configure(dx
, dy
, frame
.rect
.width(), frame
.rect
.height());
2622 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2626 frame
.changing
.width() - 1,
2627 frame
.changing
.height() - 1);
2629 frame
.changing
.setPos(dx
, dy
);
2631 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2635 frame
.changing
.width() - 1,
2636 frame
.changing
.height() - 1);
2639 screen
->showPosition(dx
, dy
);
2641 } else if ((functions
& Func_Resize
) &&
2642 (((me
->state
& Button1Mask
) &&
2643 (me
->window
== frame
.right_grip
||
2644 me
->window
== frame
.left_grip
)) ||
2645 (me
->state
& (Mod1Mask
| Button3Mask
) &&
2646 me
->window
== frame
.window
))) {
2647 bool left
= (me
->window
== frame
.left_grip
);
2649 if (! flags
.resizing
) {
2650 XGrabServer(blackbox
->getXDisplay());
2651 XGrabPointer(blackbox
->getXDisplay(), me
->window
, False
,
2652 ButtonMotionMask
| ButtonReleaseMask
,
2653 GrabModeAsync
, GrabModeAsync
, None
,
2654 ((left
) ? blackbox
->getLowerLeftAngleCursor() :
2655 blackbox
->getLowerRightAngleCursor()),
2658 flags
.resizing
= True
;
2661 frame
.grab_x
= me
->x
;
2662 frame
.grab_y
= me
->y
;
2663 frame
.changing
= frame
.rect
;
2665 constrain((left
) ? TopRight
: TopLeft
, &gw
, &gh
);
2667 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2668 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
2669 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
2671 screen
->showGeometry(gw
, gh
);
2673 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2674 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
2675 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
2683 frame
.changing
.setCoords(me
->x_root
- frame
.grab_x
, frame
.rect
.top(),
2684 frame
.rect
.right(), frame
.rect
.bottom());
2685 frame
.changing
.setHeight(frame
.rect
.height() + (me
->y
- frame
.grab_y
));
2688 frame
.changing
.setSize(frame
.rect
.width() + (me
->x
- frame
.grab_x
),
2689 frame
.rect
.height() + (me
->y
- frame
.grab_y
));
2692 constrain(anchor
, &gw
, &gh
);
2694 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2695 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
2696 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
2698 screen
->showGeometry(gw
, gh
);
2705 void BlackboxWindow::shapeEvent(XShapeEvent
*) {
2706 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
2713 bool BlackboxWindow::validateClient(void) {
2714 XSync(blackbox
->getXDisplay(), False
);
2717 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
2718 DestroyNotify
, &e
) ||
2719 XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
2721 XPutBackEvent(blackbox
->getXDisplay(), &e
);
2730 void BlackboxWindow::restore(bool remap
) {
2731 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeDelete
);
2732 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
2733 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, NoEventMask
);
2737 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
2738 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
2740 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, client
.old_bw
);
2743 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
2744 ReparentNotify
, &ev
)) {
2747 // according to the ICCCM - if the client doesn't reparent to
2748 // root, then we have to do it for them
2749 XReparentWindow(blackbox
->getXDisplay(), client
.window
,
2750 screen
->getRootWindow(),
2751 client
.rect
.x(), client
.rect
.y());
2754 if (remap
) XMapWindow(blackbox
->getXDisplay(), client
.window
);
2758 // timer for autoraise
2759 void BlackboxWindow::timeout(void) {
2760 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2764 void BlackboxWindow::changeBlackboxHints(BlackboxHints
*net
) {
2765 if ((net
->flags
& AttribShaded
) &&
2766 ((blackbox_attrib
.attrib
& AttribShaded
) !=
2767 (net
->attrib
& AttribShaded
)))
2770 if (flags
.visible
&& // watch out for requests when we can not be seen
2771 (net
->flags
& (AttribMaxVert
| AttribMaxHoriz
)) &&
2772 ((blackbox_attrib
.attrib
& (AttribMaxVert
| AttribMaxHoriz
)) !=
2773 (net
->attrib
& (AttribMaxVert
| AttribMaxHoriz
)))) {
2774 if (flags
.maximized
) {
2779 if ((net
->flags
& AttribMaxHoriz
) && (net
->flags
& AttribMaxVert
))
2780 button
= ((net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0);
2781 else if (net
->flags
& AttribMaxVert
)
2782 button
= ((net
->attrib
& AttribMaxVert
) ? 2 : 0);
2783 else if (net
->flags
& AttribMaxHoriz
)
2784 button
= ((net
->attrib
& AttribMaxHoriz
) ? 3 : 0);
2790 if ((net
->flags
& AttribOmnipresent
) &&
2791 ((blackbox_attrib
.attrib
& AttribOmnipresent
) !=
2792 (net
->attrib
& AttribOmnipresent
)))
2795 if ((net
->flags
& AttribWorkspace
) &&
2796 (blackbox_attrib
.workspace
!= net
->workspace
)) {
2797 screen
->reassociateWindow(this, net
->workspace
, True
);
2799 if (screen
->getCurrentWorkspaceID() != net
->workspace
) {
2803 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2807 if (net
->flags
& AttribDecoration
) {
2808 switch (net
->decoration
) {
2810 // clear all decorations except close
2811 decorations
&= Decor_Close
;
2817 decorations
|= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
2818 Decor_Iconify
| Decor_Maximize
;
2823 decorations
|= Decor_Titlebar
| Decor_Iconify
;
2824 decorations
&= ~(Decor_Border
| Decor_Handle
| Decor_Maximize
);
2829 decorations
|= Decor_Titlebar
;
2830 decorations
&= ~(Decor_Iconify
| Decor_Border
| Decor_Handle
);
2831 functions
|= Func_Move
;
2836 // we can not be shaded if we lack a titlebar
2837 if (flags
.shaded
&& ! (decorations
& Decor_Titlebar
))
2841 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
2842 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
2846 setState(current_state
);
2852 * Set the sizes of all components of the window frame
2853 * (the window decorations).
2854 * These values are based upon the current style settings and the client
2855 * window's dimensions.
2857 void BlackboxWindow::upsize(void) {
2858 frame
.bevel_w
= screen
->getBevelWidth();
2860 if (decorations
& Decor_Border
) {
2861 frame
.border_w
= screen
->getBorderWidth();
2862 if (! isTransient())
2863 frame
.mwm_border_w
= screen
->getFrameWidth();
2865 frame
.mwm_border_w
= 0;
2867 frame
.mwm_border_w
= frame
.border_w
= 0;
2870 if (decorations
& Decor_Titlebar
) {
2871 // the height of the titlebar is based upon the height of the font being
2872 // used to display the window's title
2873 WindowStyle
*style
= screen
->getWindowStyle();
2874 if (i18n
.multibyte())
2875 frame
.title_h
= (style
->fontset_extents
->max_ink_extent
.height
+
2876 (frame
.bevel_w
* 2) + 2);
2878 frame
.title_h
= (style
->font
->ascent
+ style
->font
->descent
+
2879 (frame
.bevel_w
* 2) + 2);
2881 frame
.label_h
= frame
.title_h
- (frame
.bevel_w
* 2);
2882 frame
.button_w
= (frame
.label_h
- 2);
2884 // set the top frame margin
2885 frame
.margin
.top
= frame
.border_w
+ frame
.title_h
+
2886 frame
.border_w
+ frame
.mwm_border_w
;
2892 // set the top frame margin
2893 frame
.margin
.top
= frame
.border_w
+ frame
.mwm_border_w
;
2896 // set the left/right frame margin
2897 frame
.margin
.left
= frame
.margin
.right
= frame
.border_w
+ frame
.mwm_border_w
;
2899 if (decorations
& Decor_Handle
) {
2900 frame
.grip_w
= frame
.button_w
* 2;
2901 frame
.handle_h
= screen
->getHandleWidth();
2903 // set the bottom frame margin
2904 frame
.margin
.bottom
= frame
.border_w
+ frame
.handle_h
+
2905 frame
.border_w
+ frame
.mwm_border_w
;
2910 // set the bottom frame margin
2911 frame
.margin
.bottom
= frame
.border_w
+ frame
.mwm_border_w
;
2915 We first get the normal dimensions and use this to define the inside_w/h
2916 then we modify the height if shading is in effect.
2917 If the shade state is not considered then frame.rect gets reset to the
2918 normal window size on a reconfigure() call resulting in improper
2919 dimensions appearing in move/resize and other events.
2922 height
= client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
,
2923 width
= client
.rect
.width() + frame
.margin
.left
+ frame
.margin
.right
;
2925 frame
.inside_w
= width
- (frame
.border_w
* 2);
2926 frame
.inside_h
= height
- (frame
.border_w
* 2);
2929 height
= frame
.title_h
+ (frame
.border_w
* 2);
2930 frame
.rect
.setSize(width
, height
);
2935 * Calculate the size of the client window and constrain it to the
2936 * size specified by the size hints of the client window.
2938 * The logical width and height are placed into pw and ph, if they
2939 * are non-zero. Logical size refers to the users perception of
2940 * the window size (for example an xterm resizes in cells, not in pixels).
2942 * The physical geometry is placed into frame.changing_{x,y,width,height}.
2943 * Physical geometry refers to the geometry of the window in pixels.
2945 void BlackboxWindow::constrain(Corner anchor
, int *pw
, int *ph
) {
2946 // frame.changing represents the requested frame size, we need to
2947 // strip the frame margin off and constrain the client size
2948 frame
.changing
.setCoords(frame
.changing
.left() + frame
.margin
.left
,
2949 frame
.changing
.top() + frame
.margin
.top
,
2950 frame
.changing
.right() - frame
.margin
.right
,
2951 frame
.changing
.bottom() - frame
.margin
.bottom
);
2953 int dw
= frame
.changing
.width(), dh
= frame
.changing
.height(),
2954 base_width
= (client
.base_width
) ? client
.base_width
: client
.min_width
,
2955 base_height
= (client
.base_height
) ? client
.base_height
:
2959 if (dw
< static_cast<signed>(client
.min_width
)) dw
= client
.min_width
;
2960 if (dh
< static_cast<signed>(client
.min_height
)) dh
= client
.min_height
;
2961 if (dw
> static_cast<signed>(client
.max_width
)) dw
= client
.max_width
;
2962 if (dh
> static_cast<signed>(client
.max_height
)) dh
= client
.max_height
;
2965 dw
/= client
.width_inc
;
2967 dh
/= client
.height_inc
;
2972 dw
*= client
.width_inc
;
2974 dh
*= client
.height_inc
;
2977 frame
.changing
.setSize(dw
, dh
);
2979 // add the frame margin back onto frame.changing
2980 frame
.changing
.setCoords(frame
.changing
.left() - frame
.margin
.left
,
2981 frame
.changing
.top() - frame
.margin
.top
,
2982 frame
.changing
.right() + frame
.margin
.right
,
2983 frame
.changing
.bottom() + frame
.margin
.bottom
);
2985 // move frame.changing to the specified anchor
2992 int dx
= frame
.rect
.right() - frame
.changing
.right();
2993 frame
.changing
.setPos(frame
.changing
.x() + dx
, frame
.changing
.y());
2999 int WindowStyle::doJustify(const char *text
, int &start_pos
,
3000 unsigned int max_length
, unsigned int modifier
,
3001 bool multibyte
) const {
3002 size_t text_len
= strlen(text
);
3003 unsigned int length
;
3007 XRectangle ink
, logical
;
3008 XmbTextExtents(fontset
, text
, text_len
, &ink
, &logical
);
3009 length
= logical
.width
;
3011 length
= XTextWidth(font
, text
, text_len
);
3014 } while (length
> max_length
&& text_len
-- > 0);
3018 start_pos
+= max_length
- length
;
3022 start_pos
+= (max_length
- length
) / 2;
3034 BWindowGroup::BWindowGroup(Blackbox
*b
, Window _group
)
3035 : blackbox(b
), group(_group
) {
3036 XWindowAttributes wattrib
;
3037 if (! XGetWindowAttributes(blackbox
->getXDisplay(), group
, &wattrib
)) {
3038 // group window doesn't seem to exist anymore
3044 watch for destroy notify on the group window (in addition to
3045 any other events we are looking for)
3047 since some managed windows can also be window group controllers,
3048 we need to make sure that we don't clobber the event mask for the
3051 XSelectInput(blackbox
->getXDisplay(), group
,
3052 wattrib
.your_event_mask
| StructureNotifyMask
);
3054 blackbox
->saveGroupSearch(group
, this);
3058 BWindowGroup::~BWindowGroup(void) {
3059 blackbox
->removeGroupSearch(group
);
3064 BWindowGroup::find(BScreen
*screen
, bool allow_transients
) const {
3065 BlackboxWindow
*ret
= blackbox
->getFocusedWindow();
3067 // does the focus window match (or any transient_fors)?
3069 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3070 if (ret
->isTransient() && allow_transients
) break;
3071 else if (! ret
->isTransient()) break;
3074 ret
= ret
->getTransientFor();
3077 if (ret
) return ret
;
3079 // the focus window didn't match, look in the group's window list
3080 BlackboxWindowList::const_iterator it
, end
= windowList
.end();
3081 for (it
= windowList
.begin(); it
!= end
; ++it
) {
3083 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3084 if (ret
->isTransient() && allow_transients
) break;
3085 else if (! ret
->isTransient()) break;