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"
60 * Initializes the class with default values/the window's set initial values.
62 BlackboxWindow::BlackboxWindow(Blackbox
*b
, Window w
, BScreen
*s
) {
63 // fprintf(stderr, "BlackboxWindow size: %d bytes\n",
64 // sizeof(BlackboxWindow));
67 fprintf(stderr
, "BlackboxWindow::BlackboxWindow(): creating 0x%lx\n", w
);
70 // set timer to zero... it is initialized properly later, so we check
71 // if timer is zero in the destructor, and assume that the window is not
72 // fully constructed if timer is zero...
78 if (! validateClient()) {
83 // set the eventmask early in the game so that we make sure we get
84 // all the events we are interested in
85 XSetWindowAttributes attrib_set
;
86 attrib_set
.event_mask
= PropertyChangeMask
| FocusChangeMask
|
88 attrib_set
.do_not_propagate_mask
= ButtonPressMask
| ButtonReleaseMask
|
90 XChangeWindowAttributes(blackbox
->getXDisplay(), client
.window
,
91 CWEventMask
|CWDontPropagate
, &attrib_set
);
93 // fetch client size and placement
94 XWindowAttributes wattrib
;
95 if ((! XGetWindowAttributes(blackbox
->getXDisplay(),
96 client
.window
, &wattrib
)) ||
97 (! wattrib
.screen
) || wattrib
.override_redirect
) {
100 "BlackboxWindow::BlackboxWindow(): XGetWindowAttributes failed\n");
107 flags
.moving
= flags
.resizing
= flags
.shaded
= flags
.visible
=
108 flags
.iconic
= flags
.focused
= flags
.stuck
= flags
.modal
=
109 flags
.send_focus_message
= flags
.shaped
= False
;
112 blackbox_attrib
.workspace
= window_number
= BSENTINEL
;
114 blackbox_attrib
.flags
= blackbox_attrib
.attrib
= blackbox_attrib
.stack
115 = blackbox_attrib
.decoration
= 0l;
116 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
117 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
120 frame
.window
= frame
.plate
= frame
.title
= frame
.handle
= None
;
121 frame
.close_button
= frame
.iconify_button
= frame
.maximize_button
= None
;
122 frame
.right_grip
= frame
.left_grip
= None
;
124 frame
.ulabel_pixel
= frame
.flabel_pixel
= frame
.utitle_pixel
=
125 frame
.ftitle_pixel
= frame
.uhandle_pixel
= frame
.fhandle_pixel
=
126 frame
.ubutton_pixel
= frame
.fbutton_pixel
= frame
.pbutton_pixel
=
127 frame
.uborder_pixel
= frame
.fborder_pixel
= frame
.ugrip_pixel
=
128 frame
.fgrip_pixel
= 0;
129 frame
.utitle
= frame
.ftitle
= frame
.uhandle
= frame
.fhandle
= None
;
130 frame
.ulabel
= frame
.flabel
= frame
.ubutton
= frame
.fbutton
= None
;
131 frame
.pbutton
= frame
.ugrip
= frame
.fgrip
= decorations
;
133 decorations
= Decor_Titlebar
| Decor_Border
| Decor_Handle
|
134 Decor_Iconify
| Decor_Maximize
;
135 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
137 client
.wm_hint_flags
= client
.normal_hint_flags
= 0;
138 client
.transient_for
= 0;
140 // get the initial size and location of client window (relative to the
141 // _root window_). This position is the reference point used with the
142 // window's gravity to find the window's initial position.
143 client
.rect
.setRect(wattrib
.x
, wattrib
.y
, wattrib
.width
, wattrib
.height
);
144 client
.old_bw
= wattrib
.border_width
;
147 lastButtonPressTime
= 0;
149 timer
= new BTimer(blackbox
, this);
150 timer
->setTimeout(blackbox
->getAutoRaiseDelay());
152 if (! getBlackboxHints())
155 // get size, aspect, minimum/maximum size and other hints set by the
161 if (client
.initial_state
== WithdrawnState
) {
162 screen
->getSlit()->addClient(client
.window
);
167 frame
.window
= createToplevelWindow();
168 frame
.plate
= createChildWindow(frame
.window
);
169 associateClientWindow();
171 blackbox
->saveWindowSearch(frame
.window
, this);
172 blackbox
->saveWindowSearch(frame
.plate
, this);
173 blackbox
->saveWindowSearch(client
.window
, this);
175 // determine if this is a transient window
178 // adjust the window decorations based on transience and window sizes
180 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
181 functions
&= ~Func_Maximize
;
184 if ((client
.normal_hint_flags
& PMinSize
) &&
185 (client
.normal_hint_flags
& PMaxSize
) &&
186 client
.max_width
<= client
.min_width
&&
187 client
.max_height
<= client
.min_height
) {
188 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
189 functions
&= ~(Func_Resize
| Func_Maximize
);
193 bool place_window
= True
;
194 if (blackbox
->isStartup() || isTransient() ||
195 client
.normal_hint_flags
& (PPosition
|USPosition
)) {
199 if (blackbox
->isStartup() ||
200 client
.rect
.intersects(screen
->availableArea()))
201 place_window
= False
;
204 if (decorations
& Decor_Titlebar
)
207 if (decorations
& Decor_Handle
)
211 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
216 if ((! screen
->isSloppyFocus()) || screen
->doClickRaise()) {
217 // grab button 1 for changing focus/raising
218 blackbox
->grabButton(Button1
, 0, frame
.plate
, True
, ButtonPressMask
,
219 GrabModeSync
, GrabModeSync
, frame
.plate
, None
);
222 blackbox
->grabButton(Button1
, Mod1Mask
, frame
.window
, True
,
223 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
224 GrabModeAsync
, frame
.window
, blackbox
->getMoveCursor());
225 blackbox
->grabButton(Button2
, Mod1Mask
, frame
.window
, True
,
226 ButtonReleaseMask
, GrabModeAsync
, GrabModeAsync
,
228 blackbox
->grabButton(Button3
, Mod1Mask
, frame
.window
, True
,
229 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
230 GrabModeAsync
, frame
.window
,
231 blackbox
->getLowerRightAngleCursor());
236 if (decorations
& Decor_Titlebar
)
237 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
238 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
240 windowmenu
= new Windowmenu(this);
242 if (blackbox_attrib
.workspace
>= screen
->getWorkspaceCount())
243 screen
->getCurrentWorkspace()->addWindow(this, place_window
);
245 screen
->getWorkspace(blackbox_attrib
.workspace
)->
246 addWindow(this, place_window
);
248 if (! place_window
) {
249 // don't need to call configure if we are letting the workspace
251 configure(frame
.rect
.x(), frame
.rect
.y(),
252 frame
.rect
.width(), frame
.rect
.height());
256 flags
.shaded
= False
;
260 if (flags
.maximized
&& (functions
& Func_Maximize
)) {
268 BlackboxWindow::~BlackboxWindow(void) {
271 fprintf(stderr
, "BlackboxWindow::~BlackboxWindow: destroying 0x%lx\n",
275 if (! timer
) // window not managed...
278 if (flags
.moving
|| flags
.resizing
) {
279 screen
->hideGeometry();
280 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
287 if (client
.window_group
) {
288 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
289 if (group
) group
->removeWindow(this);
292 // remove ourselves from our transient_for
294 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
295 client
.transient_for
->client
.transientList
.remove(this);
297 client
.transient_for
= (BlackboxWindow
*) 0;
300 if (client
.transientList
.size() > 0) {
301 // reset transient_for for all transients
302 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
303 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
304 (*it
)->client
.transient_for
= (BlackboxWindow
*) 0;
315 blackbox
->removeWindowSearch(frame
.plate
);
316 XDestroyWindow(blackbox
->getXDisplay(), frame
.plate
);
320 blackbox
->removeWindowSearch(frame
.window
);
321 XDestroyWindow(blackbox
->getXDisplay(), frame
.window
);
324 blackbox
->removeWindowSearch(client
.window
);
329 * Creates a new top level window, with a given location, size, and border
331 * Returns: the newly created window
333 Window
BlackboxWindow::createToplevelWindow(void) {
334 XSetWindowAttributes attrib_create
;
335 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
| CWColormap
|
336 CWOverrideRedirect
| CWEventMask
;
338 attrib_create
.background_pixmap
= None
;
339 attrib_create
.colormap
= screen
->getColormap();
340 attrib_create
.override_redirect
= True
;
341 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
342 ButtonMotionMask
| EnterWindowMask
;
344 return XCreateWindow(blackbox
->getXDisplay(), screen
->getRootWindow(),
345 -1, -1, 1, 1, frame
.border_w
, screen
->getDepth(),
346 InputOutput
, screen
->getVisual(), create_mask
,
352 * Creates a child window, and optionally associates a given cursor with
355 Window
BlackboxWindow::createChildWindow(Window parent
, Cursor cursor
) {
356 XSetWindowAttributes attrib_create
;
357 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
|
360 attrib_create
.background_pixmap
= None
;
361 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
362 ButtonMotionMask
| ExposureMask
;
365 create_mask
|= CWCursor
;
366 attrib_create
.cursor
= cursor
;
369 return XCreateWindow(blackbox
->getXDisplay(), parent
, 0, 0, 1, 1, 0,
370 screen
->getDepth(), InputOutput
, screen
->getVisual(),
371 create_mask
, &attrib_create
);
375 void BlackboxWindow::associateClientWindow(void) {
376 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, 0);
380 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeInsert
);
382 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, SubstructureRedirectMask
);
384 XGrabServer(blackbox
->getXDisplay());
385 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
386 XReparentWindow(blackbox
->getXDisplay(), client
.window
, frame
.plate
, 0, 0);
387 XSelectInput(blackbox
->getXDisplay(), client
.window
,
388 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
389 XUngrabServer(blackbox
->getXDisplay());
391 XRaiseWindow(blackbox
->getXDisplay(), frame
.plate
);
392 XMapSubwindows(blackbox
->getXDisplay(), frame
.plate
);
396 if (blackbox
->hasShapeExtensions()) {
397 XShapeSelectInput(blackbox
->getXDisplay(), client
.window
,
404 XShapeQueryExtents(blackbox
->getXDisplay(), client
.window
, &shaped
,
405 &foo
, &foo
, &ufoo
, &ufoo
, &foo
, &foo
, &foo
,
407 flags
.shaped
= shaped
;
413 void BlackboxWindow::decorate(void) {
416 texture
= &(screen
->getWindowStyle()->b_focus
);
417 frame
.fbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
420 frame
.fbutton_pixel
= texture
->color().pixel();
422 texture
= &(screen
->getWindowStyle()->b_unfocus
);
423 frame
.ubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
426 frame
.ubutton_pixel
= texture
->color().pixel();
428 texture
= &(screen
->getWindowStyle()->b_pressed
);
429 frame
.pbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
432 frame
.pbutton_pixel
= texture
->color().pixel();
434 if (decorations
& Decor_Titlebar
) {
435 texture
= &(screen
->getWindowStyle()->t_focus
);
436 frame
.ftitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
439 frame
.ftitle_pixel
= texture
->color().pixel();
441 texture
= &(screen
->getWindowStyle()->t_unfocus
);
442 frame
.utitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
445 frame
.utitle_pixel
= texture
->color().pixel();
447 XSetWindowBorder(blackbox
->getXDisplay(), frame
.title
,
448 screen
->getBorderColor()->pixel());
453 if (decorations
& Decor_Border
) {
454 frame
.fborder_pixel
= screen
->getWindowStyle()->f_focus
.pixel();
455 frame
.uborder_pixel
= screen
->getWindowStyle()->f_unfocus
.pixel();
456 blackbox_attrib
.flags
|= AttribDecoration
;
457 blackbox_attrib
.decoration
= DecorNormal
;
459 blackbox_attrib
.flags
|= AttribDecoration
;
460 blackbox_attrib
.decoration
= DecorNone
;
463 if (decorations
& Decor_Handle
) {
464 texture
= &(screen
->getWindowStyle()->h_focus
);
465 frame
.fhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
468 frame
.fhandle_pixel
= texture
->color().pixel();
470 texture
= &(screen
->getWindowStyle()->h_unfocus
);
471 frame
.uhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
474 frame
.uhandle_pixel
= texture
->color().pixel();
476 texture
= &(screen
->getWindowStyle()->g_focus
);
477 frame
.fgrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.fgrip
);
479 frame
.fgrip_pixel
= texture
->color().pixel();
481 texture
= &(screen
->getWindowStyle()->g_unfocus
);
482 frame
.ugrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.ugrip
);
484 frame
.ugrip_pixel
= texture
->color().pixel();
486 XSetWindowBorder(blackbox
->getXDisplay(), frame
.handle
,
487 screen
->getBorderColor()->pixel());
488 XSetWindowBorder(blackbox
->getXDisplay(), frame
.left_grip
,
489 screen
->getBorderColor()->pixel());
490 XSetWindowBorder(blackbox
->getXDisplay(), frame
.right_grip
,
491 screen
->getBorderColor()->pixel());
494 XSetWindowBorder(blackbox
->getXDisplay(), frame
.window
,
495 screen
->getBorderColor()->pixel());
499 void BlackboxWindow::decorateLabel(void) {
502 texture
= &(screen
->getWindowStyle()->l_focus
);
503 frame
.flabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.flabel
);
505 frame
.flabel_pixel
= texture
->color().pixel();
507 texture
= &(screen
->getWindowStyle()->l_unfocus
);
508 frame
.ulabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.ulabel
);
510 frame
.ulabel_pixel
= texture
->color().pixel();
514 void BlackboxWindow::createHandle(void) {
515 frame
.handle
= createChildWindow(frame
.window
);
516 blackbox
->saveWindowSearch(frame
.handle
, this);
519 createChildWindow(frame
.handle
, blackbox
->getLowerLeftAngleCursor());
520 blackbox
->saveWindowSearch(frame
.left_grip
, this);
523 createChildWindow(frame
.handle
, blackbox
->getLowerRightAngleCursor());
524 blackbox
->saveWindowSearch(frame
.right_grip
, this);
528 void BlackboxWindow::destroyHandle(void) {
530 screen
->getImageControl()->removeImage(frame
.fhandle
);
533 screen
->getImageControl()->removeImage(frame
.uhandle
);
536 screen
->getImageControl()->removeImage(frame
.fgrip
);
539 screen
->getImageControl()->removeImage(frame
.ugrip
);
541 blackbox
->removeWindowSearch(frame
.left_grip
);
542 blackbox
->removeWindowSearch(frame
.right_grip
);
544 XDestroyWindow(blackbox
->getXDisplay(), frame
.left_grip
);
545 XDestroyWindow(blackbox
->getXDisplay(), frame
.right_grip
);
546 frame
.left_grip
= frame
.right_grip
= None
;
548 blackbox
->removeWindowSearch(frame
.handle
);
549 XDestroyWindow(blackbox
->getXDisplay(), frame
.handle
);
554 void BlackboxWindow::createTitlebar(void) {
555 frame
.title
= createChildWindow(frame
.window
);
556 frame
.label
= createChildWindow(frame
.title
);
557 blackbox
->saveWindowSearch(frame
.title
, this);
558 blackbox
->saveWindowSearch(frame
.label
, this);
560 if (decorations
& Decor_Iconify
) createIconifyButton();
561 if (decorations
& Decor_Maximize
) createMaximizeButton();
562 if (decorations
& Decor_Close
) createCloseButton();
566 void BlackboxWindow::destroyTitlebar(void) {
567 if (frame
.close_button
)
568 destroyCloseButton();
570 if (frame
.iconify_button
)
571 destroyIconifyButton();
573 if (frame
.maximize_button
)
574 destroyMaximizeButton();
577 screen
->getImageControl()->removeImage(frame
.ftitle
);
580 screen
->getImageControl()->removeImage(frame
.utitle
);
583 screen
->getImageControl()->removeImage(frame
.flabel
);
586 screen
->getImageControl()->removeImage(frame
.ulabel
);
589 screen
->getImageControl()->removeImage(frame
.fbutton
);
592 screen
->getImageControl()->removeImage(frame
.ubutton
);
595 screen
->getImageControl()->removeImage(frame
.pbutton
);
597 blackbox
->removeWindowSearch(frame
.title
);
598 blackbox
->removeWindowSearch(frame
.label
);
600 XDestroyWindow(blackbox
->getXDisplay(), frame
.label
);
601 XDestroyWindow(blackbox
->getXDisplay(), frame
.title
);
602 frame
.title
= frame
.label
= None
;
606 void BlackboxWindow::createCloseButton(void) {
607 if (frame
.title
!= None
) {
608 frame
.close_button
= createChildWindow(frame
.title
);
609 blackbox
->saveWindowSearch(frame
.close_button
, this);
614 void BlackboxWindow::destroyCloseButton(void) {
615 blackbox
->removeWindowSearch(frame
.close_button
);
616 XDestroyWindow(blackbox
->getXDisplay(), frame
.close_button
);
617 frame
.close_button
= None
;
621 void BlackboxWindow::createIconifyButton(void) {
622 if (frame
.title
!= None
) {
623 frame
.iconify_button
= createChildWindow(frame
.title
);
624 blackbox
->saveWindowSearch(frame
.iconify_button
, this);
629 void BlackboxWindow::destroyIconifyButton(void) {
630 blackbox
->removeWindowSearch(frame
.iconify_button
);
631 XDestroyWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
632 frame
.iconify_button
= None
;
636 void BlackboxWindow::createMaximizeButton(void) {
637 if (frame
.title
!= None
) {
638 frame
.maximize_button
= createChildWindow(frame
.title
);
639 blackbox
->saveWindowSearch(frame
.maximize_button
, this);
644 void BlackboxWindow::destroyMaximizeButton(void) {
645 blackbox
->removeWindowSearch(frame
.maximize_button
);
646 XDestroyWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
647 frame
.maximize_button
= None
;
651 void BlackboxWindow::positionButtons(bool redecorate_label
) {
652 unsigned int bw
= frame
.button_w
+ frame
.bevel_w
+ 1,
653 by
= frame
.bevel_w
+ 1, lx
= by
, lw
= frame
.inside_w
- by
;
655 if (decorations
& Decor_Iconify
) {
656 if (frame
.iconify_button
== None
) createIconifyButton();
658 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.iconify_button
, by
, by
,
659 frame
.button_w
, frame
.button_w
);
660 XMapWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
661 XClearWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
665 } else if (frame
.iconify_button
) {
666 destroyIconifyButton();
668 int bx
= frame
.inside_w
- bw
;
670 if (decorations
& Decor_Close
) {
671 if (frame
.close_button
== None
) createCloseButton();
673 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.close_button
, bx
, by
,
674 frame
.button_w
, frame
.button_w
);
675 XMapWindow(blackbox
->getXDisplay(), frame
.close_button
);
676 XClearWindow(blackbox
->getXDisplay(), frame
.close_button
);
680 } else if (frame
.close_button
) {
681 destroyCloseButton();
683 if (decorations
& Decor_Maximize
) {
684 if (frame
.maximize_button
== None
) createMaximizeButton();
686 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.maximize_button
, bx
, by
,
687 frame
.button_w
, frame
.button_w
);
688 XMapWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
689 XClearWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
692 } else if (frame
.maximize_button
) {
693 destroyMaximizeButton();
695 frame
.label_w
= lw
- by
;
696 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.label
, lx
, frame
.bevel_w
,
697 frame
.label_w
, frame
.label_h
);
698 if (redecorate_label
) decorateLabel();
705 void BlackboxWindow::reconfigure(void) {
708 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
709 frame
.rect
.top() + frame
.margin
.top
);
714 XClearWindow(blackbox
->getXDisplay(), frame
.window
);
715 setFocusFlag(flags
.focused
);
717 configure(frame
.rect
.x(), frame
.rect
.y(),
718 frame
.rect
.width(), frame
.rect
.height());
721 windowmenu
->move(windowmenu
->getX(), frame
.rect
.y() + frame
.title_h
);
722 windowmenu
->reconfigure();
727 void BlackboxWindow::updateFocusModel(void) {
728 if ((! screen
->isSloppyFocus()) || screen
->doClickRaise()) {
729 // grab button 1 for changing focus/raising
730 blackbox
->grabButton(Button1
, 0, frame
.plate
, True
, ButtonPressMask
,
731 GrabModeSync
, GrabModeSync
, None
, None
);
733 blackbox
->ungrabButton(Button1
, 0, frame
.plate
);
738 void BlackboxWindow::positionWindows(void) {
739 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.window
,
740 frame
.rect
.x(), frame
.rect
.y(), frame
.inside_w
,
741 (flags
.shaded
) ? frame
.title_h
: frame
.inside_h
);
742 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.window
, frame
.border_w
);
743 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.plate
,
745 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.plate
,
746 frame
.margin
.left
- frame
.mwm_border_w
- frame
.border_w
,
747 frame
.margin
.top
- frame
.mwm_border_w
- frame
.border_w
,
748 client
.rect
.width(), client
.rect
.height());
749 XMoveResizeWindow(blackbox
->getXDisplay(), client
.window
,
750 0, 0, client
.rect
.width(), client
.rect
.height());
752 if (decorations
& Decor_Titlebar
) {
753 if (frame
.title
== None
) createTitlebar();
755 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.title
,
757 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.title
, -frame
.border_w
,
758 -frame
.border_w
, frame
.inside_w
, frame
.title_h
);
761 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
762 XMapWindow(blackbox
->getXDisplay(), frame
.title
);
763 } else if (frame
.title
) {
766 if (decorations
& Decor_Handle
) {
767 if (frame
.handle
== None
) createHandle();
768 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.handle
,
770 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.left_grip
,
772 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.right_grip
,
775 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.handle
,
777 frame
.rect
.height() - frame
.margin
.bottom
+
778 frame
.mwm_border_w
- frame
.border_w
,
779 frame
.inside_w
, frame
.handle_h
);
780 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.left_grip
,
781 -frame
.border_w
, -frame
.border_w
,
782 frame
.grip_w
, frame
.handle_h
);
783 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.right_grip
,
784 frame
.inside_w
- frame
.grip_w
- frame
.border_w
,
785 -frame
.border_w
, frame
.grip_w
, frame
.handle_h
);
786 XMapSubwindows(blackbox
->getXDisplay(), frame
.handle
);
787 XMapWindow(blackbox
->getXDisplay(), frame
.handle
);
788 } else if (frame
.handle
) {
794 void BlackboxWindow::getWMName(void) {
795 XTextProperty text_prop
;
797 if (XGetWMName(blackbox
->getXDisplay(), client
.window
, &text_prop
)) {
798 client
.title
= textPropertyToString(blackbox
->getXDisplay(), text_prop
);
799 if (client
.title
.empty())
800 client
.title
= i18n(WindowSet
, WindowUnnamed
, "Unnamed");
801 XFree((char *) text_prop
.value
);
803 client
.title
= i18n(WindowSet
, WindowUnnamed
, "Unnamed");
808 void BlackboxWindow::getWMIconName(void) {
809 XTextProperty text_prop
;
811 if (XGetWMIconName(blackbox
->getXDisplay(), client
.window
, &text_prop
)) {
813 textPropertyToString(blackbox
->getXDisplay(), text_prop
);
814 if (client
.icon_title
.empty())
815 client
.icon_title
= client
.title
;
816 XFree((char *) text_prop
.value
);
818 client
.icon_title
= client
.title
;
824 * Retrieve which WM Protocols are supported by the client window.
825 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
826 * window's decorations and allow the close behavior.
827 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
830 void BlackboxWindow::getWMProtocols(void) {
834 if (XGetWMProtocols(blackbox
->getXDisplay(), client
.window
,
835 &proto
, &num_return
)) {
836 for (int i
= 0; i
< num_return
; ++i
) {
837 if (proto
[i
] == blackbox
->getWMDeleteAtom()) {
838 decorations
|= Decor_Close
;
839 functions
|= Func_Close
;
840 } else if (proto
[i
] == blackbox
->getWMTakeFocusAtom())
841 flags
.send_focus_message
= True
;
842 else if (proto
[i
] == blackbox
->getBlackboxStructureMessagesAtom())
843 screen
->addNetizen(new Netizen(screen
, client
.window
));
852 * Gets the value of the WM_HINTS property.
853 * If the property is not set, then use a set of default values.
855 void BlackboxWindow::getWMHints(void) {
856 focus_mode
= F_Passive
;
857 client
.initial_state
= NormalState
;
859 // remove from current window group
860 if (client
.window_group
) {
861 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
862 if (group
) group
->removeWindow(this);
864 client
.window_group
= None
;
866 XWMHints
*wmhint
= XGetWMHints(blackbox
->getXDisplay(), client
.window
);
871 if (wmhint
->flags
& InputHint
) {
872 if (wmhint
->input
== True
) {
873 if (flags
.send_focus_message
)
874 focus_mode
= F_LocallyActive
;
876 if (flags
.send_focus_message
)
877 focus_mode
= F_GloballyActive
;
879 focus_mode
= F_NoInput
;
883 if (wmhint
->flags
& StateHint
)
884 client
.initial_state
= wmhint
->initial_state
;
886 if (wmhint
->flags
& WindowGroupHint
) {
887 client
.window_group
= wmhint
->window_group
;
889 // add window to the appropriate group
890 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
891 if (! group
) // no group found, create it!
892 group
= new BWindowGroup(blackbox
, client
.window_group
);
893 group
->addWindow(this);
896 client
.wm_hint_flags
= wmhint
->flags
;
902 * Gets the value of the WM_NORMAL_HINTS property.
903 * If the property is not set, then use a set of default values.
905 void BlackboxWindow::getWMNormalHints(void) {
909 const Rect
& screen_area
= screen
->availableArea();
911 client
.min_width
= client
.min_height
=
912 client
.width_inc
= client
.height_inc
= 1;
913 client
.base_width
= client
.base_height
= 0;
914 client
.max_width
= screen_area
.width();
915 client
.max_height
= screen_area
.height();
916 client
.min_aspect_x
= client
.min_aspect_y
=
917 client
.max_aspect_x
= client
.max_aspect_y
= 1;
918 client
.win_gravity
= NorthWestGravity
;
920 if (! XGetWMNormalHints(blackbox
->getXDisplay(), client
.window
,
921 &sizehint
, &icccm_mask
))
924 client
.normal_hint_flags
= sizehint
.flags
;
926 if (sizehint
.flags
& PMinSize
) {
927 client
.min_width
= sizehint
.min_width
;
928 client
.min_height
= sizehint
.min_height
;
931 if (sizehint
.flags
& PMaxSize
) {
932 client
.max_width
= sizehint
.max_width
;
933 client
.max_height
= sizehint
.max_height
;
936 if (sizehint
.flags
& PResizeInc
) {
937 client
.width_inc
= sizehint
.width_inc
;
938 client
.height_inc
= sizehint
.height_inc
;
941 if (sizehint
.flags
& PAspect
) {
942 client
.min_aspect_x
= sizehint
.min_aspect
.x
;
943 client
.min_aspect_y
= sizehint
.min_aspect
.y
;
944 client
.max_aspect_x
= sizehint
.max_aspect
.x
;
945 client
.max_aspect_y
= sizehint
.max_aspect
.y
;
948 if (sizehint
.flags
& PBaseSize
) {
949 client
.base_width
= sizehint
.base_width
;
950 client
.base_height
= sizehint
.base_height
;
953 if (sizehint
.flags
& PWinGravity
)
954 client
.win_gravity
= sizehint
.win_gravity
;
959 * Gets the MWM hints for the class' contained window.
960 * This is used while initializing the window to its first state, and not
962 * Returns: true if the MWM hints are successfully retreived and applied;
963 * false if they are not.
965 void BlackboxWindow::getMWMHints(void) {
968 unsigned long num
, len
;
969 MwmHints
*mwm_hint
= 0;
971 int ret
= XGetWindowProperty(blackbox
->getXDisplay(), client
.window
,
972 blackbox
->getMotifWMHintsAtom(), 0,
973 PropMwmHintsElements
, False
,
974 blackbox
->getMotifWMHintsAtom(), &atom_return
,
976 (unsigned char **) &mwm_hint
);
978 if (ret
!= Success
|| ! mwm_hint
|| num
!= PropMwmHintsElements
)
981 if (mwm_hint
->flags
& MwmHintsDecorations
) {
982 if (mwm_hint
->decorations
& MwmDecorAll
) {
983 decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
984 Decor_Iconify
| Decor_Maximize
| Decor_Close
;
988 if (mwm_hint
->decorations
& MwmDecorBorder
)
989 decorations
|= Decor_Border
;
990 if (mwm_hint
->decorations
& MwmDecorHandle
)
991 decorations
|= Decor_Handle
;
992 if (mwm_hint
->decorations
& MwmDecorTitle
)
993 decorations
|= Decor_Titlebar
;
994 if (mwm_hint
->decorations
& MwmDecorIconify
)
995 decorations
|= Decor_Iconify
;
996 if (mwm_hint
->decorations
& MwmDecorMaximize
)
997 decorations
|= Decor_Maximize
;
1001 if (mwm_hint
->flags
& MwmHintsFunctions
) {
1002 if (mwm_hint
->functions
& MwmFuncAll
) {
1003 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
|
1008 if (mwm_hint
->functions
& MwmFuncResize
)
1009 functions
|= Func_Resize
;
1010 if (mwm_hint
->functions
& MwmFuncMove
)
1011 functions
|= Func_Move
;
1012 if (mwm_hint
->functions
& MwmFuncIconify
)
1013 functions
|= Func_Iconify
;
1014 if (mwm_hint
->functions
& MwmFuncMaximize
)
1015 functions
|= Func_Maximize
;
1016 if (mwm_hint
->functions
& MwmFuncClose
)
1017 functions
|= Func_Close
;
1025 * Gets the blackbox hints from the class' contained window.
1026 * This is used while initializing the window to its first state, and not
1028 * Returns: true if the hints are successfully retreived and applied; false if
1031 bool BlackboxWindow::getBlackboxHints(void) {
1034 unsigned long num
, len
;
1035 BlackboxHints
*blackbox_hint
= 0;
1037 int ret
= XGetWindowProperty(blackbox
->getXDisplay(), client
.window
,
1038 blackbox
->getBlackboxHintsAtom(), 0,
1039 PropBlackboxHintsElements
, False
,
1040 blackbox
->getBlackboxHintsAtom(), &atom_return
,
1041 &format
, &num
, &len
,
1042 (unsigned char **) &blackbox_hint
);
1043 if (ret
!= Success
|| ! blackbox_hint
|| num
!= PropBlackboxHintsElements
)
1046 if (blackbox_hint
->flags
& AttribShaded
)
1047 flags
.shaded
= (blackbox_hint
->attrib
& AttribShaded
);
1049 if ((blackbox_hint
->flags
& AttribMaxHoriz
) &&
1050 (blackbox_hint
->flags
& AttribMaxVert
))
1051 flags
.maximized
= (blackbox_hint
->attrib
&
1052 (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1053 else if (blackbox_hint
->flags
& AttribMaxVert
)
1054 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxVert
) ? 2 : 0;
1055 else if (blackbox_hint
->flags
& AttribMaxHoriz
)
1056 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1058 if (blackbox_hint
->flags
& AttribOmnipresent
)
1059 flags
.stuck
= (blackbox_hint
->attrib
& AttribOmnipresent
);
1061 if (blackbox_hint
->flags
& AttribWorkspace
)
1062 blackbox_attrib
.workspace
= blackbox_hint
->workspace
;
1064 // if (blackbox_hint->flags & AttribStack)
1065 // don't yet have always on top/bottom for blackbox yet... working
1068 if (blackbox_hint
->flags
& AttribDecoration
) {
1069 switch (blackbox_hint
->decoration
) {
1071 // clear all decorations except close
1072 decorations
&= Decor_Close
;
1073 // clear all functions except close
1074 functions
&= Func_Close
;
1079 decorations
|= Decor_Titlebar
| Decor_Iconify
;
1080 decorations
&= ~(Decor_Border
| Decor_Handle
| Decor_Maximize
);
1081 functions
|= Func_Move
| Func_Iconify
;
1082 functions
&= ~(Func_Resize
| Func_Maximize
);
1087 decorations
|= Decor_Titlebar
;
1088 decorations
&= ~(Decor_Iconify
| Decor_Border
| Decor_Handle
);
1089 functions
|= Func_Move
;
1090 functions
&= ~(Func_Resize
| Func_Maximize
| Func_Iconify
);
1096 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Handle
|
1097 Decor_Iconify
| Decor_Maximize
;
1098 functions
|= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
1105 XFree(blackbox_hint
);
1110 void BlackboxWindow::getTransientInfo(void) {
1111 if (client
.transient_for
&&
1112 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1113 // the transient for hint was removed, so we need to tell our
1114 // previous transient_for that we are going away
1115 client
.transient_for
->client
.transientList
.remove(this);
1118 // we have no transient_for until we find a new one
1119 client
.transient_for
= 0;
1122 if (! XGetTransientForHint(blackbox
->getXDisplay(), client
.window
,
1124 // transient_for hint not set
1128 if (trans_for
== client
.window
) {
1129 // wierd client... treat this window as a normal window
1133 if (trans_for
== None
|| trans_for
== screen
->getRootWindow()) {
1134 // this is an undocumented interpretation of the ICCCM. a transient
1135 // associated with None/Root/itself is assumed to be a modal root
1136 // transient. we don't support the concept of a global transient,
1137 // so we just associate this transient with nothing, and perhaps
1138 // we will add support later for global modality.
1139 client
.transient_for
= (BlackboxWindow
*) ~0ul;
1144 client
.transient_for
= blackbox
->searchWindow(trans_for
);
1145 if (! client
.transient_for
&&
1146 client
.window_group
&& trans_for
== client
.window_group
) {
1147 // no direct transient_for, perhaps this is a group transient?
1148 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1149 if (group
) client
.transient_for
= group
->find(screen
);
1152 if (! client
.transient_for
|| client
.transient_for
== this) {
1153 // no transient_for found, or we have a wierd client that wants to be
1154 // a transient for itself, so we treat this window as a normal window
1155 client
.transient_for
= (BlackboxWindow
*) 0;
1159 // register ourselves with our new transient_for
1160 client
.transient_for
->client
.transientList
.push_back(this);
1161 flags
.stuck
= client
.transient_for
->flags
.stuck
;
1165 BlackboxWindow
*BlackboxWindow::getTransientFor(void) const {
1166 if (client
.transient_for
&&
1167 client
.transient_for
!= (BlackboxWindow
*) ~0ul)
1168 return client
.transient_for
;
1173 void BlackboxWindow::configure(int dx
, int dy
,
1174 unsigned int dw
, unsigned int dh
) {
1175 bool send_event
= (frame
.rect
.x() != dx
|| frame
.rect
.y() != dy
);
1177 if ((dw
!= frame
.rect
.width()) || (dh
!= frame
.rect
.height())) {
1178 frame
.rect
.setRect(dx
, dy
, dw
, dh
);
1179 frame
.inside_w
= frame
.rect
.width() - (frame
.border_w
* 2);
1180 frame
.inside_h
= frame
.rect
.height() - (frame
.border_w
* 2);
1182 if (frame
.rect
.right() <= 0 || frame
.rect
.bottom() <= 0)
1183 frame
.rect
.setPos(0, 0);
1185 client
.rect
.setCoords(frame
.rect
.left() + frame
.margin
.left
,
1186 frame
.rect
.top() + frame
.margin
.top
,
1187 frame
.rect
.right() - frame
.margin
.right
,
1188 frame
.rect
.bottom() - frame
.margin
.bottom
);
1191 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
1198 setFocusFlag(flags
.focused
);
1201 frame
.rect
.setPos(dx
, dy
);
1203 XMoveWindow(blackbox
->getXDisplay(), frame
.window
,
1204 frame
.rect
.x(), frame
.rect
.y());
1206 if (! flags
.moving
) send_event
= True
;
1209 if (send_event
&& ! flags
.moving
) {
1210 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1211 frame
.rect
.top() + frame
.margin
.top
);
1214 event
.type
= ConfigureNotify
;
1216 event
.xconfigure
.display
= blackbox
->getXDisplay();
1217 event
.xconfigure
.event
= client
.window
;
1218 event
.xconfigure
.window
= client
.window
;
1219 event
.xconfigure
.x
= client
.rect
.x();
1220 event
.xconfigure
.y
= client
.rect
.y();
1221 event
.xconfigure
.width
= client
.rect
.width();
1222 event
.xconfigure
.height
= client
.rect
.height();
1223 event
.xconfigure
.border_width
= client
.old_bw
;
1224 event
.xconfigure
.above
= frame
.window
;
1225 event
.xconfigure
.override_redirect
= False
;
1227 XSendEvent(blackbox
->getXDisplay(), client
.window
, True
,
1228 NoEventMask
, &event
);
1230 screen
->updateNetizenConfigNotify(&event
);
1236 void BlackboxWindow::configureShape(void) {
1237 XShapeCombineShape(blackbox
->getXDisplay(), frame
.window
, ShapeBounding
,
1238 frame
.margin
.left
- frame
.border_w
,
1239 frame
.margin
.top
- frame
.border_w
,
1240 client
.window
, ShapeBounding
, ShapeSet
);
1243 XRectangle xrect
[2];
1245 if (decorations
& Decor_Titlebar
) {
1246 xrect
[0].x
= xrect
[0].y
= -frame
.border_w
;
1247 xrect
[0].width
= frame
.rect
.width();
1248 xrect
[0].height
= frame
.title_h
+ (frame
.border_w
* 2);
1252 if (decorations
& Decor_Handle
) {
1253 xrect
[1].x
= -frame
.border_w
;
1254 xrect
[1].y
= frame
.rect
.height() - frame
.margin
.bottom
+
1255 frame
.mwm_border_w
- frame
.border_w
;
1256 xrect
[1].width
= frame
.rect
.width();
1257 xrect
[1].height
= frame
.handle_h
+ (frame
.border_w
* 2);
1261 XShapeCombineRectangles(blackbox
->getXDisplay(), frame
.window
,
1262 ShapeBounding
, 0, 0, xrect
, num
,
1263 ShapeUnion
, Unsorted
);
1268 bool BlackboxWindow::setInputFocus(void) {
1269 if (flags
.focused
) return True
;
1271 if (! client
.rect
.intersects(screen
->getRect())) {
1272 // client is outside the screen, move it to the center
1273 configure((screen
->getWidth() - frame
.rect
.width()) / 2,
1274 (screen
->getHeight() - frame
.rect
.height()) / 2,
1275 frame
.rect
.width(), frame
.rect
.height());
1278 if (client
.transientList
.size() > 0) {
1279 // transfer focus to any modal transients
1280 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1281 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1282 if ((*it
)->flags
.modal
) return (*it
)->setInputFocus();
1287 if (focus_mode
== F_LocallyActive
|| focus_mode
== F_Passive
) {
1288 XSetInputFocus(blackbox
->getXDisplay(), client
.window
,
1289 RevertToPointerRoot
, CurrentTime
);
1291 blackbox
->setFocusedWindow(this);
1293 /* we could set the focus to none, since the window doesn't accept focus,
1294 * but we shouldn't set focus to nothing since this would surely make
1300 if (flags
.send_focus_message
) {
1302 ce
.xclient
.type
= ClientMessage
;
1303 ce
.xclient
.message_type
= blackbox
->getWMProtocolsAtom();
1304 ce
.xclient
.display
= blackbox
->getXDisplay();
1305 ce
.xclient
.window
= client
.window
;
1306 ce
.xclient
.format
= 32;
1307 ce
.xclient
.data
.l
[0] = blackbox
->getWMTakeFocusAtom();
1308 ce
.xclient
.data
.l
[1] = blackbox
->getLastTime();
1309 ce
.xclient
.data
.l
[2] = 0l;
1310 ce
.xclient
.data
.l
[3] = 0l;
1311 ce
.xclient
.data
.l
[4] = 0l;
1312 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1320 void BlackboxWindow::iconify(void) {
1321 if (flags
.iconic
) return;
1323 if (windowmenu
) windowmenu
->hide();
1325 setState(IconicState
);
1328 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1329 * we need to clear the event mask on client.window for a split second.
1330 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1331 * split second, leaving us with a ghost window... so, we need to do this
1332 * while the X server is grabbed
1334 XGrabServer(blackbox
->getXDisplay());
1335 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
1336 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1337 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1338 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
1339 XUngrabServer(blackbox
->getXDisplay());
1341 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1342 flags
.visible
= False
;
1343 flags
.iconic
= True
;
1345 screen
->getWorkspace(blackbox_attrib
.workspace
)->removeWindow(this);
1347 if (isTransient()) {
1348 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1349 ! client
.transient_for
->flags
.iconic
) {
1350 // iconify our transient_for
1351 client
.transient_for
->iconify();
1355 screen
->addIcon(this);
1357 if (client
.transientList
.size() > 0) {
1358 // iconify all transients
1359 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1360 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1361 if (! (*it
)->flags
.iconic
) (*it
)->iconify();
1367 void BlackboxWindow::show(void) {
1368 setState(NormalState
);
1370 XMapWindow(blackbox
->getXDisplay(), client
.window
);
1371 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
1372 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
1374 flags
.visible
= True
;
1375 flags
.iconic
= False
;
1379 void BlackboxWindow::deiconify(bool reassoc
, bool raise
) {
1380 if (flags
.iconic
|| reassoc
)
1381 screen
->reassociateWindow(this, BSENTINEL
, False
);
1382 else if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspace()->getID())
1387 // reassociate and deiconify all transients
1388 if (reassoc
&& client
.transientList
.size() > 0) {
1389 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1390 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1391 (*it
)->deiconify(True
, False
);
1396 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1400 void BlackboxWindow::close(void) {
1402 ce
.xclient
.type
= ClientMessage
;
1403 ce
.xclient
.message_type
= blackbox
->getWMProtocolsAtom();
1404 ce
.xclient
.display
= blackbox
->getXDisplay();
1405 ce
.xclient
.window
= client
.window
;
1406 ce
.xclient
.format
= 32;
1407 ce
.xclient
.data
.l
[0] = blackbox
->getWMDeleteAtom();
1408 ce
.xclient
.data
.l
[1] = CurrentTime
;
1409 ce
.xclient
.data
.l
[2] = 0l;
1410 ce
.xclient
.data
.l
[3] = 0l;
1411 ce
.xclient
.data
.l
[4] = 0l;
1412 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
, NoEventMask
, &ce
);
1416 void BlackboxWindow::withdraw(void) {
1417 setState(current_state
);
1419 flags
.visible
= False
;
1420 flags
.iconic
= False
;
1422 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1424 XGrabServer(blackbox
->getXDisplay());
1425 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
1426 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1427 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1428 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
1429 XUngrabServer(blackbox
->getXDisplay());
1431 if (windowmenu
) windowmenu
->hide();
1435 void BlackboxWindow::maximize(unsigned int button
) {
1436 // handle case where menu is open then the max button is used instead
1437 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
1439 if (flags
.maximized
) {
1440 flags
.maximized
= 0;
1442 blackbox_attrib
.flags
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1443 blackbox_attrib
.attrib
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1446 when a resize is begun, maximize(0) is called to clear any maximization
1447 flags currently set. Otherwise it still thinks it is maximized.
1448 so we do not need to call configure() because resizing will handle it
1450 if (! flags
.resizing
)
1451 configure(blackbox_attrib
.premax_x
, blackbox_attrib
.premax_y
,
1452 blackbox_attrib
.premax_w
, blackbox_attrib
.premax_h
);
1454 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
1455 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
1458 setState(current_state
);
1462 blackbox_attrib
.premax_x
= frame
.rect
.x();
1463 blackbox_attrib
.premax_y
= frame
.rect
.y();
1464 blackbox_attrib
.premax_w
= frame
.rect
.width();
1465 blackbox_attrib
.premax_h
= frame
.rect
.height();
1467 const Rect
&screen_area
= screen
->availableArea();
1468 frame
.changing
= screen_area
;
1473 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1474 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1478 blackbox_attrib
.flags
|= AttribMaxVert
;
1479 blackbox_attrib
.attrib
|= AttribMaxVert
;
1481 frame
.changing
.setX(frame
.rect
.x());
1482 frame
.changing
.setWidth(frame
.rect
.width());
1486 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1487 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1489 frame
.changing
.setY(frame
.rect
.y());
1490 frame
.changing
.setHeight(frame
.rect
.height());
1495 blackbox_attrib
.flags
^= AttribShaded
;
1496 blackbox_attrib
.attrib
^= AttribShaded
;
1497 flags
.shaded
= False
;
1500 flags
.maximized
= button
;
1502 configure(frame
.changing
.x(), frame
.changing
.y(),
1503 frame
.changing
.width(), frame
.changing
.height());
1505 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1507 setState(current_state
);
1511 // re-maximizes the window to take into account availableArea changes
1512 void BlackboxWindow::remaximize(void) {
1513 // save the original dimensions because maximize will wipe them out
1514 int premax_x
= blackbox_attrib
.premax_x
,
1515 premax_y
= blackbox_attrib
.premax_y
,
1516 premax_w
= blackbox_attrib
.premax_w
,
1517 premax_h
= blackbox_attrib
.premax_h
;
1519 unsigned int button
= flags
.maximized
;
1520 flags
.maximized
= 0; // trick maximize() into working
1523 // restore saved values
1524 blackbox_attrib
.premax_x
= premax_x
;
1525 blackbox_attrib
.premax_y
= premax_y
;
1526 blackbox_attrib
.premax_w
= premax_w
;
1527 blackbox_attrib
.premax_h
= premax_h
;
1531 void BlackboxWindow::setWorkspace(unsigned int n
) {
1532 blackbox_attrib
.flags
|= AttribWorkspace
;
1533 blackbox_attrib
.workspace
= n
;
1537 void BlackboxWindow::shade(void) {
1538 if (! (decorations
& Decor_Titlebar
))
1542 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1543 frame
.inside_w
, frame
.inside_h
);
1544 flags
.shaded
= False
;
1545 blackbox_attrib
.flags
^= AttribShaded
;
1546 blackbox_attrib
.attrib
^= AttribShaded
;
1548 setState(NormalState
);
1550 // set the frame rect to the normal size
1551 frame
.rect
.setHeight(client
.rect
.height() + frame
.margin
.top
+
1552 frame
.margin
.bottom
);
1554 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1555 frame
.inside_w
, frame
.title_h
);
1556 flags
.shaded
= True
;
1557 blackbox_attrib
.flags
|= AttribShaded
;
1558 blackbox_attrib
.attrib
|= AttribShaded
;
1560 setState(IconicState
);
1562 // set the frame rect to the shaded size
1563 frame
.rect
.setHeight(frame
.title_h
+ (frame
.border_w
* 2));
1568 void BlackboxWindow::stick(void) {
1570 blackbox_attrib
.flags
^= AttribOmnipresent
;
1571 blackbox_attrib
.attrib
^= AttribOmnipresent
;
1573 flags
.stuck
= False
;
1576 screen
->reassociateWindow(this, BSENTINEL
, True
);
1578 setState(current_state
);
1582 blackbox_attrib
.flags
|= AttribOmnipresent
;
1583 blackbox_attrib
.attrib
|= AttribOmnipresent
;
1585 setState(current_state
);
1590 void BlackboxWindow::setFocusFlag(bool focus
) {
1591 flags
.focused
= focus
;
1593 if (decorations
& Decor_Titlebar
) {
1594 if (flags
.focused
) {
1596 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1597 frame
.title
, frame
.ftitle
);
1599 XSetWindowBackground(blackbox
->getXDisplay(),
1600 frame
.title
, frame
.ftitle_pixel
);
1603 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1604 frame
.title
, frame
.utitle
);
1606 XSetWindowBackground(blackbox
->getXDisplay(),
1607 frame
.title
, frame
.utitle_pixel
);
1609 XClearWindow(blackbox
->getXDisplay(), frame
.title
);
1615 if (decorations
& Decor_Handle
) {
1616 if (flags
.focused
) {
1618 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1619 frame
.handle
, frame
.fhandle
);
1621 XSetWindowBackground(blackbox
->getXDisplay(),
1622 frame
.handle
, frame
.fhandle_pixel
);
1625 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1626 frame
.left_grip
, frame
.fgrip
);
1627 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1628 frame
.right_grip
, frame
.fgrip
);
1630 XSetWindowBackground(blackbox
->getXDisplay(),
1631 frame
.left_grip
, frame
.fgrip_pixel
);
1632 XSetWindowBackground(blackbox
->getXDisplay(),
1633 frame
.right_grip
, frame
.fgrip_pixel
);
1637 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1638 frame
.handle
, frame
.uhandle
);
1640 XSetWindowBackground(blackbox
->getXDisplay(),
1641 frame
.handle
, frame
.uhandle_pixel
);
1644 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1645 frame
.left_grip
, frame
.ugrip
);
1646 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1647 frame
.right_grip
, frame
.ugrip
);
1649 XSetWindowBackground(blackbox
->getXDisplay(),
1650 frame
.left_grip
, frame
.ugrip_pixel
);
1651 XSetWindowBackground(blackbox
->getXDisplay(),
1652 frame
.right_grip
, frame
.ugrip_pixel
);
1655 XClearWindow(blackbox
->getXDisplay(), frame
.handle
);
1656 XClearWindow(blackbox
->getXDisplay(), frame
.left_grip
);
1657 XClearWindow(blackbox
->getXDisplay(), frame
.right_grip
);
1660 if (decorations
& Decor_Border
) {
1662 XSetWindowBorder(blackbox
->getXDisplay(),
1663 frame
.plate
, frame
.fborder_pixel
);
1665 XSetWindowBorder(blackbox
->getXDisplay(),
1666 frame
.plate
, frame
.uborder_pixel
);
1669 if (screen
->isSloppyFocus() && screen
->doAutoRaise()) {
1670 if (isFocused()) timer
->start();
1675 blackbox
->setFocusedWindow(this);
1679 void BlackboxWindow::installColormap(bool install
) {
1680 int i
= 0, ncmap
= 0;
1681 Colormap
*cmaps
= XListInstalledColormaps(blackbox
->getXDisplay(),
1682 client
.window
, &ncmap
);
1683 XWindowAttributes wattrib
;
1685 if (XGetWindowAttributes(blackbox
->getXDisplay(),
1686 client
.window
, &wattrib
)) {
1688 // install the window's colormap
1689 for (i
= 0; i
< ncmap
; i
++) {
1690 if (*(cmaps
+ i
) == wattrib
.colormap
)
1691 // this window is using an installed color map... do not install
1694 // otherwise, install the window's colormap
1696 XInstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
1698 // uninstall the window's colormap
1699 for (i
= 0; i
< ncmap
; i
++) {
1700 if (*(cmaps
+ i
) == wattrib
.colormap
)
1701 // we found the colormap to uninstall
1702 XUninstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
1712 void BlackboxWindow::setState(unsigned long new_state
) {
1713 current_state
= new_state
;
1715 unsigned long state
[2];
1716 state
[0] = current_state
;
1718 XChangeProperty(blackbox
->getXDisplay(), client
.window
,
1719 blackbox
->getWMStateAtom(), blackbox
->getWMStateAtom(), 32,
1720 PropModeReplace
, (unsigned char *) state
, 2);
1722 XChangeProperty(blackbox
->getXDisplay(), client
.window
,
1723 blackbox
->getBlackboxAttributesAtom(),
1724 blackbox
->getBlackboxAttributesAtom(), 32, PropModeReplace
,
1725 (unsigned char *) &blackbox_attrib
,
1726 PropBlackboxAttributesElements
);
1730 bool BlackboxWindow::getState(void) {
1736 unsigned long *state
, ulfoo
, nitems
;
1738 if ((XGetWindowProperty(blackbox
->getXDisplay(), client
.window
,
1739 blackbox
->getWMStateAtom(),
1740 0l, 2l, False
, blackbox
->getWMStateAtom(),
1741 &atom_return
, &foo
, &nitems
, &ulfoo
,
1742 (unsigned char **) &state
) != Success
) ||
1748 current_state
= static_cast<unsigned long>(state
[0]);
1753 XFree((void *) state
);
1759 void BlackboxWindow::restoreAttributes(void) {
1760 if (! getState()) current_state
= NormalState
;
1764 unsigned long ulfoo
, nitems
;
1766 BlackboxAttributes
*net
;
1767 int ret
= XGetWindowProperty(blackbox
->getXDisplay(), client
.window
,
1768 blackbox
->getBlackboxAttributesAtom(), 0l,
1769 PropBlackboxAttributesElements
, False
,
1770 blackbox
->getBlackboxAttributesAtom(),
1771 &atom_return
, &foo
, &nitems
, &ulfoo
,
1772 (unsigned char **) &net
);
1773 if (ret
!= Success
|| ! net
|| nitems
!= PropBlackboxAttributesElements
)
1776 if (net
->flags
& AttribShaded
&&
1777 net
->attrib
& AttribShaded
) {
1779 ((current_state
== IconicState
) ? NormalState
: current_state
);
1781 flags
.shaded
= False
;
1784 current_state
= save_state
;
1787 if ((net
->workspace
!= screen
->getCurrentWorkspaceID()) &&
1788 (net
->workspace
< screen
->getWorkspaceCount())) {
1789 screen
->reassociateWindow(this, net
->workspace
, True
);
1791 if (current_state
== NormalState
) current_state
= WithdrawnState
;
1792 } else if (current_state
== WithdrawnState
) {
1793 current_state
= NormalState
;
1796 if (net
->flags
& AttribOmnipresent
&&
1797 net
->attrib
& AttribOmnipresent
) {
1798 flags
.stuck
= False
;
1801 current_state
= NormalState
;
1804 if ((net
->flags
& AttribMaxHoriz
) ||
1805 (net
->flags
& AttribMaxVert
)) {
1806 int x
= net
->premax_x
, y
= net
->premax_y
;
1807 unsigned int w
= net
->premax_w
, h
= net
->premax_h
;
1808 flags
.maximized
= 0;
1811 if ((net
->flags
& AttribMaxHoriz
) &&
1812 (net
->flags
& AttribMaxVert
))
1813 m
= (net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1814 else if (net
->flags
& AttribMaxVert
)
1815 m
= (net
->attrib
& AttribMaxVert
) ? 2 : 0;
1816 else if (net
->flags
& AttribMaxHoriz
)
1817 m
= (net
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1821 blackbox_attrib
.premax_x
= x
;
1822 blackbox_attrib
.premax_y
= y
;
1823 blackbox_attrib
.premax_w
= w
;
1824 blackbox_attrib
.premax_h
= h
;
1827 setState(current_state
);
1829 XFree((void *) net
);
1834 * Positions the frame according the the client window position and window
1837 void BlackboxWindow::setGravityOffsets(void) {
1838 // x coordinates for each gravity type
1839 const int x_west
= client
.rect
.x();
1840 const int x_east
= client
.rect
.right() - frame
.inside_w
+ 1;
1841 const int x_center
= client
.rect
.right() - (frame
.rect
.width()/2) + 1;
1842 // y coordinates for each gravity type
1843 const int y_north
= client
.rect
.y();
1844 const int y_south
= client
.rect
.bottom() - frame
.inside_h
+ 1;
1845 const int y_center
= client
.rect
.bottom() - (frame
.rect
.height()/2) + 1;
1847 switch (client
.win_gravity
) {
1849 case NorthWestGravity
: frame
.rect
.setPos(x_west
, y_north
); break;
1850 case NorthGravity
: frame
.rect
.setPos(x_center
, y_north
); break;
1851 case NorthEastGravity
: frame
.rect
.setPos(x_east
, y_north
); break;
1852 case SouthWestGravity
: frame
.rect
.setPos(x_west
, y_south
); break;
1853 case SouthGravity
: frame
.rect
.setPos(x_center
, y_south
); break;
1854 case SouthEastGravity
: frame
.rect
.setPos(x_east
, y_south
); break;
1855 case WestGravity
: frame
.rect
.setPos(x_west
, y_center
); break;
1856 case CenterGravity
: frame
.rect
.setPos(x_center
, y_center
); break;
1857 case EastGravity
: frame
.rect
.setPos(x_east
, y_center
); break;
1861 frame
.rect
.setPos(client
.rect
.x() - frame
.margin
.left
,
1862 client
.rect
.y() - frame
.margin
.top
);
1869 * The reverse of the setGravityOffsets function. Uses the frame window's
1870 * position to find the window's reference point.
1872 void BlackboxWindow::restoreGravity(void) {
1873 // x coordinates for each gravity type
1874 const int x_west
= frame
.rect
.x();
1875 const int x_east
= frame
.rect
.x() + frame
.inside_w
- client
.rect
.width();
1876 const int x_center
= frame
.rect
.x() + (frame
.rect
.width()/2) -
1877 client
.rect
.width();
1878 // y coordinates for each gravity type
1879 const int y_north
= frame
.rect
.y();
1880 const int y_south
= frame
.rect
.y() + frame
.inside_h
- client
.rect
.height();
1881 const int y_center
= frame
.rect
.y() + (frame
.rect
.height()/2) -
1882 client
.rect
.height();
1884 switch(client
.win_gravity
) {
1886 case NorthWestGravity
: client
.rect
.setPos(x_west
, y_north
); break;
1887 case NorthGravity
: client
.rect
.setPos(x_center
, y_north
); break;
1888 case NorthEastGravity
: client
.rect
.setPos(x_east
, y_north
); break;
1889 case SouthWestGravity
: client
.rect
.setPos(x_west
, y_south
); break;
1890 case SouthGravity
: client
.rect
.setPos(x_center
, y_south
); break;
1891 case SouthEastGravity
: client
.rect
.setPos(x_east
, y_south
); break;
1892 case WestGravity
: client
.rect
.setPos(x_west
, y_center
); break;
1893 case CenterGravity
: client
.rect
.setPos(x_center
, y_center
); break;
1894 case EastGravity
: client
.rect
.setPos(x_east
, y_center
); break;
1898 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1899 frame
.rect
.top() + frame
.margin
.top
);
1905 void BlackboxWindow::redrawLabel(void) {
1906 if (flags
.focused
) {
1908 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1909 frame
.label
, frame
.flabel
);
1911 XSetWindowBackground(blackbox
->getXDisplay(),
1912 frame
.label
, frame
.flabel_pixel
);
1915 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1916 frame
.label
, frame
.ulabel
);
1918 XSetWindowBackground(blackbox
->getXDisplay(),
1919 frame
.label
, frame
.ulabel_pixel
);
1921 XClearWindow(blackbox
->getXDisplay(), frame
.label
);
1923 WindowStyle
*style
= screen
->getWindowStyle();
1925 int pos
= frame
.bevel_w
* 2,
1926 dlen
= style
->doJustify(client
.title
.c_str(), pos
, frame
.label_w
,
1927 frame
.bevel_w
* 4, i18n
.multibyte());
1929 BPen
pen((flags
.focused
) ? style
->l_text_focus
: style
->l_text_unfocus
,
1931 if (i18n
.multibyte())
1932 XmbDrawString(blackbox
->getXDisplay(), frame
.label
, style
->fontset
,
1934 (1 - style
->fontset_extents
->max_ink_extent
.y
),
1935 client
.title
.c_str(), dlen
);
1937 XDrawString(blackbox
->getXDisplay(), frame
.label
, pen
.gc(), pos
,
1938 (style
->font
->ascent
+ 1), client
.title
.c_str(), dlen
);
1942 void BlackboxWindow::redrawAllButtons(void) {
1943 if (frame
.iconify_button
) redrawIconifyButton(False
);
1944 if (frame
.maximize_button
) redrawMaximizeButton(flags
.maximized
);
1945 if (frame
.close_button
) redrawCloseButton(False
);
1949 void BlackboxWindow::redrawIconifyButton(bool pressed
) {
1951 if (flags
.focused
) {
1953 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1954 frame
.iconify_button
, frame
.fbutton
);
1956 XSetWindowBackground(blackbox
->getXDisplay(),
1957 frame
.iconify_button
, frame
.fbutton_pixel
);
1960 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1961 frame
.iconify_button
, frame
.ubutton
);
1963 XSetWindowBackground(blackbox
->getXDisplay(), frame
.iconify_button
,
1964 frame
.ubutton_pixel
);
1968 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1969 frame
.iconify_button
, frame
.pbutton
);
1971 XSetWindowBackground(blackbox
->getXDisplay(),
1972 frame
.iconify_button
, frame
.pbutton_pixel
);
1974 XClearWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
1976 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
1977 screen
->getWindowStyle()->b_pic_unfocus
);
1978 XDrawRectangle(blackbox
->getXDisplay(), frame
.iconify_button
, pen
.gc(),
1979 2, (frame
.button_w
- 5), (frame
.button_w
- 5), 2);
1983 void BlackboxWindow::redrawMaximizeButton(bool pressed
) {
1985 if (flags
.focused
) {
1987 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1988 frame
.maximize_button
, frame
.fbutton
);
1990 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
1991 frame
.fbutton_pixel
);
1994 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1995 frame
.maximize_button
, frame
.ubutton
);
1997 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
1998 frame
.ubutton_pixel
);
2002 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2003 frame
.maximize_button
, frame
.pbutton
);
2005 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2006 frame
.pbutton_pixel
);
2008 XClearWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
2010 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2011 screen
->getWindowStyle()->b_pic_unfocus
);
2012 XDrawRectangle(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2013 2, 2, (frame
.button_w
- 5), (frame
.button_w
- 5));
2014 XDrawLine(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2015 2, 3, (frame
.button_w
- 3), 3);
2019 void BlackboxWindow::redrawCloseButton(bool pressed
) {
2021 if (flags
.focused
) {
2023 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2026 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2027 frame
.fbutton_pixel
);
2030 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2033 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2034 frame
.ubutton_pixel
);
2038 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2039 frame
.close_button
, frame
.pbutton
);
2041 XSetWindowBackground(blackbox
->getXDisplay(),
2042 frame
.close_button
, frame
.pbutton_pixel
);
2044 XClearWindow(blackbox
->getXDisplay(), frame
.close_button
);
2046 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2047 screen
->getWindowStyle()->b_pic_unfocus
);
2048 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2049 2, 2, (frame
.button_w
- 3), (frame
.button_w
- 3));
2050 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2051 2, (frame
.button_w
- 3), (frame
.button_w
- 3), 2);
2055 void BlackboxWindow::mapRequestEvent(XMapRequestEvent
*re
) {
2056 if (re
->window
!= client
.window
)
2060 fprintf(stderr
, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2064 bool get_state_ret
= getState();
2065 if (! (get_state_ret
&& blackbox
->isStartup())) {
2066 if ((client
.wm_hint_flags
& StateHint
) &&
2067 (! (current_state
== NormalState
|| current_state
== IconicState
)))
2068 current_state
= client
.initial_state
;
2070 current_state
= NormalState
;
2071 } else if (flags
.iconic
) {
2072 current_state
= NormalState
;
2075 switch (current_state
) {
2080 case WithdrawnState
:
2089 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2090 if (! blackbox
->isStartup() && (isTransient() || screen
->doFocusNew())) {
2091 XSync(blackbox
->getXDisplay(), False
); // make sure the frame is mapped..
2099 void BlackboxWindow::unmapNotifyEvent(XUnmapEvent
*ue
) {
2100 if (ue
->window
!= client
.window
)
2104 fprintf(stderr
, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2108 screen
->unmanageWindow(this, False
);
2112 void BlackboxWindow::destroyNotifyEvent(XDestroyWindowEvent
*de
) {
2113 if (de
->window
!= client
.window
)
2117 fprintf(stderr
, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2121 screen
->unmanageWindow(this, False
);
2125 void BlackboxWindow::reparentNotifyEvent(XReparentEvent
*re
) {
2126 if (re
->window
!= client
.window
|| re
->parent
== frame
.plate
)
2130 fprintf(stderr
, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2131 "0x%lx.\n", client
.window
, re
->parent
);
2136 XPutBackEvent(blackbox
->getXDisplay(), &ev
);
2137 screen
->unmanageWindow(this, True
);
2141 void BlackboxWindow::propertyNotifyEvent(Atom atom
) {
2144 case XA_WM_CLIENT_MACHINE
:
2148 case XA_WM_TRANSIENT_FOR
: {
2149 // determine if this is a transient window
2152 // adjust the window decorations based on transience
2153 if (isTransient()) {
2154 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2155 functions
&= ~Func_Maximize
;
2166 case XA_WM_ICON_NAME
:
2168 if (flags
.iconic
) screen
->propagateWindowName(this);
2174 if (decorations
& Decor_Titlebar
)
2177 screen
->propagateWindowName(this);
2180 case XA_WM_NORMAL_HINTS
: {
2183 if ((client
.normal_hint_flags
& PMinSize
) &&
2184 (client
.normal_hint_flags
& PMaxSize
)) {
2185 if (client
.max_width
<= client
.min_width
&&
2186 client
.max_height
<= client
.min_height
) {
2187 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2188 functions
&= ~(Func_Resize
| Func_Maximize
);
2190 decorations
|= Decor_Maximize
| Decor_Handle
;
2191 functions
|= Func_Resize
| Func_Maximize
;
2195 Rect old_rect
= frame
.rect
;
2199 if (old_rect
!= frame
.rect
)
2206 if (atom
== blackbox
->getWMProtocolsAtom()) {
2209 if ((decorations
& Decor_Close
) && (! frame
.close_button
)) {
2210 createCloseButton();
2211 if (decorations
& Decor_Titlebar
) {
2212 positionButtons(True
);
2213 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
2215 if (windowmenu
) windowmenu
->reconfigure();
2224 void BlackboxWindow::exposeEvent(XExposeEvent
*ee
) {
2225 if (frame
.label
== ee
->window
&& (decorations
& Decor_Titlebar
))
2227 else if (frame
.close_button
== ee
->window
)
2228 redrawCloseButton(False
);
2229 else if (frame
.maximize_button
== ee
->window
)
2230 redrawMaximizeButton(flags
.maximized
);
2231 else if (frame
.iconify_button
== ee
->window
)
2232 redrawIconifyButton(False
);
2236 void BlackboxWindow::configureRequestEvent(XConfigureRequestEvent
*cr
) {
2237 if (cr
->window
!= client
.window
|| flags
.iconic
)
2240 int cx
= frame
.rect
.x(), cy
= frame
.rect
.y();
2241 unsigned int cw
= frame
.rect
.width(), ch
= frame
.rect
.height();
2243 if (cr
->value_mask
& CWBorderWidth
)
2244 client
.old_bw
= cr
->border_width
;
2246 if (cr
->value_mask
& CWX
)
2247 cx
= cr
->x
- frame
.margin
.left
;
2249 if (cr
->value_mask
& CWY
)
2250 cy
= cr
->y
- frame
.margin
.top
;
2252 if (cr
->value_mask
& CWWidth
)
2253 cw
= cr
->width
+ frame
.margin
.left
+ frame
.margin
.right
;
2255 if (cr
->value_mask
& CWHeight
)
2256 ch
= cr
->height
+ frame
.margin
.top
+ frame
.margin
.bottom
;
2258 if (frame
.rect
!= Rect(cx
, cy
, cw
, ch
))
2259 configure(cx
, cy
, cw
, ch
);
2261 if (cr
->value_mask
& CWStackMode
) {
2262 switch (cr
->detail
) {
2265 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2271 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2278 void BlackboxWindow::buttonPressEvent(XButtonEvent
*be
) {
2279 if (frame
.maximize_button
== be
->window
) {
2280 redrawMaximizeButton(True
);
2281 } else if (be
->button
== 1 || (be
->button
== 3 && be
->state
== Mod1Mask
)) {
2282 if (! flags
.focused
)
2285 if (frame
.iconify_button
== be
->window
) {
2286 redrawIconifyButton(True
);
2287 } else if (frame
.close_button
== be
->window
) {
2288 redrawCloseButton(True
);
2289 } else if (frame
.plate
== be
->window
) {
2290 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2292 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2294 XAllowEvents(blackbox
->getXDisplay(), ReplayPointer
, be
->time
);
2296 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
2297 if (((be
->time
- lastButtonPressTime
) <=
2298 blackbox
->getDoubleClickInterval()) ||
2299 (be
->state
& ControlMask
)) {
2300 lastButtonPressTime
= 0;
2303 lastButtonPressTime
= be
->time
;
2307 frame
.grab_x
= be
->x_root
- frame
.rect
.x() - frame
.border_w
;
2308 frame
.grab_y
= be
->y_root
- frame
.rect
.y() - frame
.border_w
;
2310 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2312 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2314 } else if (be
->button
== 2 && (be
->window
!= frame
.iconify_button
) &&
2315 (be
->window
!= frame
.close_button
)) {
2316 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2317 } else if (windowmenu
&& be
->button
== 3 &&
2318 (frame
.title
== be
->window
|| frame
.label
== be
->window
||
2319 frame
.handle
== be
->window
|| frame
.window
== be
->window
)) {
2322 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
2323 mx
= be
->x_root
- (windowmenu
->getWidth() / 2);
2324 my
= frame
.rect
.y() + frame
.title_h
+ frame
.border_w
;
2325 } else if (frame
.handle
== be
->window
) {
2326 mx
= be
->x_root
- (windowmenu
->getWidth() / 2);
2327 my
= frame
.rect
.bottom() - frame
.handle_h
- (frame
.border_w
* 3) -
2328 windowmenu
->getHeight();
2330 mx
= be
->x_root
- (windowmenu
->getWidth() / 2);
2332 if (be
->y
<= static_cast<signed>(frame
.bevel_w
))
2333 my
= frame
.rect
.y() + frame
.title_h
;
2335 my
= be
->y_root
- (windowmenu
->getHeight() / 2);
2338 // snap the window menu into a corner if necessary - we check the
2339 // position of the menu with the coordinates of the client to
2340 // make the comparisions easier.
2341 // ### this needs some work!
2342 if (mx
> client
.rect
.right() -
2343 static_cast<signed>(windowmenu
->getWidth()))
2344 mx
= frame
.rect
.right() - windowmenu
->getWidth() - frame
.border_w
+ 1;
2345 if (mx
< client
.rect
.left())
2346 mx
= frame
.rect
.x();
2348 if (my
> client
.rect
.bottom() -
2349 static_cast<signed>(windowmenu
->getHeight()))
2350 my
= frame
.rect
.bottom() - windowmenu
->getHeight() - frame
.border_w
+ 1;
2351 if (my
< client
.rect
.top())
2352 my
= frame
.rect
.y() + ((decorations
& Decor_Titlebar
) ?
2356 if (! windowmenu
->isVisible()) {
2357 windowmenu
->move(mx
, my
);
2359 XRaiseWindow(blackbox
->getXDisplay(), windowmenu
->getWindowID());
2360 XRaiseWindow(blackbox
->getXDisplay(),
2361 windowmenu
->getSendToMenu()->getWindowID());
2370 void BlackboxWindow::buttonReleaseEvent(XButtonEvent
*re
) {
2371 if (re
->window
== frame
.maximize_button
) {
2372 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2373 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2374 maximize(re
->button
);
2376 redrawMaximizeButton(flags
.maximized
);
2378 } else if (re
->window
== frame
.iconify_button
) {
2379 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2380 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2383 redrawIconifyButton(False
);
2385 } else if (re
->window
== frame
.close_button
) {
2386 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2387 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
)))
2389 redrawCloseButton(False
);
2390 } else if (flags
.moving
) {
2391 flags
.moving
= False
;
2393 if (! screen
->doOpaqueMove()) {
2394 /* when drawing the rubber band, we need to make sure we only draw inside
2395 * the frame... frame.changing_* contain the new coords for the window,
2396 * so we need to subtract 1 from changing_w/changing_h every where we
2397 * draw the rubber band (for both moving and resizing)
2399 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2400 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
2401 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
2402 XUngrabServer(blackbox
->getXDisplay());
2404 configure(frame
.changing
.x(), frame
.changing
.y(),
2405 frame
.changing
.width(), frame
.changing
.height());
2407 configure(frame
.rect
.x(), frame
.rect
.y(),
2408 frame
.rect
.width(), frame
.rect
.height());
2410 screen
->hideGeometry();
2411 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
2412 } else if (flags
.resizing
) {
2413 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2414 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
2415 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
2416 XUngrabServer(blackbox
->getXDisplay());
2418 screen
->hideGeometry();
2420 constrain((re
->window
== frame
.left_grip
) ? TopRight
: TopLeft
);
2422 // unset maximized state when resized after fully maximized
2423 if (flags
.maximized
== 1)
2425 flags
.resizing
= False
;
2426 configure(frame
.changing
.x(), frame
.changing
.y(),
2427 frame
.changing
.width(), frame
.changing
.height());
2429 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
2430 } else if (re
->window
== frame
.window
) {
2431 if (re
->button
== 2 && re
->state
== Mod1Mask
)
2432 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
2437 void BlackboxWindow::motionNotifyEvent(XMotionEvent
*me
) {
2438 if (! flags
.resizing
&& (me
->state
& Button1Mask
) &&
2439 (functions
& Func_Move
) &&
2440 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
2441 frame
.handle
== me
->window
|| frame
.window
== me
->window
)) {
2442 if (! flags
.moving
) {
2443 XGrabPointer(blackbox
->getXDisplay(), me
->window
, False
,
2444 Button1MotionMask
| ButtonReleaseMask
,
2445 GrabModeAsync
, GrabModeAsync
,
2446 None
, blackbox
->getMoveCursor(), CurrentTime
);
2448 if (windowmenu
&& windowmenu
->isVisible())
2451 flags
.moving
= True
;
2453 if (! screen
->doOpaqueMove()) {
2454 XGrabServer(blackbox
->getXDisplay());
2456 frame
.changing
= frame
.rect
;
2457 screen
->showPosition(frame
.changing
.x(), frame
.changing
.y());
2459 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2463 frame
.changing
.width() - 1,
2464 frame
.changing
.height() - 1);
2467 int dx
= me
->x_root
- frame
.grab_x
, dy
= me
->y_root
- frame
.grab_y
;
2468 dx
-= frame
.border_w
;
2469 dy
-= frame
.border_w
;
2471 const int snap_distance
= screen
->getEdgeSnapThreshold();
2473 if (snap_distance
) {
2474 Rect srect
= screen
->availableArea();
2476 const int wleft
= dx
,
2477 wright
= dx
+ frame
.rect
.width() - 1,
2479 wbottom
= dy
+ frame
.rect
.height() - 1;
2481 int dleft
= std::abs(wleft
- srect
.left()),
2482 dright
= std::abs(wright
- srect
.right()),
2483 dtop
= std::abs(wtop
- srect
.top()),
2484 dbottom
= std::abs(wbottom
- srect
.bottom());
2487 if (dleft
< snap_distance
&& dleft
< dright
)
2490 else if (dright
< snap_distance
&& dright
< dleft
)
2491 dx
= srect
.right() - frame
.rect
.width() + 1;
2494 if (dtop
< snap_distance
&& dtop
< dbottom
)
2497 else if (dbottom
< snap_distance
&& dbottom
< dtop
)
2498 dy
= srect
.bottom() - frame
.rect
.height() + 1;
2500 srect
= screen
->getRect(); // now get the full screen
2502 dleft
= std::abs(wleft
- srect
.left()),
2503 dright
= std::abs(wright
- srect
.right()),
2504 dtop
= std::abs(wtop
- srect
.top()),
2505 dbottom
= std::abs(wbottom
- srect
.bottom());
2508 if (dleft
< snap_distance
&& dleft
< dright
)
2511 else if (dright
< snap_distance
&& dright
< dleft
)
2512 dx
= srect
.right() - frame
.rect
.width() + 1;
2515 if (dtop
< snap_distance
&& dtop
< dbottom
)
2518 else if (dbottom
< snap_distance
&& dbottom
< dtop
)
2519 dy
= srect
.bottom() - frame
.rect
.height() + 1;
2522 if (screen
->doOpaqueMove()) {
2523 configure(dx
, dy
, frame
.rect
.width(), frame
.rect
.height());
2525 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2529 frame
.changing
.width() - 1,
2530 frame
.changing
.height() - 1);
2532 frame
.changing
.setPos(dx
, dy
);
2534 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2538 frame
.changing
.width() - 1,
2539 frame
.changing
.height() - 1);
2542 screen
->showPosition(dx
, dy
);
2544 } else if ((functions
& Func_Resize
) &&
2545 (((me
->state
& Button1Mask
) &&
2546 (me
->window
== frame
.right_grip
||
2547 me
->window
== frame
.left_grip
)) ||
2548 (me
->state
& (Mod1Mask
| Button3Mask
) &&
2549 me
->window
== frame
.window
))) {
2550 bool left
= (me
->window
== frame
.left_grip
);
2552 if (! flags
.resizing
) {
2553 XGrabServer(blackbox
->getXDisplay());
2554 XGrabPointer(blackbox
->getXDisplay(), me
->window
, False
,
2555 ButtonMotionMask
| ButtonReleaseMask
,
2556 GrabModeAsync
, GrabModeAsync
, None
,
2557 ((left
) ? blackbox
->getLowerLeftAngleCursor() :
2558 blackbox
->getLowerRightAngleCursor()),
2561 flags
.resizing
= True
;
2564 frame
.grab_x
= me
->x
;
2565 frame
.grab_y
= me
->y
;
2566 frame
.changing
= frame
.rect
;
2568 constrain((left
) ? TopRight
: TopLeft
, &gw
, &gh
);
2570 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2571 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
2572 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
2574 screen
->showGeometry(gw
, gh
);
2576 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2577 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
2578 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
2586 frame
.changing
.setCoords(me
->x_root
- frame
.grab_x
, frame
.rect
.top(),
2587 frame
.rect
.right(), frame
.rect
.bottom());
2588 frame
.changing
.setHeight(frame
.rect
.height() + (me
->y
- frame
.grab_y
));
2591 frame
.changing
.setSize(frame
.rect
.width() + (me
->x
- frame
.grab_x
),
2592 frame
.rect
.height() + (me
->y
- frame
.grab_y
));
2595 constrain(anchor
, &gw
, &gh
);
2597 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2598 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
2599 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
2601 screen
->showGeometry(gw
, gh
);
2608 void BlackboxWindow::shapeEvent(XShapeEvent
*) {
2609 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
2616 bool BlackboxWindow::validateClient(void) {
2617 XSync(blackbox
->getXDisplay(), False
);
2620 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
2621 DestroyNotify
, &e
) ||
2622 XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
2624 XPutBackEvent(blackbox
->getXDisplay(), &e
);
2633 void BlackboxWindow::restore(bool remap
) {
2634 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeDelete
);
2635 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
2636 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, NoEventMask
);
2640 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
2641 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
2643 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, client
.old_bw
);
2646 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
2647 ReparentNotify
, &ev
)) {
2650 // according to the ICCCM - if the client doesn't reparent to
2651 // root, then we have to do it for them
2652 XReparentWindow(blackbox
->getXDisplay(), client
.window
,
2653 screen
->getRootWindow(),
2654 client
.rect
.x(), client
.rect
.y());
2657 if (remap
) XMapWindow(blackbox
->getXDisplay(), client
.window
);
2661 // timer for autoraise
2662 void BlackboxWindow::timeout(void) {
2663 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2667 void BlackboxWindow::changeBlackboxHints(BlackboxHints
*net
) {
2668 if ((net
->flags
& AttribShaded
) &&
2669 ((blackbox_attrib
.attrib
& AttribShaded
) !=
2670 (net
->attrib
& AttribShaded
)))
2673 if (flags
.visible
&& // watch out for requests when we can not be seen
2674 (net
->flags
& (AttribMaxVert
| AttribMaxHoriz
)) &&
2675 ((blackbox_attrib
.attrib
& (AttribMaxVert
| AttribMaxHoriz
)) !=
2676 (net
->attrib
& (AttribMaxVert
| AttribMaxHoriz
)))) {
2677 if (flags
.maximized
) {
2682 if ((net
->flags
& AttribMaxHoriz
) && (net
->flags
& AttribMaxVert
))
2683 button
= ((net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0);
2684 else if (net
->flags
& AttribMaxVert
)
2685 button
= ((net
->attrib
& AttribMaxVert
) ? 2 : 0);
2686 else if (net
->flags
& AttribMaxHoriz
)
2687 button
= ((net
->attrib
& AttribMaxHoriz
) ? 3 : 0);
2693 if ((net
->flags
& AttribOmnipresent
) &&
2694 ((blackbox_attrib
.attrib
& AttribOmnipresent
) !=
2695 (net
->attrib
& AttribOmnipresent
)))
2698 if ((net
->flags
& AttribWorkspace
) &&
2699 (blackbox_attrib
.workspace
!= net
->workspace
)) {
2700 screen
->reassociateWindow(this, net
->workspace
, True
);
2702 if (screen
->getCurrentWorkspaceID() != net
->workspace
) {
2706 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2710 if (net
->flags
& AttribDecoration
) {
2711 switch (net
->decoration
) {
2713 // clear all decorations except close
2714 decorations
&= Decor_Close
;
2720 decorations
|= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
2721 Decor_Iconify
| Decor_Maximize
;
2726 decorations
|= Decor_Titlebar
| Decor_Iconify
;
2727 decorations
&= ~(Decor_Border
| Decor_Handle
| Decor_Maximize
);
2732 decorations
|= Decor_Titlebar
;
2733 decorations
&= ~(Decor_Iconify
| Decor_Border
| Decor_Handle
);
2734 functions
|= Func_Move
;
2739 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
2740 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
2744 setState(current_state
);
2750 * Set the sizes of all components of the window frame
2751 * (the window decorations).
2752 * These values are based upon the current style settings and the client
2753 * window's dimensions.
2755 void BlackboxWindow::upsize(void) {
2756 frame
.bevel_w
= screen
->getBevelWidth();
2758 if (decorations
& Decor_Border
) {
2759 frame
.border_w
= screen
->getBorderWidth();
2760 if (! isTransient())
2761 frame
.mwm_border_w
= screen
->getFrameWidth();
2763 frame
.mwm_border_w
= 0;
2765 frame
.mwm_border_w
= frame
.border_w
= 0;
2768 if (decorations
& Decor_Titlebar
) {
2769 // the height of the titlebar is based upon the height of the font being
2770 // used to display the window's title
2771 WindowStyle
*style
= screen
->getWindowStyle();
2772 if (i18n
.multibyte())
2773 frame
.title_h
= (style
->fontset_extents
->max_ink_extent
.height
+
2774 (frame
.bevel_w
* 2) + 2);
2776 frame
.title_h
= (style
->font
->ascent
+ style
->font
->descent
+
2777 (frame
.bevel_w
* 2) + 2);
2779 frame
.label_h
= frame
.title_h
- (frame
.bevel_w
* 2);
2780 frame
.button_w
= (frame
.label_h
- 2);
2782 // set the top frame margin
2783 frame
.margin
.top
= frame
.border_w
+ frame
.title_h
+
2784 frame
.border_w
+ frame
.mwm_border_w
;
2790 // set the top frame margin
2791 frame
.margin
.top
= frame
.border_w
+ frame
.mwm_border_w
;
2794 // set the left/right frame margin
2795 frame
.margin
.left
= frame
.margin
.right
= frame
.border_w
+ frame
.mwm_border_w
;
2797 if (decorations
& Decor_Handle
) {
2798 frame
.grip_w
= frame
.button_w
* 2;
2799 frame
.handle_h
= screen
->getHandleWidth();
2801 // set the bottom frame margin
2802 frame
.margin
.bottom
= frame
.border_w
+ frame
.handle_h
+
2803 frame
.border_w
+ frame
.mwm_border_w
;
2808 // set the bottom frame margin
2809 frame
.margin
.bottom
= frame
.border_w
+ frame
.mwm_border_w
;
2812 // set the frame rect
2813 frame
.rect
.setSize(client
.rect
.width() + frame
.margin
.left
+
2815 client
.rect
.height() + frame
.margin
.top
+
2816 frame
.margin
.bottom
);
2817 frame
.inside_w
= frame
.rect
.width() - (frame
.border_w
* 2);
2818 frame
.inside_h
= frame
.rect
.height() - (frame
.border_w
* 2);
2823 * Calculate the size of the client window and constrain it to the
2824 * size specified by the size hints of the client window.
2826 * The logical width and height are placed into pw and ph, if they
2827 * are non-zero. Logical size refers to the users perception of
2828 * the window size (for example an xterm has resizes in cells, not in
2831 * The physical geometry is placed into frame.changing_{x,y,width,height}.
2832 * Physical geometry refers to the geometry of the window in pixels.
2834 void BlackboxWindow::constrain(Corner anchor
, int *pw
, int *ph
) {
2835 // frame.changing represents the requested frame size, we need to
2836 // strip the frame margin off and constrain the client size
2837 frame
.changing
.setCoords(frame
.changing
.left() + frame
.margin
.left
,
2838 frame
.changing
.top() + frame
.margin
.top
,
2839 frame
.changing
.right() - frame
.margin
.right
,
2840 frame
.changing
.bottom() - frame
.margin
.bottom
);
2842 int dw
= frame
.changing
.width(), dh
= frame
.changing
.height(),
2843 base_width
= (client
.base_width
) ? client
.base_width
: client
.min_width
,
2844 base_height
= (client
.base_height
) ? client
.base_height
:
2848 if (dw
< static_cast<signed>(client
.min_width
)) dw
= client
.min_width
;
2849 if (dh
< static_cast<signed>(client
.min_height
)) dh
= client
.min_height
;
2850 if (dw
> static_cast<signed>(client
.max_width
)) dw
= client
.max_width
;
2851 if (dh
> static_cast<signed>(client
.max_height
)) dh
= client
.max_height
;
2854 dw
/= client
.width_inc
;
2856 dh
/= client
.height_inc
;
2861 dw
*= client
.width_inc
;
2863 dh
*= client
.height_inc
;
2866 frame
.changing
.setSize(dw
, dh
);
2868 // add the frame margin back onto frame.changing
2869 frame
.changing
.setCoords(frame
.changing
.left() - frame
.margin
.left
,
2870 frame
.changing
.top() - frame
.margin
.top
,
2871 frame
.changing
.right() + frame
.margin
.right
,
2872 frame
.changing
.bottom() + frame
.margin
.bottom
);
2874 // move frame.changing to the specified anchor
2881 int dx
= frame
.rect
.right() - frame
.changing
.right();
2882 frame
.changing
.setPos(frame
.changing
.x() + dx
, frame
.changing
.y());
2888 int WindowStyle::doJustify(const char *text
, int &start_pos
,
2889 unsigned int max_length
, unsigned int modifier
,
2890 bool multibyte
) const {
2891 size_t text_len
= strlen(text
);
2892 unsigned int length
;
2896 XRectangle ink
, logical
;
2897 XmbTextExtents(fontset
, text
, text_len
, &ink
, &logical
);
2898 length
= logical
.width
;
2900 length
= XTextWidth(font
, text
, text_len
);
2903 } while (length
> max_length
&& text_len
-- > 0);
2907 start_pos
+= max_length
- length
;
2911 start_pos
+= (max_length
- length
) / 2;
2923 BWindowGroup::BWindowGroup(Blackbox
*b
, Window _group
)
2924 : blackbox(b
), group(_group
) {
2925 // watch for destroy notify on the group window
2926 XSelectInput(blackbox
->getXDisplay(), group
, StructureNotifyMask
);
2927 blackbox
->saveGroupSearch(group
, this);
2931 BWindowGroup::~BWindowGroup(void) {
2932 blackbox
->removeGroupSearch(group
);
2937 BWindowGroup::find(BScreen
*screen
, bool allow_transients
) const {
2938 BlackboxWindow
*ret
= blackbox
->getFocusedWindow();
2940 // does the focus window match (or any transient_fors)?
2942 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
2943 if (ret
->isTransient() && allow_transients
) break;
2944 else if (! ret
->isTransient()) break;
2947 ret
= ret
->getTransientFor();
2950 if (ret
) return ret
;
2952 // the focus window didn't match, look in the group's window list
2953 BlackboxWindowList::const_iterator it
, end
= windowList
.end();
2954 for (it
= windowList
.begin(); it
!= end
; ++it
) {
2956 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
2957 if (ret
->isTransient() && allow_transients
) break;
2958 else if (! ret
->isTransient()) break;