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
);
1445 // when a resize is begun, maximize(0) is called to clear any maximization
1446 // flags currently set. Otherwise it still thinks it is maximized.
1447 // so we do not need to call configure() because resizing will handle it
1448 if (!flags
.resizing
)
1449 configure(blackbox_attrib
.premax_x
, blackbox_attrib
.premax_y
,
1450 blackbox_attrib
.premax_w
, blackbox_attrib
.premax_h
);
1452 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
1453 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
1456 setState(current_state
);
1460 blackbox_attrib
.premax_x
= frame
.rect
.x();
1461 blackbox_attrib
.premax_y
= frame
.rect
.y();
1462 blackbox_attrib
.premax_w
= frame
.rect
.width();
1463 blackbox_attrib
.premax_h
= frame
.rect
.height();
1465 const Rect
&screen_area
= screen
->availableArea();
1466 frame
.changing
= screen_area
;
1471 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1472 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1476 blackbox_attrib
.flags
|= AttribMaxVert
;
1477 blackbox_attrib
.attrib
|= AttribMaxVert
;
1479 frame
.changing
.setX(frame
.rect
.x());
1480 frame
.changing
.setWidth(frame
.rect
.width());
1484 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1485 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1487 frame
.changing
.setY(frame
.rect
.y());
1488 frame
.changing
.setHeight(frame
.rect
.height());
1493 blackbox_attrib
.flags
^= AttribShaded
;
1494 blackbox_attrib
.attrib
^= AttribShaded
;
1495 flags
.shaded
= False
;
1498 flags
.maximized
= button
;
1500 configure(frame
.changing
.x(), frame
.changing
.y(),
1501 frame
.changing
.width(), frame
.changing
.height());
1502 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1504 setState(current_state
);
1508 // re-maximizes the window to take into account availableArea changes
1509 void BlackboxWindow::remaximize(void) {
1510 // save the original dimensions because maximize will wipe them out
1511 int premax_x
= blackbox_attrib
.premax_x
,
1512 premax_y
= blackbox_attrib
.premax_y
,
1513 premax_w
= blackbox_attrib
.premax_w
,
1514 premax_h
= blackbox_attrib
.premax_h
;
1516 unsigned int button
= flags
.maximized
;
1517 flags
.maximized
= 0; // trick maximize() into working
1520 // restore saved values
1521 blackbox_attrib
.premax_x
= premax_x
;
1522 blackbox_attrib
.premax_y
= premax_y
;
1523 blackbox_attrib
.premax_w
= premax_w
;
1524 blackbox_attrib
.premax_h
= premax_h
;
1528 void BlackboxWindow::setWorkspace(unsigned int n
) {
1529 blackbox_attrib
.flags
|= AttribWorkspace
;
1530 blackbox_attrib
.workspace
= n
;
1534 void BlackboxWindow::shade(void) {
1535 if (! (decorations
& Decor_Titlebar
))
1539 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1540 frame
.inside_w
, frame
.inside_h
);
1541 flags
.shaded
= False
;
1542 blackbox_attrib
.flags
^= AttribShaded
;
1543 blackbox_attrib
.attrib
^= AttribShaded
;
1545 setState(NormalState
);
1547 // set the frame rect to the normal size
1548 frame
.rect
.setHeight(client
.rect
.height() + frame
.margin
.top
+
1549 frame
.margin
.bottom
);
1551 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1552 frame
.inside_w
, frame
.title_h
);
1553 flags
.shaded
= True
;
1554 blackbox_attrib
.flags
|= AttribShaded
;
1555 blackbox_attrib
.attrib
|= AttribShaded
;
1557 setState(IconicState
);
1559 // set the frame rect to the shaded size
1560 frame
.rect
.setHeight(frame
.title_h
+ (frame
.border_w
* 2));
1565 void BlackboxWindow::stick(void) {
1567 blackbox_attrib
.flags
^= AttribOmnipresent
;
1568 blackbox_attrib
.attrib
^= AttribOmnipresent
;
1570 flags
.stuck
= False
;
1573 screen
->reassociateWindow(this, BSENTINEL
, True
);
1575 setState(current_state
);
1579 blackbox_attrib
.flags
|= AttribOmnipresent
;
1580 blackbox_attrib
.attrib
|= AttribOmnipresent
;
1582 setState(current_state
);
1587 void BlackboxWindow::setFocusFlag(bool focus
) {
1588 flags
.focused
= focus
;
1590 if (decorations
& Decor_Titlebar
) {
1591 if (flags
.focused
) {
1593 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1594 frame
.title
, frame
.ftitle
);
1596 XSetWindowBackground(blackbox
->getXDisplay(),
1597 frame
.title
, frame
.ftitle_pixel
);
1600 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1601 frame
.title
, frame
.utitle
);
1603 XSetWindowBackground(blackbox
->getXDisplay(),
1604 frame
.title
, frame
.utitle_pixel
);
1606 XClearWindow(blackbox
->getXDisplay(), frame
.title
);
1612 if (decorations
& Decor_Handle
) {
1613 if (flags
.focused
) {
1615 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1616 frame
.handle
, frame
.fhandle
);
1618 XSetWindowBackground(blackbox
->getXDisplay(),
1619 frame
.handle
, frame
.fhandle_pixel
);
1622 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1623 frame
.left_grip
, frame
.fgrip
);
1624 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1625 frame
.right_grip
, frame
.fgrip
);
1627 XSetWindowBackground(blackbox
->getXDisplay(),
1628 frame
.left_grip
, frame
.fgrip_pixel
);
1629 XSetWindowBackground(blackbox
->getXDisplay(),
1630 frame
.right_grip
, frame
.fgrip_pixel
);
1634 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1635 frame
.handle
, frame
.uhandle
);
1637 XSetWindowBackground(blackbox
->getXDisplay(),
1638 frame
.handle
, frame
.uhandle_pixel
);
1641 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1642 frame
.left_grip
, frame
.ugrip
);
1643 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1644 frame
.right_grip
, frame
.ugrip
);
1646 XSetWindowBackground(blackbox
->getXDisplay(),
1647 frame
.left_grip
, frame
.ugrip_pixel
);
1648 XSetWindowBackground(blackbox
->getXDisplay(),
1649 frame
.right_grip
, frame
.ugrip_pixel
);
1652 XClearWindow(blackbox
->getXDisplay(), frame
.handle
);
1653 XClearWindow(blackbox
->getXDisplay(), frame
.left_grip
);
1654 XClearWindow(blackbox
->getXDisplay(), frame
.right_grip
);
1657 if (decorations
& Decor_Border
) {
1659 XSetWindowBorder(blackbox
->getXDisplay(),
1660 frame
.plate
, frame
.fborder_pixel
);
1662 XSetWindowBorder(blackbox
->getXDisplay(),
1663 frame
.plate
, frame
.uborder_pixel
);
1666 if (screen
->isSloppyFocus() && screen
->doAutoRaise()) {
1667 if (isFocused()) timer
->start();
1672 blackbox
->setFocusedWindow(this);
1676 void BlackboxWindow::installColormap(bool install
) {
1677 int i
= 0, ncmap
= 0;
1678 Colormap
*cmaps
= XListInstalledColormaps(blackbox
->getXDisplay(),
1679 client
.window
, &ncmap
);
1680 XWindowAttributes wattrib
;
1682 if (XGetWindowAttributes(blackbox
->getXDisplay(),
1683 client
.window
, &wattrib
)) {
1685 // install the window's colormap
1686 for (i
= 0; i
< ncmap
; i
++) {
1687 if (*(cmaps
+ i
) == wattrib
.colormap
)
1688 // this window is using an installed color map... do not install
1691 // otherwise, install the window's colormap
1693 XInstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
1695 // uninstall the window's colormap
1696 for (i
= 0; i
< ncmap
; i
++) {
1697 if (*(cmaps
+ i
) == wattrib
.colormap
)
1698 // we found the colormap to uninstall
1699 XUninstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
1709 void BlackboxWindow::setState(unsigned long new_state
) {
1710 current_state
= new_state
;
1712 unsigned long state
[2];
1713 state
[0] = current_state
;
1715 XChangeProperty(blackbox
->getXDisplay(), client
.window
,
1716 blackbox
->getWMStateAtom(), blackbox
->getWMStateAtom(), 32,
1717 PropModeReplace
, (unsigned char *) state
, 2);
1719 XChangeProperty(blackbox
->getXDisplay(), client
.window
,
1720 blackbox
->getBlackboxAttributesAtom(),
1721 blackbox
->getBlackboxAttributesAtom(), 32, PropModeReplace
,
1722 (unsigned char *) &blackbox_attrib
,
1723 PropBlackboxAttributesElements
);
1727 bool BlackboxWindow::getState(void) {
1733 unsigned long *state
, ulfoo
, nitems
;
1735 if ((XGetWindowProperty(blackbox
->getXDisplay(), client
.window
,
1736 blackbox
->getWMStateAtom(),
1737 0l, 2l, False
, blackbox
->getWMStateAtom(),
1738 &atom_return
, &foo
, &nitems
, &ulfoo
,
1739 (unsigned char **) &state
) != Success
) ||
1745 current_state
= static_cast<unsigned long>(state
[0]);
1750 XFree((void *) state
);
1756 void BlackboxWindow::restoreAttributes(void) {
1757 if (! getState()) current_state
= NormalState
;
1761 unsigned long ulfoo
, nitems
;
1763 BlackboxAttributes
*net
;
1764 int ret
= XGetWindowProperty(blackbox
->getXDisplay(), client
.window
,
1765 blackbox
->getBlackboxAttributesAtom(), 0l,
1766 PropBlackboxAttributesElements
, False
,
1767 blackbox
->getBlackboxAttributesAtom(),
1768 &atom_return
, &foo
, &nitems
, &ulfoo
,
1769 (unsigned char **) &net
);
1770 if (ret
!= Success
|| !net
|| nitems
!= PropBlackboxAttributesElements
)
1773 if (net
->flags
& AttribShaded
&&
1774 net
->attrib
& AttribShaded
) {
1776 ((current_state
== IconicState
) ? NormalState
: current_state
);
1778 flags
.shaded
= False
;
1781 current_state
= save_state
;
1784 if ((net
->workspace
!= screen
->getCurrentWorkspaceID()) &&
1785 (net
->workspace
< screen
->getWorkspaceCount())) {
1786 screen
->reassociateWindow(this, net
->workspace
, True
);
1788 if (current_state
== NormalState
) current_state
= WithdrawnState
;
1789 } else if (current_state
== WithdrawnState
) {
1790 current_state
= NormalState
;
1793 if (net
->flags
& AttribOmnipresent
&&
1794 net
->attrib
& AttribOmnipresent
) {
1795 flags
.stuck
= False
;
1798 current_state
= NormalState
;
1801 if ((net
->flags
& AttribMaxHoriz
) ||
1802 (net
->flags
& AttribMaxVert
)) {
1803 int x
= net
->premax_x
, y
= net
->premax_y
;
1804 unsigned int w
= net
->premax_w
, h
= net
->premax_h
;
1805 flags
.maximized
= 0;
1808 if ((net
->flags
& AttribMaxHoriz
) &&
1809 (net
->flags
& AttribMaxVert
))
1810 m
= (net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1811 else if (net
->flags
& AttribMaxVert
)
1812 m
= (net
->attrib
& AttribMaxVert
) ? 2 : 0;
1813 else if (net
->flags
& AttribMaxHoriz
)
1814 m
= (net
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1818 blackbox_attrib
.premax_x
= x
;
1819 blackbox_attrib
.premax_y
= y
;
1820 blackbox_attrib
.premax_w
= w
;
1821 blackbox_attrib
.premax_h
= h
;
1824 setState(current_state
);
1826 XFree((void *) net
);
1831 * Positions the frame according the the client window position and window
1834 void BlackboxWindow::setGravityOffsets(void) {
1835 // x coordinates for each gravity type
1836 const int x_west
= client
.rect
.x();
1837 const int x_east
= client
.rect
.right() - frame
.inside_w
+ 1;
1838 const int x_center
= client
.rect
.right() - (frame
.rect
.width()/2) + 1;
1839 // y coordinates for each gravity type
1840 const int y_north
= client
.rect
.y();
1841 const int y_south
= client
.rect
.bottom() - frame
.inside_h
+ 1;
1842 const int y_center
= client
.rect
.bottom() - (frame
.rect
.height()/2) + 1;
1844 switch (client
.win_gravity
) {
1846 case NorthWestGravity
: frame
.rect
.setPos(x_west
, y_north
); break;
1847 case NorthGravity
: frame
.rect
.setPos(x_center
, y_north
); break;
1848 case NorthEastGravity
: frame
.rect
.setPos(x_east
, y_north
); break;
1849 case SouthWestGravity
: frame
.rect
.setPos(x_west
, y_south
); break;
1850 case SouthGravity
: frame
.rect
.setPos(x_center
, y_south
); break;
1851 case SouthEastGravity
: frame
.rect
.setPos(x_east
, y_south
); break;
1852 case WestGravity
: frame
.rect
.setPos(x_west
, y_center
); break;
1853 case CenterGravity
: frame
.rect
.setPos(x_center
, y_center
); break;
1854 case EastGravity
: frame
.rect
.setPos(x_east
, y_center
); break;
1858 frame
.rect
.setPos(client
.rect
.x() - frame
.margin
.left
,
1859 client
.rect
.y() - frame
.margin
.top
);
1866 * The reverse of the setGravityOffsets function. Uses the frame window's
1867 * position to find the window's reference point.
1869 void BlackboxWindow::restoreGravity(void) {
1870 // x coordinates for each gravity type
1871 const int x_west
= frame
.rect
.x();
1872 const int x_east
= frame
.rect
.x() + frame
.inside_w
- client
.rect
.width();
1873 const int x_center
= frame
.rect
.x() + (frame
.rect
.width()/2) -
1874 client
.rect
.width();
1875 // y coordinates for each gravity type
1876 const int y_north
= frame
.rect
.y();
1877 const int y_south
= frame
.rect
.y() + frame
.inside_h
- client
.rect
.height();
1878 const int y_center
= frame
.rect
.y() + (frame
.rect
.height()/2) -
1879 client
.rect
.height();
1881 switch(client
.win_gravity
) {
1883 case NorthWestGravity
: client
.rect
.setPos(x_west
, y_north
); break;
1884 case NorthGravity
: client
.rect
.setPos(x_center
, y_north
); break;
1885 case NorthEastGravity
: client
.rect
.setPos(x_east
, y_north
); break;
1886 case SouthWestGravity
: client
.rect
.setPos(x_west
, y_south
); break;
1887 case SouthGravity
: client
.rect
.setPos(x_center
, y_south
); break;
1888 case SouthEastGravity
: client
.rect
.setPos(x_east
, y_south
); break;
1889 case WestGravity
: client
.rect
.setPos(x_west
, y_center
); break;
1890 case CenterGravity
: client
.rect
.setPos(x_center
, y_center
); break;
1891 case EastGravity
: client
.rect
.setPos(x_east
, y_center
); break;
1895 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1896 frame
.rect
.top() + frame
.margin
.top
);
1902 void BlackboxWindow::redrawLabel(void) {
1903 if (flags
.focused
) {
1905 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1906 frame
.label
, frame
.flabel
);
1908 XSetWindowBackground(blackbox
->getXDisplay(),
1909 frame
.label
, frame
.flabel_pixel
);
1912 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1913 frame
.label
, frame
.ulabel
);
1915 XSetWindowBackground(blackbox
->getXDisplay(),
1916 frame
.label
, frame
.ulabel_pixel
);
1918 XClearWindow(blackbox
->getXDisplay(), frame
.label
);
1920 WindowStyle
*style
= screen
->getWindowStyle();
1922 int pos
= frame
.bevel_w
* 2,
1923 dlen
= style
->doJustify(client
.title
.c_str(), pos
, frame
.label_w
,
1924 frame
.bevel_w
* 4, i18n
.multibyte());
1926 BPen
pen((flags
.focused
) ? style
->l_text_focus
: style
->l_text_unfocus
,
1928 if (i18n
.multibyte())
1929 XmbDrawString(blackbox
->getXDisplay(), frame
.label
, style
->fontset
,
1931 (1 - style
->fontset_extents
->max_ink_extent
.y
),
1932 client
.title
.c_str(), dlen
);
1934 XDrawString(blackbox
->getXDisplay(), frame
.label
, pen
.gc(), pos
,
1935 (style
->font
->ascent
+ 1), client
.title
.c_str(), dlen
);
1939 void BlackboxWindow::redrawAllButtons(void) {
1940 if (frame
.iconify_button
) redrawIconifyButton(False
);
1941 if (frame
.maximize_button
) redrawMaximizeButton(flags
.maximized
);
1942 if (frame
.close_button
) redrawCloseButton(False
);
1946 void BlackboxWindow::redrawIconifyButton(bool pressed
) {
1948 if (flags
.focused
) {
1950 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1951 frame
.iconify_button
, frame
.fbutton
);
1953 XSetWindowBackground(blackbox
->getXDisplay(),
1954 frame
.iconify_button
, frame
.fbutton_pixel
);
1957 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1958 frame
.iconify_button
, frame
.ubutton
);
1960 XSetWindowBackground(blackbox
->getXDisplay(), frame
.iconify_button
,
1961 frame
.ubutton_pixel
);
1965 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1966 frame
.iconify_button
, frame
.pbutton
);
1968 XSetWindowBackground(blackbox
->getXDisplay(),
1969 frame
.iconify_button
, frame
.pbutton_pixel
);
1971 XClearWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
1973 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
1974 screen
->getWindowStyle()->b_pic_unfocus
);
1975 XDrawRectangle(blackbox
->getXDisplay(), frame
.iconify_button
, pen
.gc(),
1976 2, (frame
.button_w
- 5), (frame
.button_w
- 5), 2);
1980 void BlackboxWindow::redrawMaximizeButton(bool pressed
) {
1982 if (flags
.focused
) {
1984 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1985 frame
.maximize_button
, frame
.fbutton
);
1987 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
1988 frame
.fbutton_pixel
);
1991 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1992 frame
.maximize_button
, frame
.ubutton
);
1994 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
1995 frame
.ubutton_pixel
);
1999 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2000 frame
.maximize_button
, frame
.pbutton
);
2002 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2003 frame
.pbutton_pixel
);
2005 XClearWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
2007 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2008 screen
->getWindowStyle()->b_pic_unfocus
);
2009 XDrawRectangle(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2010 2, 2, (frame
.button_w
- 5), (frame
.button_w
- 5));
2011 XDrawLine(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2012 2, 3, (frame
.button_w
- 3), 3);
2016 void BlackboxWindow::redrawCloseButton(bool pressed
) {
2018 if (flags
.focused
) {
2020 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2023 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2024 frame
.fbutton_pixel
);
2027 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2030 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2031 frame
.ubutton_pixel
);
2035 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2036 frame
.close_button
, frame
.pbutton
);
2038 XSetWindowBackground(blackbox
->getXDisplay(),
2039 frame
.close_button
, frame
.pbutton_pixel
);
2041 XClearWindow(blackbox
->getXDisplay(), frame
.close_button
);
2043 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2044 screen
->getWindowStyle()->b_pic_unfocus
);
2045 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2046 2, 2, (frame
.button_w
- 3), (frame
.button_w
- 3));
2047 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2048 2, (frame
.button_w
- 3), (frame
.button_w
- 3), 2);
2052 void BlackboxWindow::mapRequestEvent(XMapRequestEvent
*re
) {
2053 if (re
->window
!= client
.window
)
2057 fprintf(stderr
, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2061 bool get_state_ret
= getState();
2062 if (! (get_state_ret
&& blackbox
->isStartup())) {
2063 if ((client
.wm_hint_flags
& StateHint
) &&
2064 (! (current_state
== NormalState
|| current_state
== IconicState
)))
2065 current_state
= client
.initial_state
;
2067 current_state
= NormalState
;
2068 } else if (flags
.iconic
) {
2069 current_state
= NormalState
;
2072 switch (current_state
) {
2077 case WithdrawnState
:
2086 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2087 if (! blackbox
->isStartup() && (isTransient() || screen
->doFocusNew())) {
2088 XSync(blackbox
->getXDisplay(), False
); // make sure the frame is mapped..
2096 void BlackboxWindow::unmapNotifyEvent(XUnmapEvent
*ue
) {
2097 if (ue
->window
!= client
.window
)
2101 fprintf(stderr
, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2105 screen
->unmanageWindow(this, False
);
2109 void BlackboxWindow::destroyNotifyEvent(XDestroyWindowEvent
*de
) {
2110 if (de
->window
!= client
.window
)
2114 fprintf(stderr
, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2118 screen
->unmanageWindow(this, False
);
2122 void BlackboxWindow::reparentNotifyEvent(XReparentEvent
*re
) {
2123 if (re
->window
!= client
.window
|| re
->parent
== frame
.plate
)
2127 fprintf(stderr
, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2128 "0x%lx.\n", client
.window
, re
->parent
);
2133 XPutBackEvent(blackbox
->getXDisplay(), &ev
);
2134 screen
->unmanageWindow(this, True
);
2138 void BlackboxWindow::propertyNotifyEvent(Atom atom
) {
2141 case XA_WM_CLIENT_MACHINE
:
2145 case XA_WM_TRANSIENT_FOR
: {
2146 // determine if this is a transient window
2149 // adjust the window decorations based on transience
2150 if (isTransient()) {
2151 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2152 functions
&= ~Func_Maximize
;
2163 case XA_WM_ICON_NAME
:
2165 if (flags
.iconic
) screen
->propagateWindowName(this);
2171 if (decorations
& Decor_Titlebar
)
2174 screen
->propagateWindowName(this);
2177 case XA_WM_NORMAL_HINTS
: {
2180 if ((client
.normal_hint_flags
& PMinSize
) &&
2181 (client
.normal_hint_flags
& PMaxSize
)) {
2182 if (client
.max_width
<= client
.min_width
&&
2183 client
.max_height
<= client
.min_height
) {
2184 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2185 functions
&= ~(Func_Resize
| Func_Maximize
);
2187 decorations
|= Decor_Maximize
| Decor_Handle
;
2188 functions
|= Func_Resize
| Func_Maximize
;
2192 Rect old_rect
= frame
.rect
;
2196 if (old_rect
!= frame
.rect
)
2203 if (atom
== blackbox
->getWMProtocolsAtom()) {
2206 if ((decorations
& Decor_Close
) && (! frame
.close_button
)) {
2207 createCloseButton();
2208 if (decorations
& Decor_Titlebar
) {
2209 positionButtons(True
);
2210 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
2212 if (windowmenu
) windowmenu
->reconfigure();
2221 void BlackboxWindow::exposeEvent(XExposeEvent
*ee
) {
2222 if (frame
.label
== ee
->window
&& (decorations
& Decor_Titlebar
))
2224 else if (frame
.close_button
== ee
->window
)
2225 redrawCloseButton(False
);
2226 else if (frame
.maximize_button
== ee
->window
)
2227 redrawMaximizeButton(flags
.maximized
);
2228 else if (frame
.iconify_button
== ee
->window
)
2229 redrawIconifyButton(False
);
2233 void BlackboxWindow::configureRequestEvent(XConfigureRequestEvent
*cr
) {
2234 if (cr
->window
!= client
.window
|| flags
.iconic
)
2237 int cx
= frame
.rect
.x(), cy
= frame
.rect
.y();
2238 unsigned int cw
= frame
.rect
.width(), ch
= frame
.rect
.height();
2240 if (cr
->value_mask
& CWBorderWidth
)
2241 client
.old_bw
= cr
->border_width
;
2243 if (cr
->value_mask
& CWX
)
2244 cx
= cr
->x
- frame
.margin
.left
;
2246 if (cr
->value_mask
& CWY
)
2247 cy
= cr
->y
- frame
.margin
.top
;
2249 if (cr
->value_mask
& CWWidth
)
2250 cw
= cr
->width
+ frame
.margin
.left
+ frame
.margin
.right
;
2252 if (cr
->value_mask
& CWHeight
)
2253 ch
= cr
->height
+ frame
.margin
.top
+ frame
.margin
.bottom
;
2255 if (frame
.rect
!= Rect(cx
, cy
, cw
, ch
))
2256 configure(cx
, cy
, cw
, ch
);
2258 if (cr
->value_mask
& CWStackMode
) {
2259 switch (cr
->detail
) {
2262 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2268 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2275 void BlackboxWindow::buttonPressEvent(XButtonEvent
*be
) {
2276 if (frame
.maximize_button
== be
->window
) {
2277 redrawMaximizeButton(True
);
2278 } else if (be
->button
== 1 || (be
->button
== 3 && be
->state
== Mod1Mask
)) {
2279 if (! flags
.focused
)
2282 if (frame
.iconify_button
== be
->window
) {
2283 redrawIconifyButton(True
);
2284 } else if (frame
.close_button
== be
->window
) {
2285 redrawCloseButton(True
);
2286 } else if (frame
.plate
== be
->window
) {
2287 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2289 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2291 XAllowEvents(blackbox
->getXDisplay(), ReplayPointer
, be
->time
);
2293 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
2294 if (((be
->time
- lastButtonPressTime
) <=
2295 blackbox
->getDoubleClickInterval()) ||
2296 (be
->state
& ControlMask
)) {
2297 lastButtonPressTime
= 0;
2300 lastButtonPressTime
= be
->time
;
2304 frame
.grab_x
= be
->x_root
- frame
.rect
.x() - frame
.border_w
;
2305 frame
.grab_y
= be
->y_root
- frame
.rect
.y() - frame
.border_w
;
2307 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2309 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2311 } else if (be
->button
== 2 && (be
->window
!= frame
.iconify_button
) &&
2312 (be
->window
!= frame
.close_button
)) {
2313 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2314 } else if (windowmenu
&& be
->button
== 3 &&
2315 (frame
.title
== be
->window
|| frame
.label
== be
->window
||
2316 frame
.handle
== be
->window
|| frame
.window
== be
->window
)) {
2319 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
2320 mx
= be
->x_root
- (windowmenu
->getWidth() / 2);
2321 my
= frame
.rect
.y() + frame
.title_h
+ frame
.border_w
;
2322 } else if (frame
.handle
== be
->window
) {
2323 mx
= be
->x_root
- (windowmenu
->getWidth() / 2);
2324 my
= frame
.rect
.bottom() - frame
.handle_h
- (frame
.border_w
* 3) -
2325 windowmenu
->getHeight();
2327 mx
= be
->x_root
- (windowmenu
->getWidth() / 2);
2329 if (be
->y
<= static_cast<signed>(frame
.bevel_w
))
2330 my
= frame
.rect
.y() + frame
.title_h
;
2332 my
= be
->y_root
- (windowmenu
->getHeight() / 2);
2335 // snap the window menu into a corner if necessary - we check the
2336 // position of the menu with the coordinates of the client to
2337 // make the comparisions easier.
2338 // ### this needs some work!
2339 if (mx
> client
.rect
.right() -
2340 static_cast<signed>(windowmenu
->getWidth()))
2341 mx
= frame
.rect
.right() - windowmenu
->getWidth() - frame
.border_w
+ 1;
2342 if (mx
< client
.rect
.left())
2343 mx
= frame
.rect
.x();
2345 if (my
> client
.rect
.bottom() -
2346 static_cast<signed>(windowmenu
->getHeight()))
2347 my
= frame
.rect
.bottom() - windowmenu
->getHeight() - frame
.border_w
+ 1;
2348 if (my
< client
.rect
.top())
2349 my
= frame
.rect
.y() + ((decorations
& Decor_Titlebar
) ?
2353 if (! windowmenu
->isVisible()) {
2354 windowmenu
->move(mx
, my
);
2356 XRaiseWindow(blackbox
->getXDisplay(), windowmenu
->getWindowID());
2357 XRaiseWindow(blackbox
->getXDisplay(),
2358 windowmenu
->getSendToMenu()->getWindowID());
2367 void BlackboxWindow::buttonReleaseEvent(XButtonEvent
*re
) {
2368 if (re
->window
== frame
.maximize_button
) {
2369 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2370 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2371 maximize(re
->button
);
2373 redrawMaximizeButton(flags
.maximized
);
2375 } else if (re
->window
== frame
.iconify_button
) {
2376 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2377 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2380 redrawIconifyButton(False
);
2382 } else if (re
->window
== frame
.close_button
) {
2383 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2384 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
)))
2386 redrawCloseButton(False
);
2387 } else if (flags
.moving
) {
2388 flags
.moving
= False
;
2390 if (! screen
->doOpaqueMove()) {
2391 /* when drawing the rubber band, we need to make sure we only draw inside
2392 * the frame... frame.changing_* contain the new coords for the window,
2393 * so we need to subtract 1 from changing_w/changing_h every where we
2394 * draw the rubber band (for both moving and resizing)
2396 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2397 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
2398 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
2399 XUngrabServer(blackbox
->getXDisplay());
2401 configure(frame
.changing
.x(), frame
.changing
.y(),
2402 frame
.changing
.width(), frame
.changing
.height());
2404 configure(frame
.rect
.x(), frame
.rect
.y(),
2405 frame
.rect
.width(), frame
.rect
.height());
2407 screen
->hideGeometry();
2408 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
2409 } else if (flags
.resizing
) {
2410 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2411 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
2412 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
2413 XUngrabServer(blackbox
->getXDisplay());
2415 screen
->hideGeometry();
2417 constrain((re
->window
== frame
.left_grip
) ? TopRight
: TopLeft
);
2419 // unset maximized state when resized after fully maximized
2420 if (flags
.maximized
== 1)
2422 flags
.resizing
= False
;
2423 configure(frame
.changing
.x(), frame
.changing
.y(),
2424 frame
.changing
.width(), frame
.changing
.height());
2426 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
2427 } else if (re
->window
== frame
.window
) {
2428 if (re
->button
== 2 && re
->state
== Mod1Mask
)
2429 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
2434 void BlackboxWindow::motionNotifyEvent(XMotionEvent
*me
) {
2435 if (!flags
.resizing
&& (me
->state
& Button1Mask
) &&
2436 (functions
& Func_Move
) &&
2437 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
2438 frame
.handle
== me
->window
|| frame
.window
== me
->window
)) {
2439 if (! flags
.moving
) {
2440 XGrabPointer(blackbox
->getXDisplay(), me
->window
, False
,
2441 Button1MotionMask
| ButtonReleaseMask
,
2442 GrabModeAsync
, GrabModeAsync
,
2443 None
, blackbox
->getMoveCursor(), CurrentTime
);
2445 if (windowmenu
&& windowmenu
->isVisible())
2448 flags
.moving
= True
;
2450 if (! screen
->doOpaqueMove()) {
2451 XGrabServer(blackbox
->getXDisplay());
2453 frame
.changing
= frame
.rect
;
2454 screen
->showPosition(frame
.changing
.x(), frame
.changing
.y());
2456 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2460 frame
.changing
.width() - 1,
2461 frame
.changing
.height() - 1);
2464 int dx
= me
->x_root
- frame
.grab_x
, dy
= me
->y_root
- frame
.grab_y
;
2465 dx
-= frame
.border_w
;
2466 dy
-= frame
.border_w
;
2468 const int snap_distance
= screen
->getEdgeSnapThreshold();
2470 if (snap_distance
) {
2471 Rect srect
= screen
->availableArea();
2473 const int wleft
= dx
,
2474 wright
= dx
+ frame
.rect
.width() - 1,
2476 wbottom
= dy
+ frame
.rect
.height() - 1;
2478 int dleft
= std::abs(wleft
- srect
.left()),
2479 dright
= std::abs(wright
- srect
.right()),
2480 dtop
= std::abs(wtop
- srect
.top()),
2481 dbottom
= std::abs(wbottom
- srect
.bottom());
2484 if (dleft
< snap_distance
&& dleft
< dright
)
2487 else if (dright
< snap_distance
&& dright
< dleft
)
2488 dx
= srect
.right() - frame
.rect
.width() + 1;
2491 if (dtop
< snap_distance
&& dtop
< dbottom
)
2494 else if (dbottom
< snap_distance
&& dbottom
< dtop
)
2495 dy
= srect
.bottom() - frame
.rect
.height() + 1;
2497 srect
= screen
->getRect(); // now get the full screen
2499 dleft
= std::abs(wleft
- srect
.left()),
2500 dright
= std::abs(wright
- srect
.right()),
2501 dtop
= std::abs(wtop
- srect
.top()),
2502 dbottom
= std::abs(wbottom
- srect
.bottom());
2505 if (dleft
< snap_distance
&& dleft
< dright
)
2508 else if (dright
< snap_distance
&& dright
< dleft
)
2509 dx
= srect
.right() - frame
.rect
.width() + 1;
2512 if (dtop
< snap_distance
&& dtop
< dbottom
)
2515 else if (dbottom
< snap_distance
&& dbottom
< dtop
)
2516 dy
= srect
.bottom() - frame
.rect
.height() + 1;
2519 if (screen
->doOpaqueMove()) {
2520 configure(dx
, dy
, frame
.rect
.width(), frame
.rect
.height());
2522 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2526 frame
.changing
.width() - 1,
2527 frame
.changing
.height() - 1);
2529 frame
.changing
.setPos(dx
, dy
);
2531 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2535 frame
.changing
.width() - 1,
2536 frame
.changing
.height() - 1);
2539 screen
->showPosition(dx
, dy
);
2541 } else if ((functions
& Func_Resize
) &&
2542 (((me
->state
& Button1Mask
) &&
2543 (me
->window
== frame
.right_grip
||
2544 me
->window
== frame
.left_grip
)) ||
2545 (me
->state
& (Mod1Mask
| Button3Mask
) &&
2546 me
->window
== frame
.window
))) {
2547 bool left
= (me
->window
== frame
.left_grip
);
2549 if (! flags
.resizing
) {
2550 XGrabServer(blackbox
->getXDisplay());
2551 XGrabPointer(blackbox
->getXDisplay(), me
->window
, False
,
2552 ButtonMotionMask
| ButtonReleaseMask
,
2553 GrabModeAsync
, GrabModeAsync
, None
,
2554 ((left
) ? blackbox
->getLowerLeftAngleCursor() :
2555 blackbox
->getLowerRightAngleCursor()),
2558 flags
.resizing
= True
;
2561 frame
.grab_x
= me
->x
;
2562 frame
.grab_y
= me
->y
;
2563 frame
.changing
= frame
.rect
;
2565 constrain((left
) ? TopRight
: TopLeft
, &gw
, &gh
);
2567 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2568 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
2569 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
2571 screen
->showGeometry(gw
, gh
);
2573 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2574 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
2575 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
2583 frame
.changing
.setCoords(me
->x_root
- frame
.grab_x
, frame
.rect
.top(),
2584 frame
.rect
.right(), frame
.rect
.bottom());
2585 frame
.changing
.setHeight(frame
.rect
.height() + (me
->y
- frame
.grab_y
));
2588 frame
.changing
.setSize(frame
.rect
.width() + (me
->x
- frame
.grab_x
),
2589 frame
.rect
.height() + (me
->y
- frame
.grab_y
));
2592 constrain(anchor
, &gw
, &gh
);
2594 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2595 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
2596 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
2598 screen
->showGeometry(gw
, gh
);
2605 void BlackboxWindow::shapeEvent(XShapeEvent
*) {
2606 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
2613 bool BlackboxWindow::validateClient(void) {
2614 XSync(blackbox
->getXDisplay(), False
);
2617 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
2618 DestroyNotify
, &e
) ||
2619 XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
2621 XPutBackEvent(blackbox
->getXDisplay(), &e
);
2630 void BlackboxWindow::restore(bool remap
) {
2631 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeDelete
);
2632 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
2633 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, NoEventMask
);
2637 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
2638 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
2640 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, client
.old_bw
);
2643 if (! XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
2644 ReparentNotify
, &ev
)) {
2645 // according to the ICCCM - if the client doesn't reparent to
2646 // root, then we have to do it for them
2647 XReparentWindow(blackbox
->getXDisplay(), client
.window
,
2648 screen
->getRootWindow(),
2649 client
.rect
.x(), client
.rect
.y());
2652 if (remap
) XMapWindow(blackbox
->getXDisplay(), client
.window
);
2656 // timer for autoraise
2657 void BlackboxWindow::timeout(void) {
2658 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2662 void BlackboxWindow::changeBlackboxHints(BlackboxHints
*net
) {
2663 if ((net
->flags
& AttribShaded
) &&
2664 ((blackbox_attrib
.attrib
& AttribShaded
) !=
2665 (net
->attrib
& AttribShaded
)))
2668 if (flags
.visible
&& // watch out for requests when we can not be seen
2669 (net
->flags
& (AttribMaxVert
| AttribMaxHoriz
)) &&
2670 ((blackbox_attrib
.attrib
& (AttribMaxVert
| AttribMaxHoriz
)) !=
2671 (net
->attrib
& (AttribMaxVert
| AttribMaxHoriz
)))) {
2672 if (flags
.maximized
) {
2677 if ((net
->flags
& AttribMaxHoriz
) && (net
->flags
& AttribMaxVert
))
2678 button
= ((net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0);
2679 else if (net
->flags
& AttribMaxVert
)
2680 button
= ((net
->attrib
& AttribMaxVert
) ? 2 : 0);
2681 else if (net
->flags
& AttribMaxHoriz
)
2682 button
= ((net
->attrib
& AttribMaxHoriz
) ? 3 : 0);
2688 if ((net
->flags
& AttribOmnipresent
) &&
2689 ((blackbox_attrib
.attrib
& AttribOmnipresent
) !=
2690 (net
->attrib
& AttribOmnipresent
)))
2693 if ((net
->flags
& AttribWorkspace
) &&
2694 (blackbox_attrib
.workspace
!= net
->workspace
)) {
2695 screen
->reassociateWindow(this, net
->workspace
, True
);
2697 if (screen
->getCurrentWorkspaceID() != net
->workspace
) {
2701 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2705 if (net
->flags
& AttribDecoration
) {
2706 switch (net
->decoration
) {
2708 // clear all decorations except close
2709 decorations
&= Decor_Close
;
2715 decorations
|= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
2716 Decor_Iconify
| Decor_Maximize
;
2721 decorations
|= Decor_Titlebar
| Decor_Iconify
;
2722 decorations
&= ~(Decor_Border
| Decor_Handle
| Decor_Maximize
);
2727 decorations
|= Decor_Titlebar
;
2728 decorations
&= ~(Decor_Iconify
| Decor_Border
| Decor_Handle
);
2729 functions
|= Func_Move
;
2734 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
2735 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
2739 setState(current_state
);
2745 * Set the sizes of all components of the window frame
2746 * (the window decorations).
2747 * These values are based upon the current style settings and the client
2748 * window's dimensions.
2750 void BlackboxWindow::upsize(void) {
2751 frame
.bevel_w
= screen
->getBevelWidth();
2753 if (decorations
& Decor_Border
) {
2754 frame
.border_w
= screen
->getBorderWidth();
2756 frame
.mwm_border_w
= screen
->getFrameWidth();
2758 frame
.mwm_border_w
= 0;
2760 frame
.mwm_border_w
= frame
.border_w
= 0;
2763 if (decorations
& Decor_Titlebar
) {
2764 // the height of the titlebar is based upon the height of the font being
2765 // used to display the window's title
2766 WindowStyle
*style
= screen
->getWindowStyle();
2767 if (i18n
.multibyte())
2768 frame
.title_h
= (style
->fontset_extents
->max_ink_extent
.height
+
2769 (frame
.bevel_w
* 2) + 2);
2771 frame
.title_h
= (style
->font
->ascent
+ style
->font
->descent
+
2772 (frame
.bevel_w
* 2) + 2);
2774 frame
.label_h
= frame
.title_h
- (frame
.bevel_w
* 2);
2775 frame
.button_w
= (frame
.label_h
- 2);
2777 // set the top frame margin
2778 frame
.margin
.top
= frame
.border_w
+ frame
.title_h
+
2779 frame
.border_w
+ frame
.mwm_border_w
;
2785 // set the top frame margin
2786 frame
.margin
.top
= frame
.border_w
+ frame
.mwm_border_w
;
2789 // set the left/right frame margin
2790 frame
.margin
.left
= frame
.margin
.right
= frame
.border_w
+ frame
.mwm_border_w
;
2792 if (decorations
& Decor_Handle
) {
2793 frame
.grip_w
= frame
.button_w
* 2;
2794 frame
.handle_h
= screen
->getHandleWidth();
2796 // set the bottom frame margin
2797 frame
.margin
.bottom
= frame
.border_w
+ frame
.handle_h
+
2798 frame
.border_w
+ frame
.mwm_border_w
;
2803 // set the bottom frame margin
2804 frame
.margin
.bottom
= frame
.border_w
+ frame
.mwm_border_w
;
2807 // set the frame rect
2808 frame
.rect
.setSize(client
.rect
.width() + frame
.margin
.left
+
2810 client
.rect
.height() + frame
.margin
.top
+
2811 frame
.margin
.bottom
);
2812 frame
.inside_w
= frame
.rect
.width() - (frame
.border_w
* 2);
2813 frame
.inside_h
= frame
.rect
.height() - (frame
.border_w
* 2);
2818 * Calculate the size of the client window and constrain it to the
2819 * size specified by the size hints of the client window.
2821 * The logical width and height are placed into pw and ph, if they
2822 * are non-zero. Logical size refers to the users perception of
2823 * the window size (for example an xterm has resizes in cells, not in
2826 * The physical geometry is placed into frame.changing_{x,y,width,height}.
2827 * Physical geometry refers to the geometry of the window in pixels.
2829 void BlackboxWindow::constrain(Corner anchor
, int *pw
, int *ph
) {
2830 // frame.changing represents the requested frame size, we need to
2831 // strip the frame margin off and constrain the client size
2832 frame
.changing
.setCoords(frame
.changing
.left() + frame
.margin
.left
,
2833 frame
.changing
.top() + frame
.margin
.top
,
2834 frame
.changing
.right() - frame
.margin
.right
,
2835 frame
.changing
.bottom() - frame
.margin
.bottom
);
2837 int dw
= frame
.changing
.width(), dh
= frame
.changing
.height(),
2838 base_width
= (client
.base_width
) ? client
.base_width
: client
.min_width
,
2839 base_height
= (client
.base_height
) ? client
.base_height
:
2843 if (dw
< static_cast<signed>(client
.min_width
)) dw
= client
.min_width
;
2844 if (dh
< static_cast<signed>(client
.min_height
)) dh
= client
.min_height
;
2845 if (dw
> static_cast<signed>(client
.max_width
)) dw
= client
.max_width
;
2846 if (dh
> static_cast<signed>(client
.max_height
)) dh
= client
.max_height
;
2849 dw
/= client
.width_inc
;
2851 dh
/= client
.height_inc
;
2856 dw
*= client
.width_inc
;
2858 dh
*= client
.height_inc
;
2861 frame
.changing
.setSize(dw
, dh
);
2863 // add the frame margin back onto frame.changing
2864 frame
.changing
.setCoords(frame
.changing
.left() - frame
.margin
.left
,
2865 frame
.changing
.top() - frame
.margin
.top
,
2866 frame
.changing
.right() + frame
.margin
.right
,
2867 frame
.changing
.bottom() + frame
.margin
.bottom
);
2869 // move frame.changing to the specified anchor
2876 int dx
= frame
.rect
.right() - frame
.changing
.right();
2877 frame
.changing
.setPos(frame
.changing
.x() + dx
, frame
.changing
.y());
2883 int WindowStyle::doJustify(const char *text
, int &start_pos
,
2884 unsigned int max_length
, unsigned int modifier
,
2885 bool multibyte
) const {
2886 size_t text_len
= strlen(text
);
2887 unsigned int length
;
2891 XRectangle ink
, logical
;
2892 XmbTextExtents(fontset
, text
, text_len
, &ink
, &logical
);
2893 length
= logical
.width
;
2895 length
= XTextWidth(font
, text
, text_len
);
2898 } while (length
> max_length
&& text_len
-- > 0);
2902 start_pos
+= max_length
- length
;
2906 start_pos
+= (max_length
- length
) / 2;
2918 BWindowGroup::BWindowGroup(Blackbox
*b
, Window _group
)
2919 : blackbox(b
), group(_group
) {
2920 // watch for destroy notify on the group window
2921 XSelectInput(blackbox
->getXDisplay(), group
, StructureNotifyMask
);
2922 blackbox
->saveGroupSearch(group
, this);
2926 BWindowGroup::~BWindowGroup(void) {
2927 blackbox
->removeGroupSearch(group
);
2932 BWindowGroup::find(BScreen
*screen
, bool allow_transients
) const {
2933 BlackboxWindow
*ret
= blackbox
->getFocusedWindow();
2935 // does the focus window match (or any transient_fors)?
2937 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
2938 if (ret
->isTransient() && allow_transients
) break;
2939 else if (! ret
->isTransient()) break;
2942 ret
= ret
->getTransientFor();
2945 if (ret
) return ret
;
2947 // the focus window didn't match, look in the group's window list
2948 BlackboxWindowList::const_iterator it
, end
= windowList
.end();
2949 for (it
= windowList
.begin(); it
!= end
; ++it
) {
2951 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
2952 if (ret
->isTransient() && allow_transients
) break;
2953 else if (! ret
->isTransient()) break;