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 client
.min_width
= client
.min_height
=
910 client
.width_inc
= client
.height_inc
= 1;
911 client
.base_width
= client
.base_height
= 0;
914 use the full screen, not the strut modified size. otherwise when the
915 availableArea changes max_width/height will be incorrect and lead to odd
918 const Rect
& screen_area
= screen
->getRect();
919 client
.max_width
= screen_area
.width();
921 client
.max_height
= screen_area
.height();
922 client
.min_aspect_x
= client
.min_aspect_y
=
923 client
.max_aspect_x
= client
.max_aspect_y
= 1;
924 client
.win_gravity
= NorthWestGravity
;
926 if (! XGetWMNormalHints(blackbox
->getXDisplay(), client
.window
,
927 &sizehint
, &icccm_mask
))
930 client
.normal_hint_flags
= sizehint
.flags
;
932 if (sizehint
.flags
& PMinSize
) {
933 client
.min_width
= sizehint
.min_width
;
934 client
.min_height
= sizehint
.min_height
;
937 if (sizehint
.flags
& PMaxSize
) {
938 client
.max_width
= sizehint
.max_width
;
939 client
.max_height
= sizehint
.max_height
;
942 if (sizehint
.flags
& PResizeInc
) {
943 client
.width_inc
= sizehint
.width_inc
;
944 client
.height_inc
= sizehint
.height_inc
;
947 if (sizehint
.flags
& PAspect
) {
948 client
.min_aspect_x
= sizehint
.min_aspect
.x
;
949 client
.min_aspect_y
= sizehint
.min_aspect
.y
;
950 client
.max_aspect_x
= sizehint
.max_aspect
.x
;
951 client
.max_aspect_y
= sizehint
.max_aspect
.y
;
954 if (sizehint
.flags
& PBaseSize
) {
955 client
.base_width
= sizehint
.base_width
;
956 client
.base_height
= sizehint
.base_height
;
959 if (sizehint
.flags
& PWinGravity
)
960 client
.win_gravity
= sizehint
.win_gravity
;
965 * Gets the MWM hints for the class' contained window.
966 * This is used while initializing the window to its first state, and not
968 * Returns: true if the MWM hints are successfully retreived and applied;
969 * false if they are not.
971 void BlackboxWindow::getMWMHints(void) {
974 unsigned long num
, len
;
975 MwmHints
*mwm_hint
= 0;
977 int ret
= XGetWindowProperty(blackbox
->getXDisplay(), client
.window
,
978 blackbox
->getMotifWMHintsAtom(), 0,
979 PropMwmHintsElements
, False
,
980 blackbox
->getMotifWMHintsAtom(), &atom_return
,
982 (unsigned char **) &mwm_hint
);
984 if (ret
!= Success
|| ! mwm_hint
|| num
!= PropMwmHintsElements
)
987 if (mwm_hint
->flags
& MwmHintsDecorations
) {
988 if (mwm_hint
->decorations
& MwmDecorAll
) {
989 decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
990 Decor_Iconify
| Decor_Maximize
| Decor_Close
;
994 if (mwm_hint
->decorations
& MwmDecorBorder
)
995 decorations
|= Decor_Border
;
996 if (mwm_hint
->decorations
& MwmDecorHandle
)
997 decorations
|= Decor_Handle
;
998 if (mwm_hint
->decorations
& MwmDecorTitle
)
999 decorations
|= Decor_Titlebar
;
1000 if (mwm_hint
->decorations
& MwmDecorIconify
)
1001 decorations
|= Decor_Iconify
;
1002 if (mwm_hint
->decorations
& MwmDecorMaximize
)
1003 decorations
|= Decor_Maximize
;
1007 if (mwm_hint
->flags
& MwmHintsFunctions
) {
1008 if (mwm_hint
->functions
& MwmFuncAll
) {
1009 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
|
1014 if (mwm_hint
->functions
& MwmFuncResize
)
1015 functions
|= Func_Resize
;
1016 if (mwm_hint
->functions
& MwmFuncMove
)
1017 functions
|= Func_Move
;
1018 if (mwm_hint
->functions
& MwmFuncIconify
)
1019 functions
|= Func_Iconify
;
1020 if (mwm_hint
->functions
& MwmFuncMaximize
)
1021 functions
|= Func_Maximize
;
1022 if (mwm_hint
->functions
& MwmFuncClose
)
1023 functions
|= Func_Close
;
1031 * Gets the blackbox hints from the class' contained window.
1032 * This is used while initializing the window to its first state, and not
1034 * Returns: true if the hints are successfully retreived and applied; false if
1037 bool BlackboxWindow::getBlackboxHints(void) {
1040 unsigned long num
, len
;
1041 BlackboxHints
*blackbox_hint
= 0;
1043 int ret
= XGetWindowProperty(blackbox
->getXDisplay(), client
.window
,
1044 blackbox
->getBlackboxHintsAtom(), 0,
1045 PropBlackboxHintsElements
, False
,
1046 blackbox
->getBlackboxHintsAtom(), &atom_return
,
1047 &format
, &num
, &len
,
1048 (unsigned char **) &blackbox_hint
);
1049 if (ret
!= Success
|| ! blackbox_hint
|| num
!= PropBlackboxHintsElements
)
1052 if (blackbox_hint
->flags
& AttribShaded
)
1053 flags
.shaded
= (blackbox_hint
->attrib
& AttribShaded
);
1055 if ((blackbox_hint
->flags
& AttribMaxHoriz
) &&
1056 (blackbox_hint
->flags
& AttribMaxVert
))
1057 flags
.maximized
= (blackbox_hint
->attrib
&
1058 (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1059 else if (blackbox_hint
->flags
& AttribMaxVert
)
1060 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxVert
) ? 2 : 0;
1061 else if (blackbox_hint
->flags
& AttribMaxHoriz
)
1062 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1064 if (blackbox_hint
->flags
& AttribOmnipresent
)
1065 flags
.stuck
= (blackbox_hint
->attrib
& AttribOmnipresent
);
1067 if (blackbox_hint
->flags
& AttribWorkspace
)
1068 blackbox_attrib
.workspace
= blackbox_hint
->workspace
;
1070 // if (blackbox_hint->flags & AttribStack)
1071 // don't yet have always on top/bottom for blackbox yet... working
1074 if (blackbox_hint
->flags
& AttribDecoration
) {
1075 switch (blackbox_hint
->decoration
) {
1077 // clear all decorations except close
1078 decorations
&= Decor_Close
;
1079 // clear all functions except close
1080 functions
&= Func_Close
;
1085 decorations
|= Decor_Titlebar
| Decor_Iconify
;
1086 decorations
&= ~(Decor_Border
| Decor_Handle
| Decor_Maximize
);
1087 functions
|= Func_Move
| Func_Iconify
;
1088 functions
&= ~(Func_Resize
| Func_Maximize
);
1093 decorations
|= Decor_Titlebar
;
1094 decorations
&= ~(Decor_Iconify
| Decor_Border
| Decor_Handle
);
1095 functions
|= Func_Move
;
1096 functions
&= ~(Func_Resize
| Func_Maximize
| Func_Iconify
);
1102 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Handle
|
1103 Decor_Iconify
| Decor_Maximize
;
1104 functions
|= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
1111 XFree(blackbox_hint
);
1116 void BlackboxWindow::getTransientInfo(void) {
1117 if (client
.transient_for
&&
1118 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1119 // the transient for hint was removed, so we need to tell our
1120 // previous transient_for that we are going away
1121 client
.transient_for
->client
.transientList
.remove(this);
1124 // we have no transient_for until we find a new one
1125 client
.transient_for
= 0;
1128 if (! XGetTransientForHint(blackbox
->getXDisplay(), client
.window
,
1130 // transient_for hint not set
1134 if (trans_for
== client
.window
) {
1135 // wierd client... treat this window as a normal window
1139 if (trans_for
== None
|| trans_for
== screen
->getRootWindow()) {
1140 // this is an undocumented interpretation of the ICCCM. a transient
1141 // associated with None/Root/itself is assumed to be a modal root
1142 // transient. we don't support the concept of a global transient,
1143 // so we just associate this transient with nothing, and perhaps
1144 // we will add support later for global modality.
1145 client
.transient_for
= (BlackboxWindow
*) ~0ul;
1150 client
.transient_for
= blackbox
->searchWindow(trans_for
);
1151 if (! client
.transient_for
&&
1152 client
.window_group
&& trans_for
== client
.window_group
) {
1153 // no direct transient_for, perhaps this is a group transient?
1154 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1155 if (group
) client
.transient_for
= group
->find(screen
);
1158 if (! client
.transient_for
|| client
.transient_for
== this) {
1159 // no transient_for found, or we have a wierd client that wants to be
1160 // a transient for itself, so we treat this window as a normal window
1161 client
.transient_for
= (BlackboxWindow
*) 0;
1165 // register ourselves with our new transient_for
1166 client
.transient_for
->client
.transientList
.push_back(this);
1167 flags
.stuck
= client
.transient_for
->flags
.stuck
;
1171 BlackboxWindow
*BlackboxWindow::getTransientFor(void) const {
1172 if (client
.transient_for
&&
1173 client
.transient_for
!= (BlackboxWindow
*) ~0ul)
1174 return client
.transient_for
;
1179 void BlackboxWindow::configure(int dx
, int dy
,
1180 unsigned int dw
, unsigned int dh
) {
1181 bool send_event
= (frame
.rect
.x() != dx
|| frame
.rect
.y() != dy
);
1183 if ((dw
!= frame
.rect
.width()) || (dh
!= frame
.rect
.height())) {
1184 frame
.rect
.setRect(dx
, dy
, dw
, dh
);
1185 frame
.inside_w
= frame
.rect
.width() - (frame
.border_w
* 2);
1186 frame
.inside_h
= frame
.rect
.height() - (frame
.border_w
* 2);
1188 if (frame
.rect
.right() <= 0 || frame
.rect
.bottom() <= 0)
1189 frame
.rect
.setPos(0, 0);
1191 client
.rect
.setCoords(frame
.rect
.left() + frame
.margin
.left
,
1192 frame
.rect
.top() + frame
.margin
.top
,
1193 frame
.rect
.right() - frame
.margin
.right
,
1194 frame
.rect
.bottom() - frame
.margin
.bottom
);
1197 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
1204 setFocusFlag(flags
.focused
);
1207 frame
.rect
.setPos(dx
, dy
);
1209 XMoveWindow(blackbox
->getXDisplay(), frame
.window
,
1210 frame
.rect
.x(), frame
.rect
.y());
1212 if (! flags
.moving
) send_event
= True
;
1215 if (send_event
&& ! flags
.moving
) {
1216 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1217 frame
.rect
.top() + frame
.margin
.top
);
1220 event
.type
= ConfigureNotify
;
1222 event
.xconfigure
.display
= blackbox
->getXDisplay();
1223 event
.xconfigure
.event
= client
.window
;
1224 event
.xconfigure
.window
= client
.window
;
1225 event
.xconfigure
.x
= client
.rect
.x();
1226 event
.xconfigure
.y
= client
.rect
.y();
1227 event
.xconfigure
.width
= client
.rect
.width();
1228 event
.xconfigure
.height
= client
.rect
.height();
1229 event
.xconfigure
.border_width
= client
.old_bw
;
1230 event
.xconfigure
.above
= frame
.window
;
1231 event
.xconfigure
.override_redirect
= False
;
1233 XSendEvent(blackbox
->getXDisplay(), client
.window
, True
,
1234 NoEventMask
, &event
);
1236 screen
->updateNetizenConfigNotify(&event
);
1242 void BlackboxWindow::configureShape(void) {
1243 XShapeCombineShape(blackbox
->getXDisplay(), frame
.window
, ShapeBounding
,
1244 frame
.margin
.left
- frame
.border_w
,
1245 frame
.margin
.top
- frame
.border_w
,
1246 client
.window
, ShapeBounding
, ShapeSet
);
1249 XRectangle xrect
[2];
1251 if (decorations
& Decor_Titlebar
) {
1252 xrect
[0].x
= xrect
[0].y
= -frame
.border_w
;
1253 xrect
[0].width
= frame
.rect
.width();
1254 xrect
[0].height
= frame
.title_h
+ (frame
.border_w
* 2);
1258 if (decorations
& Decor_Handle
) {
1259 xrect
[1].x
= -frame
.border_w
;
1260 xrect
[1].y
= frame
.rect
.height() - frame
.margin
.bottom
+
1261 frame
.mwm_border_w
- frame
.border_w
;
1262 xrect
[1].width
= frame
.rect
.width();
1263 xrect
[1].height
= frame
.handle_h
+ (frame
.border_w
* 2);
1267 XShapeCombineRectangles(blackbox
->getXDisplay(), frame
.window
,
1268 ShapeBounding
, 0, 0, xrect
, num
,
1269 ShapeUnion
, Unsorted
);
1274 bool BlackboxWindow::setInputFocus(void) {
1275 if (flags
.focused
) return True
;
1277 if (! client
.rect
.intersects(screen
->getRect())) {
1278 // client is outside the screen, move it to the center
1279 configure((screen
->getWidth() - frame
.rect
.width()) / 2,
1280 (screen
->getHeight() - frame
.rect
.height()) / 2,
1281 frame
.rect
.width(), frame
.rect
.height());
1284 if (client
.transientList
.size() > 0) {
1285 // transfer focus to any modal transients
1286 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1287 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1288 if ((*it
)->flags
.modal
) return (*it
)->setInputFocus();
1293 if (focus_mode
== F_LocallyActive
|| focus_mode
== F_Passive
) {
1294 XSetInputFocus(blackbox
->getXDisplay(), client
.window
,
1295 RevertToPointerRoot
, CurrentTime
);
1297 blackbox
->setFocusedWindow(this);
1299 /* we could set the focus to none, since the window doesn't accept focus,
1300 * but we shouldn't set focus to nothing since this would surely make
1306 if (flags
.send_focus_message
) {
1308 ce
.xclient
.type
= ClientMessage
;
1309 ce
.xclient
.message_type
= blackbox
->getWMProtocolsAtom();
1310 ce
.xclient
.display
= blackbox
->getXDisplay();
1311 ce
.xclient
.window
= client
.window
;
1312 ce
.xclient
.format
= 32;
1313 ce
.xclient
.data
.l
[0] = blackbox
->getWMTakeFocusAtom();
1314 ce
.xclient
.data
.l
[1] = blackbox
->getLastTime();
1315 ce
.xclient
.data
.l
[2] = 0l;
1316 ce
.xclient
.data
.l
[3] = 0l;
1317 ce
.xclient
.data
.l
[4] = 0l;
1318 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1326 void BlackboxWindow::iconify(void) {
1327 if (flags
.iconic
) return;
1329 if (windowmenu
) windowmenu
->hide();
1331 setState(IconicState
);
1334 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1335 * we need to clear the event mask on client.window for a split second.
1336 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1337 * split second, leaving us with a ghost window... so, we need to do this
1338 * while the X server is grabbed
1340 XGrabServer(blackbox
->getXDisplay());
1341 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
1342 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1343 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1344 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
1345 XUngrabServer(blackbox
->getXDisplay());
1347 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1348 flags
.visible
= False
;
1349 flags
.iconic
= True
;
1351 screen
->getWorkspace(blackbox_attrib
.workspace
)->removeWindow(this);
1353 if (isTransient()) {
1354 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1355 ! client
.transient_for
->flags
.iconic
) {
1356 // iconify our transient_for
1357 client
.transient_for
->iconify();
1361 screen
->addIcon(this);
1363 if (client
.transientList
.size() > 0) {
1364 // iconify all transients
1365 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1366 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1367 if (! (*it
)->flags
.iconic
) (*it
)->iconify();
1373 void BlackboxWindow::show(void) {
1374 setState(NormalState
);
1376 XMapWindow(blackbox
->getXDisplay(), client
.window
);
1377 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
1378 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
1380 flags
.visible
= True
;
1381 flags
.iconic
= False
;
1385 void BlackboxWindow::deiconify(bool reassoc
, bool raise
) {
1386 if (flags
.iconic
|| reassoc
)
1387 screen
->reassociateWindow(this, BSENTINEL
, False
);
1388 else if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspace()->getID())
1393 // reassociate and deiconify all transients
1394 if (reassoc
&& client
.transientList
.size() > 0) {
1395 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1396 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1397 (*it
)->deiconify(True
, False
);
1402 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1406 void BlackboxWindow::close(void) {
1408 ce
.xclient
.type
= ClientMessage
;
1409 ce
.xclient
.message_type
= blackbox
->getWMProtocolsAtom();
1410 ce
.xclient
.display
= blackbox
->getXDisplay();
1411 ce
.xclient
.window
= client
.window
;
1412 ce
.xclient
.format
= 32;
1413 ce
.xclient
.data
.l
[0] = blackbox
->getWMDeleteAtom();
1414 ce
.xclient
.data
.l
[1] = CurrentTime
;
1415 ce
.xclient
.data
.l
[2] = 0l;
1416 ce
.xclient
.data
.l
[3] = 0l;
1417 ce
.xclient
.data
.l
[4] = 0l;
1418 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
, NoEventMask
, &ce
);
1422 void BlackboxWindow::withdraw(void) {
1423 setState(current_state
);
1425 flags
.visible
= False
;
1426 flags
.iconic
= False
;
1428 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1430 XGrabServer(blackbox
->getXDisplay());
1431 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
1432 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1433 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1434 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
1435 XUngrabServer(blackbox
->getXDisplay());
1437 if (windowmenu
) windowmenu
->hide();
1441 void BlackboxWindow::maximize(unsigned int button
) {
1442 // handle case where menu is open then the max button is used instead
1443 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
1445 if (flags
.maximized
) {
1446 flags
.maximized
= 0;
1448 blackbox_attrib
.flags
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1449 blackbox_attrib
.attrib
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1452 when a resize is begun, maximize(0) is called to clear any maximization
1453 flags currently set. Otherwise it still thinks it is maximized.
1454 so we do not need to call configure() because resizing will handle it
1456 if (! flags
.resizing
)
1457 configure(blackbox_attrib
.premax_x
, blackbox_attrib
.premax_y
,
1458 blackbox_attrib
.premax_w
, blackbox_attrib
.premax_h
);
1460 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
1461 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
1464 setState(current_state
);
1468 blackbox_attrib
.premax_x
= frame
.rect
.x();
1469 blackbox_attrib
.premax_y
= frame
.rect
.y();
1470 blackbox_attrib
.premax_w
= frame
.rect
.width();
1471 blackbox_attrib
.premax_h
= frame
.rect
.height();
1473 const Rect
&screen_area
= screen
->availableArea();
1474 frame
.changing
= screen_area
;
1479 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1480 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1484 blackbox_attrib
.flags
|= AttribMaxVert
;
1485 blackbox_attrib
.attrib
|= AttribMaxVert
;
1487 frame
.changing
.setX(frame
.rect
.x());
1488 frame
.changing
.setWidth(frame
.rect
.width());
1492 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1493 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1495 frame
.changing
.setY(frame
.rect
.y());
1496 frame
.changing
.setHeight(frame
.rect
.height());
1501 blackbox_attrib
.flags
^= AttribShaded
;
1502 blackbox_attrib
.attrib
^= AttribShaded
;
1503 flags
.shaded
= False
;
1506 flags
.maximized
= button
;
1508 configure(frame
.changing
.x(), frame
.changing
.y(),
1509 frame
.changing
.width(), frame
.changing
.height());
1511 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1513 setState(current_state
);
1517 // re-maximizes the window to take into account availableArea changes
1518 void BlackboxWindow::remaximize(void) {
1519 // save the original dimensions because maximize will wipe them out
1520 int premax_x
= blackbox_attrib
.premax_x
,
1521 premax_y
= blackbox_attrib
.premax_y
,
1522 premax_w
= blackbox_attrib
.premax_w
,
1523 premax_h
= blackbox_attrib
.premax_h
;
1525 unsigned int button
= flags
.maximized
;
1526 flags
.maximized
= 0; // trick maximize() into working
1529 // restore saved values
1530 blackbox_attrib
.premax_x
= premax_x
;
1531 blackbox_attrib
.premax_y
= premax_y
;
1532 blackbox_attrib
.premax_w
= premax_w
;
1533 blackbox_attrib
.premax_h
= premax_h
;
1537 void BlackboxWindow::setWorkspace(unsigned int n
) {
1538 blackbox_attrib
.flags
|= AttribWorkspace
;
1539 blackbox_attrib
.workspace
= n
;
1543 void BlackboxWindow::shade(void) {
1545 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1546 frame
.inside_w
, frame
.inside_h
);
1547 flags
.shaded
= False
;
1548 blackbox_attrib
.flags
^= AttribShaded
;
1549 blackbox_attrib
.attrib
^= AttribShaded
;
1551 setState(NormalState
);
1553 // set the frame rect to the normal size
1554 frame
.rect
.setHeight(client
.rect
.height() + frame
.margin
.top
+
1555 frame
.margin
.bottom
);
1557 if (! (decorations
& Decor_Titlebar
))
1560 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1561 frame
.inside_w
, frame
.title_h
);
1562 flags
.shaded
= True
;
1563 blackbox_attrib
.flags
|= AttribShaded
;
1564 blackbox_attrib
.attrib
|= AttribShaded
;
1566 setState(IconicState
);
1568 // set the frame rect to the shaded size
1569 frame
.rect
.setHeight(frame
.title_h
+ (frame
.border_w
* 2));
1574 void BlackboxWindow::stick(void) {
1576 blackbox_attrib
.flags
^= AttribOmnipresent
;
1577 blackbox_attrib
.attrib
^= AttribOmnipresent
;
1579 flags
.stuck
= False
;
1582 screen
->reassociateWindow(this, BSENTINEL
, True
);
1584 setState(current_state
);
1588 blackbox_attrib
.flags
|= AttribOmnipresent
;
1589 blackbox_attrib
.attrib
|= AttribOmnipresent
;
1591 setState(current_state
);
1596 void BlackboxWindow::setFocusFlag(bool focus
) {
1597 flags
.focused
= focus
;
1599 if (decorations
& Decor_Titlebar
) {
1600 if (flags
.focused
) {
1602 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1603 frame
.title
, frame
.ftitle
);
1605 XSetWindowBackground(blackbox
->getXDisplay(),
1606 frame
.title
, frame
.ftitle_pixel
);
1609 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1610 frame
.title
, frame
.utitle
);
1612 XSetWindowBackground(blackbox
->getXDisplay(),
1613 frame
.title
, frame
.utitle_pixel
);
1615 XClearWindow(blackbox
->getXDisplay(), frame
.title
);
1621 if (decorations
& Decor_Handle
) {
1622 if (flags
.focused
) {
1624 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1625 frame
.handle
, frame
.fhandle
);
1627 XSetWindowBackground(blackbox
->getXDisplay(),
1628 frame
.handle
, frame
.fhandle_pixel
);
1631 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1632 frame
.left_grip
, frame
.fgrip
);
1633 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1634 frame
.right_grip
, frame
.fgrip
);
1636 XSetWindowBackground(blackbox
->getXDisplay(),
1637 frame
.left_grip
, frame
.fgrip_pixel
);
1638 XSetWindowBackground(blackbox
->getXDisplay(),
1639 frame
.right_grip
, frame
.fgrip_pixel
);
1643 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1644 frame
.handle
, frame
.uhandle
);
1646 XSetWindowBackground(blackbox
->getXDisplay(),
1647 frame
.handle
, frame
.uhandle_pixel
);
1650 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1651 frame
.left_grip
, frame
.ugrip
);
1652 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1653 frame
.right_grip
, frame
.ugrip
);
1655 XSetWindowBackground(blackbox
->getXDisplay(),
1656 frame
.left_grip
, frame
.ugrip_pixel
);
1657 XSetWindowBackground(blackbox
->getXDisplay(),
1658 frame
.right_grip
, frame
.ugrip_pixel
);
1661 XClearWindow(blackbox
->getXDisplay(), frame
.handle
);
1662 XClearWindow(blackbox
->getXDisplay(), frame
.left_grip
);
1663 XClearWindow(blackbox
->getXDisplay(), frame
.right_grip
);
1666 if (decorations
& Decor_Border
) {
1668 XSetWindowBorder(blackbox
->getXDisplay(),
1669 frame
.plate
, frame
.fborder_pixel
);
1671 XSetWindowBorder(blackbox
->getXDisplay(),
1672 frame
.plate
, frame
.uborder_pixel
);
1675 if (screen
->isSloppyFocus() && screen
->doAutoRaise()) {
1676 if (isFocused()) timer
->start();
1681 blackbox
->setFocusedWindow(this);
1685 void BlackboxWindow::installColormap(bool install
) {
1686 int i
= 0, ncmap
= 0;
1687 Colormap
*cmaps
= XListInstalledColormaps(blackbox
->getXDisplay(),
1688 client
.window
, &ncmap
);
1689 XWindowAttributes wattrib
;
1691 if (XGetWindowAttributes(blackbox
->getXDisplay(),
1692 client
.window
, &wattrib
)) {
1694 // install the window's colormap
1695 for (i
= 0; i
< ncmap
; i
++) {
1696 if (*(cmaps
+ i
) == wattrib
.colormap
)
1697 // this window is using an installed color map... do not install
1700 // otherwise, install the window's colormap
1702 XInstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
1704 // uninstall the window's colormap
1705 for (i
= 0; i
< ncmap
; i
++) {
1706 if (*(cmaps
+ i
) == wattrib
.colormap
)
1707 // we found the colormap to uninstall
1708 XUninstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
1718 void BlackboxWindow::setState(unsigned long new_state
) {
1719 current_state
= new_state
;
1721 unsigned long state
[2];
1722 state
[0] = current_state
;
1724 XChangeProperty(blackbox
->getXDisplay(), client
.window
,
1725 blackbox
->getWMStateAtom(), blackbox
->getWMStateAtom(), 32,
1726 PropModeReplace
, (unsigned char *) state
, 2);
1728 XChangeProperty(blackbox
->getXDisplay(), client
.window
,
1729 blackbox
->getBlackboxAttributesAtom(),
1730 blackbox
->getBlackboxAttributesAtom(), 32, PropModeReplace
,
1731 (unsigned char *) &blackbox_attrib
,
1732 PropBlackboxAttributesElements
);
1736 bool BlackboxWindow::getState(void) {
1742 unsigned long *state
, ulfoo
, nitems
;
1744 if ((XGetWindowProperty(blackbox
->getXDisplay(), client
.window
,
1745 blackbox
->getWMStateAtom(),
1746 0l, 2l, False
, blackbox
->getWMStateAtom(),
1747 &atom_return
, &foo
, &nitems
, &ulfoo
,
1748 (unsigned char **) &state
) != Success
) ||
1754 current_state
= static_cast<unsigned long>(state
[0]);
1759 XFree((void *) state
);
1765 void BlackboxWindow::restoreAttributes(void) {
1766 if (! getState()) current_state
= NormalState
;
1770 unsigned long ulfoo
, nitems
;
1772 BlackboxAttributes
*net
;
1773 int ret
= XGetWindowProperty(blackbox
->getXDisplay(), client
.window
,
1774 blackbox
->getBlackboxAttributesAtom(), 0l,
1775 PropBlackboxAttributesElements
, False
,
1776 blackbox
->getBlackboxAttributesAtom(),
1777 &atom_return
, &foo
, &nitems
, &ulfoo
,
1778 (unsigned char **) &net
);
1779 if (ret
!= Success
|| ! net
|| nitems
!= PropBlackboxAttributesElements
)
1782 if (net
->flags
& AttribShaded
&&
1783 net
->attrib
& AttribShaded
) {
1785 ((current_state
== IconicState
) ? NormalState
: current_state
);
1787 flags
.shaded
= False
;
1790 current_state
= save_state
;
1793 if ((net
->workspace
!= screen
->getCurrentWorkspaceID()) &&
1794 (net
->workspace
< screen
->getWorkspaceCount())) {
1795 screen
->reassociateWindow(this, net
->workspace
, True
);
1797 if (current_state
== NormalState
) current_state
= WithdrawnState
;
1798 } else if (current_state
== WithdrawnState
) {
1799 current_state
= NormalState
;
1802 if (net
->flags
& AttribOmnipresent
&&
1803 net
->attrib
& AttribOmnipresent
) {
1804 flags
.stuck
= False
;
1807 current_state
= NormalState
;
1810 if ((net
->flags
& AttribMaxHoriz
) ||
1811 (net
->flags
& AttribMaxVert
)) {
1812 int x
= net
->premax_x
, y
= net
->premax_y
;
1813 unsigned int w
= net
->premax_w
, h
= net
->premax_h
;
1814 flags
.maximized
= 0;
1817 if ((net
->flags
& AttribMaxHoriz
) &&
1818 (net
->flags
& AttribMaxVert
))
1819 m
= (net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1820 else if (net
->flags
& AttribMaxVert
)
1821 m
= (net
->attrib
& AttribMaxVert
) ? 2 : 0;
1822 else if (net
->flags
& AttribMaxHoriz
)
1823 m
= (net
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1827 blackbox_attrib
.premax_x
= x
;
1828 blackbox_attrib
.premax_y
= y
;
1829 blackbox_attrib
.premax_w
= w
;
1830 blackbox_attrib
.premax_h
= h
;
1833 setState(current_state
);
1835 XFree((void *) net
);
1840 * Positions the frame according the the client window position and window
1843 void BlackboxWindow::setGravityOffsets(void) {
1844 // x coordinates for each gravity type
1845 const int x_west
= client
.rect
.x();
1846 const int x_east
= client
.rect
.right() - frame
.inside_w
+ 1;
1847 const int x_center
= client
.rect
.right() - (frame
.rect
.width()/2) + 1;
1848 // y coordinates for each gravity type
1849 const int y_north
= client
.rect
.y();
1850 const int y_south
= client
.rect
.bottom() - frame
.inside_h
+ 1;
1851 const int y_center
= client
.rect
.bottom() - (frame
.rect
.height()/2) + 1;
1853 switch (client
.win_gravity
) {
1855 case NorthWestGravity
: frame
.rect
.setPos(x_west
, y_north
); break;
1856 case NorthGravity
: frame
.rect
.setPos(x_center
, y_north
); break;
1857 case NorthEastGravity
: frame
.rect
.setPos(x_east
, y_north
); break;
1858 case SouthWestGravity
: frame
.rect
.setPos(x_west
, y_south
); break;
1859 case SouthGravity
: frame
.rect
.setPos(x_center
, y_south
); break;
1860 case SouthEastGravity
: frame
.rect
.setPos(x_east
, y_south
); break;
1861 case WestGravity
: frame
.rect
.setPos(x_west
, y_center
); break;
1862 case CenterGravity
: frame
.rect
.setPos(x_center
, y_center
); break;
1863 case EastGravity
: frame
.rect
.setPos(x_east
, y_center
); break;
1867 frame
.rect
.setPos(client
.rect
.x() - frame
.margin
.left
,
1868 client
.rect
.y() - frame
.margin
.top
);
1875 * The reverse of the setGravityOffsets function. Uses the frame window's
1876 * position to find the window's reference point.
1878 void BlackboxWindow::restoreGravity(void) {
1879 // x coordinates for each gravity type
1880 const int x_west
= frame
.rect
.x();
1881 const int x_east
= frame
.rect
.x() + frame
.inside_w
- client
.rect
.width();
1882 const int x_center
= frame
.rect
.x() + (frame
.rect
.width()/2) -
1883 client
.rect
.width();
1884 // y coordinates for each gravity type
1885 const int y_north
= frame
.rect
.y();
1886 const int y_south
= frame
.rect
.y() + frame
.inside_h
- client
.rect
.height();
1887 const int y_center
= frame
.rect
.y() + (frame
.rect
.height()/2) -
1888 client
.rect
.height();
1890 switch(client
.win_gravity
) {
1892 case NorthWestGravity
: client
.rect
.setPos(x_west
, y_north
); break;
1893 case NorthGravity
: client
.rect
.setPos(x_center
, y_north
); break;
1894 case NorthEastGravity
: client
.rect
.setPos(x_east
, y_north
); break;
1895 case SouthWestGravity
: client
.rect
.setPos(x_west
, y_south
); break;
1896 case SouthGravity
: client
.rect
.setPos(x_center
, y_south
); break;
1897 case SouthEastGravity
: client
.rect
.setPos(x_east
, y_south
); break;
1898 case WestGravity
: client
.rect
.setPos(x_west
, y_center
); break;
1899 case CenterGravity
: client
.rect
.setPos(x_center
, y_center
); break;
1900 case EastGravity
: client
.rect
.setPos(x_east
, y_center
); break;
1904 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1905 frame
.rect
.top() + frame
.margin
.top
);
1911 void BlackboxWindow::redrawLabel(void) {
1912 if (flags
.focused
) {
1914 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1915 frame
.label
, frame
.flabel
);
1917 XSetWindowBackground(blackbox
->getXDisplay(),
1918 frame
.label
, frame
.flabel_pixel
);
1921 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1922 frame
.label
, frame
.ulabel
);
1924 XSetWindowBackground(blackbox
->getXDisplay(),
1925 frame
.label
, frame
.ulabel_pixel
);
1927 XClearWindow(blackbox
->getXDisplay(), frame
.label
);
1929 WindowStyle
*style
= screen
->getWindowStyle();
1931 int pos
= frame
.bevel_w
* 2,
1932 dlen
= style
->doJustify(client
.title
.c_str(), pos
, frame
.label_w
,
1933 frame
.bevel_w
* 4, i18n
.multibyte());
1935 BPen
pen((flags
.focused
) ? style
->l_text_focus
: style
->l_text_unfocus
,
1937 if (i18n
.multibyte())
1938 XmbDrawString(blackbox
->getXDisplay(), frame
.label
, style
->fontset
,
1940 (1 - style
->fontset_extents
->max_ink_extent
.y
),
1941 client
.title
.c_str(), dlen
);
1943 XDrawString(blackbox
->getXDisplay(), frame
.label
, pen
.gc(), pos
,
1944 (style
->font
->ascent
+ 1), client
.title
.c_str(), dlen
);
1948 void BlackboxWindow::redrawAllButtons(void) {
1949 if (frame
.iconify_button
) redrawIconifyButton(False
);
1950 if (frame
.maximize_button
) redrawMaximizeButton(flags
.maximized
);
1951 if (frame
.close_button
) redrawCloseButton(False
);
1955 void BlackboxWindow::redrawIconifyButton(bool pressed
) {
1957 if (flags
.focused
) {
1959 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1960 frame
.iconify_button
, frame
.fbutton
);
1962 XSetWindowBackground(blackbox
->getXDisplay(),
1963 frame
.iconify_button
, frame
.fbutton_pixel
);
1966 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1967 frame
.iconify_button
, frame
.ubutton
);
1969 XSetWindowBackground(blackbox
->getXDisplay(), frame
.iconify_button
,
1970 frame
.ubutton_pixel
);
1974 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1975 frame
.iconify_button
, frame
.pbutton
);
1977 XSetWindowBackground(blackbox
->getXDisplay(),
1978 frame
.iconify_button
, frame
.pbutton_pixel
);
1980 XClearWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
1982 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
1983 screen
->getWindowStyle()->b_pic_unfocus
);
1984 XDrawRectangle(blackbox
->getXDisplay(), frame
.iconify_button
, pen
.gc(),
1985 2, (frame
.button_w
- 5), (frame
.button_w
- 5), 2);
1989 void BlackboxWindow::redrawMaximizeButton(bool pressed
) {
1991 if (flags
.focused
) {
1993 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1994 frame
.maximize_button
, frame
.fbutton
);
1996 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
1997 frame
.fbutton_pixel
);
2000 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2001 frame
.maximize_button
, frame
.ubutton
);
2003 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2004 frame
.ubutton_pixel
);
2008 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2009 frame
.maximize_button
, frame
.pbutton
);
2011 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2012 frame
.pbutton_pixel
);
2014 XClearWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
2016 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2017 screen
->getWindowStyle()->b_pic_unfocus
);
2018 XDrawRectangle(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2019 2, 2, (frame
.button_w
- 5), (frame
.button_w
- 5));
2020 XDrawLine(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2021 2, 3, (frame
.button_w
- 3), 3);
2025 void BlackboxWindow::redrawCloseButton(bool pressed
) {
2027 if (flags
.focused
) {
2029 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2032 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2033 frame
.fbutton_pixel
);
2036 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2039 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2040 frame
.ubutton_pixel
);
2044 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2045 frame
.close_button
, frame
.pbutton
);
2047 XSetWindowBackground(blackbox
->getXDisplay(),
2048 frame
.close_button
, frame
.pbutton_pixel
);
2050 XClearWindow(blackbox
->getXDisplay(), frame
.close_button
);
2052 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2053 screen
->getWindowStyle()->b_pic_unfocus
);
2054 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2055 2, 2, (frame
.button_w
- 3), (frame
.button_w
- 3));
2056 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2057 2, (frame
.button_w
- 3), (frame
.button_w
- 3), 2);
2061 void BlackboxWindow::mapRequestEvent(XMapRequestEvent
*re
) {
2062 if (re
->window
!= client
.window
)
2066 fprintf(stderr
, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2070 bool get_state_ret
= getState();
2071 if (! (get_state_ret
&& blackbox
->isStartup())) {
2072 if ((client
.wm_hint_flags
& StateHint
) &&
2073 (! (current_state
== NormalState
|| current_state
== IconicState
)))
2074 current_state
= client
.initial_state
;
2076 current_state
= NormalState
;
2077 } else if (flags
.iconic
) {
2078 current_state
= NormalState
;
2081 switch (current_state
) {
2086 case WithdrawnState
:
2095 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2096 if (! blackbox
->isStartup() && (isTransient() || screen
->doFocusNew())) {
2097 XSync(blackbox
->getXDisplay(), False
); // make sure the frame is mapped..
2105 void BlackboxWindow::unmapNotifyEvent(XUnmapEvent
*ue
) {
2106 if (ue
->window
!= client
.window
)
2110 fprintf(stderr
, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2114 screen
->unmanageWindow(this, False
);
2118 void BlackboxWindow::destroyNotifyEvent(XDestroyWindowEvent
*de
) {
2119 if (de
->window
!= client
.window
)
2123 fprintf(stderr
, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2127 screen
->unmanageWindow(this, False
);
2131 void BlackboxWindow::reparentNotifyEvent(XReparentEvent
*re
) {
2132 if (re
->window
!= client
.window
|| re
->parent
== frame
.plate
)
2136 fprintf(stderr
, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2137 "0x%lx.\n", client
.window
, re
->parent
);
2142 XPutBackEvent(blackbox
->getXDisplay(), &ev
);
2143 screen
->unmanageWindow(this, True
);
2147 void BlackboxWindow::propertyNotifyEvent(Atom atom
) {
2150 case XA_WM_CLIENT_MACHINE
:
2154 case XA_WM_TRANSIENT_FOR
: {
2155 // determine if this is a transient window
2158 // adjust the window decorations based on transience
2159 if (isTransient()) {
2160 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2161 functions
&= ~Func_Maximize
;
2172 case XA_WM_ICON_NAME
:
2174 if (flags
.iconic
) screen
->propagateWindowName(this);
2180 if (decorations
& Decor_Titlebar
)
2183 screen
->propagateWindowName(this);
2186 case XA_WM_NORMAL_HINTS
: {
2189 if ((client
.normal_hint_flags
& PMinSize
) &&
2190 (client
.normal_hint_flags
& PMaxSize
)) {
2191 if (client
.max_width
<= client
.min_width
&&
2192 client
.max_height
<= client
.min_height
) {
2193 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2194 functions
&= ~(Func_Resize
| Func_Maximize
);
2196 decorations
|= Decor_Maximize
| Decor_Handle
;
2197 functions
|= Func_Resize
| Func_Maximize
;
2201 Rect old_rect
= frame
.rect
;
2205 if (old_rect
!= frame
.rect
)
2212 if (atom
== blackbox
->getWMProtocolsAtom()) {
2215 if ((decorations
& Decor_Close
) && (! frame
.close_button
)) {
2216 createCloseButton();
2217 if (decorations
& Decor_Titlebar
) {
2218 positionButtons(True
);
2219 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
2221 if (windowmenu
) windowmenu
->reconfigure();
2230 void BlackboxWindow::exposeEvent(XExposeEvent
*ee
) {
2231 if (frame
.label
== ee
->window
&& (decorations
& Decor_Titlebar
))
2233 else if (frame
.close_button
== ee
->window
)
2234 redrawCloseButton(False
);
2235 else if (frame
.maximize_button
== ee
->window
)
2236 redrawMaximizeButton(flags
.maximized
);
2237 else if (frame
.iconify_button
== ee
->window
)
2238 redrawIconifyButton(False
);
2242 void BlackboxWindow::configureRequestEvent(XConfigureRequestEvent
*cr
) {
2243 if (cr
->window
!= client
.window
|| flags
.iconic
)
2246 int cx
= frame
.rect
.x(), cy
= frame
.rect
.y();
2247 unsigned int cw
= frame
.rect
.width(), ch
= frame
.rect
.height();
2249 if (cr
->value_mask
& CWBorderWidth
)
2250 client
.old_bw
= cr
->border_width
;
2252 if (cr
->value_mask
& CWX
)
2253 cx
= cr
->x
- frame
.margin
.left
;
2255 if (cr
->value_mask
& CWY
)
2256 cy
= cr
->y
- frame
.margin
.top
;
2258 if (cr
->value_mask
& CWWidth
)
2259 cw
= cr
->width
+ frame
.margin
.left
+ frame
.margin
.right
;
2261 if (cr
->value_mask
& CWHeight
)
2262 ch
= cr
->height
+ frame
.margin
.top
+ frame
.margin
.bottom
;
2264 if (frame
.rect
!= Rect(cx
, cy
, cw
, ch
))
2265 configure(cx
, cy
, cw
, ch
);
2267 if (cr
->value_mask
& CWStackMode
) {
2268 switch (cr
->detail
) {
2271 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2277 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2284 void BlackboxWindow::buttonPressEvent(XButtonEvent
*be
) {
2285 if (frame
.maximize_button
== be
->window
) {
2286 redrawMaximizeButton(True
);
2287 } else if (be
->button
== 1 || (be
->button
== 3 && be
->state
== Mod1Mask
)) {
2288 if (! flags
.focused
)
2291 if (frame
.iconify_button
== be
->window
) {
2292 redrawIconifyButton(True
);
2293 } else if (frame
.close_button
== be
->window
) {
2294 redrawCloseButton(True
);
2295 } else if (frame
.plate
== be
->window
) {
2296 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2298 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2300 XAllowEvents(blackbox
->getXDisplay(), ReplayPointer
, be
->time
);
2302 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
2303 if (((be
->time
- lastButtonPressTime
) <=
2304 blackbox
->getDoubleClickInterval()) ||
2305 (be
->state
& ControlMask
)) {
2306 lastButtonPressTime
= 0;
2309 lastButtonPressTime
= be
->time
;
2313 frame
.grab_x
= be
->x_root
- frame
.rect
.x() - frame
.border_w
;
2314 frame
.grab_y
= be
->y_root
- frame
.rect
.y() - frame
.border_w
;
2316 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2318 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2320 } else if (be
->button
== 2 && (be
->window
!= frame
.iconify_button
) &&
2321 (be
->window
!= frame
.close_button
)) {
2322 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2323 } else if (windowmenu
&& be
->button
== 3 &&
2324 (frame
.title
== be
->window
|| frame
.label
== be
->window
||
2325 frame
.handle
== be
->window
|| frame
.window
== be
->window
)) {
2328 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
2329 mx
= be
->x_root
- (windowmenu
->getWidth() / 2);
2330 my
= frame
.rect
.y() + frame
.title_h
+ frame
.border_w
;
2331 } else if (frame
.handle
== be
->window
) {
2332 mx
= be
->x_root
- (windowmenu
->getWidth() / 2);
2333 my
= frame
.rect
.bottom() - frame
.handle_h
- (frame
.border_w
* 3) -
2334 windowmenu
->getHeight();
2336 mx
= be
->x_root
- (windowmenu
->getWidth() / 2);
2338 if (be
->y
<= static_cast<signed>(frame
.bevel_w
))
2339 my
= frame
.rect
.y() + frame
.title_h
;
2341 my
= be
->y_root
- (windowmenu
->getHeight() / 2);
2344 // snap the window menu into a corner if necessary - we check the
2345 // position of the menu with the coordinates of the client to
2346 // make the comparisions easier.
2347 // ### this needs some work!
2348 if (mx
> client
.rect
.right() -
2349 static_cast<signed>(windowmenu
->getWidth()))
2350 mx
= frame
.rect
.right() - windowmenu
->getWidth() - frame
.border_w
+ 1;
2351 if (mx
< client
.rect
.left())
2352 mx
= frame
.rect
.x();
2354 if (my
> client
.rect
.bottom() -
2355 static_cast<signed>(windowmenu
->getHeight()))
2356 my
= frame
.rect
.bottom() - windowmenu
->getHeight() - frame
.border_w
+ 1;
2357 if (my
< client
.rect
.top())
2358 my
= frame
.rect
.y() + ((decorations
& Decor_Titlebar
) ?
2362 if (! windowmenu
->isVisible()) {
2363 windowmenu
->move(mx
, my
);
2365 XRaiseWindow(blackbox
->getXDisplay(), windowmenu
->getWindowID());
2366 XRaiseWindow(blackbox
->getXDisplay(),
2367 windowmenu
->getSendToMenu()->getWindowID());
2376 void BlackboxWindow::buttonReleaseEvent(XButtonEvent
*re
) {
2377 if (re
->window
== frame
.maximize_button
) {
2378 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2379 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2380 maximize(re
->button
);
2382 redrawMaximizeButton(flags
.maximized
);
2384 } else if (re
->window
== frame
.iconify_button
) {
2385 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2386 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2389 redrawIconifyButton(False
);
2391 } else if (re
->window
== frame
.close_button
) {
2392 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2393 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
)))
2395 redrawCloseButton(False
);
2396 } else if (flags
.moving
) {
2397 flags
.moving
= False
;
2399 if (! screen
->doOpaqueMove()) {
2400 /* when drawing the rubber band, we need to make sure we only draw inside
2401 * the frame... frame.changing_* contain the new coords for the window,
2402 * so we need to subtract 1 from changing_w/changing_h every where we
2403 * draw the rubber band (for both moving and resizing)
2405 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2406 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
2407 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
2408 XUngrabServer(blackbox
->getXDisplay());
2410 configure(frame
.changing
.x(), frame
.changing
.y(),
2411 frame
.changing
.width(), frame
.changing
.height());
2413 configure(frame
.rect
.x(), frame
.rect
.y(),
2414 frame
.rect
.width(), frame
.rect
.height());
2416 screen
->hideGeometry();
2417 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
2418 } else if (flags
.resizing
) {
2419 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2420 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
2421 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
2422 XUngrabServer(blackbox
->getXDisplay());
2424 screen
->hideGeometry();
2426 constrain((re
->window
== frame
.left_grip
) ? TopRight
: TopLeft
);
2428 // unset maximized state when resized after fully maximized
2429 if (flags
.maximized
== 1)
2431 flags
.resizing
= False
;
2432 configure(frame
.changing
.x(), frame
.changing
.y(),
2433 frame
.changing
.width(), frame
.changing
.height());
2435 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
2436 } else if (re
->window
== frame
.window
) {
2437 if (re
->button
== 2 && re
->state
== Mod1Mask
)
2438 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
2443 void BlackboxWindow::motionNotifyEvent(XMotionEvent
*me
) {
2444 if (! flags
.resizing
&& (me
->state
& Button1Mask
) &&
2445 (functions
& Func_Move
) &&
2446 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
2447 frame
.handle
== me
->window
|| frame
.window
== me
->window
)) {
2448 if (! flags
.moving
) {
2449 XGrabPointer(blackbox
->getXDisplay(), me
->window
, False
,
2450 Button1MotionMask
| ButtonReleaseMask
,
2451 GrabModeAsync
, GrabModeAsync
,
2452 None
, blackbox
->getMoveCursor(), CurrentTime
);
2454 if (windowmenu
&& windowmenu
->isVisible())
2457 flags
.moving
= True
;
2459 if (! screen
->doOpaqueMove()) {
2460 XGrabServer(blackbox
->getXDisplay());
2462 frame
.changing
= frame
.rect
;
2463 screen
->showPosition(frame
.changing
.x(), frame
.changing
.y());
2465 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2469 frame
.changing
.width() - 1,
2470 frame
.changing
.height() - 1);
2473 int dx
= me
->x_root
- frame
.grab_x
, dy
= me
->y_root
- frame
.grab_y
;
2474 dx
-= frame
.border_w
;
2475 dy
-= frame
.border_w
;
2477 const int snap_distance
= screen
->getEdgeSnapThreshold();
2479 if (snap_distance
) {
2480 Rect srect
= screen
->availableArea();
2482 const int wleft
= dx
,
2483 wright
= dx
+ frame
.rect
.width() - 1,
2485 wbottom
= dy
+ frame
.rect
.height() - 1;
2487 int dleft
= std::abs(wleft
- srect
.left()),
2488 dright
= std::abs(wright
- srect
.right()),
2489 dtop
= std::abs(wtop
- srect
.top()),
2490 dbottom
= std::abs(wbottom
- srect
.bottom());
2493 if (dleft
< snap_distance
&& dleft
< dright
)
2496 else if (dright
< snap_distance
&& dright
< dleft
)
2497 dx
= srect
.right() - frame
.rect
.width() + 1;
2500 if (dtop
< snap_distance
&& dtop
< dbottom
)
2503 else if (dbottom
< snap_distance
&& dbottom
< dtop
)
2504 dy
= srect
.bottom() - frame
.rect
.height() + 1;
2506 srect
= screen
->getRect(); // now get the full screen
2508 dleft
= std::abs(wleft
- srect
.left()),
2509 dright
= std::abs(wright
- srect
.right()),
2510 dtop
= std::abs(wtop
- srect
.top()),
2511 dbottom
= std::abs(wbottom
- srect
.bottom());
2514 if (dleft
< snap_distance
&& dleft
< dright
)
2517 else if (dright
< snap_distance
&& dright
< dleft
)
2518 dx
= srect
.right() - frame
.rect
.width() + 1;
2521 if (dtop
< snap_distance
&& dtop
< dbottom
)
2524 else if (dbottom
< snap_distance
&& dbottom
< dtop
)
2525 dy
= srect
.bottom() - frame
.rect
.height() + 1;
2528 if (screen
->doOpaqueMove()) {
2529 configure(dx
, dy
, frame
.rect
.width(), frame
.rect
.height());
2531 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2535 frame
.changing
.width() - 1,
2536 frame
.changing
.height() - 1);
2538 frame
.changing
.setPos(dx
, dy
);
2540 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2544 frame
.changing
.width() - 1,
2545 frame
.changing
.height() - 1);
2548 screen
->showPosition(dx
, dy
);
2550 } else if ((functions
& Func_Resize
) &&
2551 (((me
->state
& Button1Mask
) &&
2552 (me
->window
== frame
.right_grip
||
2553 me
->window
== frame
.left_grip
)) ||
2554 (me
->state
& (Mod1Mask
| Button3Mask
) &&
2555 me
->window
== frame
.window
))) {
2556 bool left
= (me
->window
== frame
.left_grip
);
2558 if (! flags
.resizing
) {
2559 XGrabServer(blackbox
->getXDisplay());
2560 XGrabPointer(blackbox
->getXDisplay(), me
->window
, False
,
2561 ButtonMotionMask
| ButtonReleaseMask
,
2562 GrabModeAsync
, GrabModeAsync
, None
,
2563 ((left
) ? blackbox
->getLowerLeftAngleCursor() :
2564 blackbox
->getLowerRightAngleCursor()),
2567 flags
.resizing
= True
;
2570 frame
.grab_x
= me
->x
;
2571 frame
.grab_y
= me
->y
;
2572 frame
.changing
= frame
.rect
;
2574 constrain((left
) ? TopRight
: TopLeft
, &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);
2580 screen
->showGeometry(gw
, gh
);
2582 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2583 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
2584 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
2592 frame
.changing
.setCoords(me
->x_root
- frame
.grab_x
, frame
.rect
.top(),
2593 frame
.rect
.right(), frame
.rect
.bottom());
2594 frame
.changing
.setHeight(frame
.rect
.height() + (me
->y
- frame
.grab_y
));
2597 frame
.changing
.setSize(frame
.rect
.width() + (me
->x
- frame
.grab_x
),
2598 frame
.rect
.height() + (me
->y
- frame
.grab_y
));
2601 constrain(anchor
, &gw
, &gh
);
2603 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2604 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
2605 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
2607 screen
->showGeometry(gw
, gh
);
2614 void BlackboxWindow::shapeEvent(XShapeEvent
*) {
2615 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
2622 bool BlackboxWindow::validateClient(void) {
2623 XSync(blackbox
->getXDisplay(), False
);
2626 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
2627 DestroyNotify
, &e
) ||
2628 XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
2630 XPutBackEvent(blackbox
->getXDisplay(), &e
);
2639 void BlackboxWindow::restore(bool remap
) {
2640 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeDelete
);
2641 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
2642 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, NoEventMask
);
2646 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
2647 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
2649 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, client
.old_bw
);
2652 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
2653 ReparentNotify
, &ev
)) {
2656 // according to the ICCCM - if the client doesn't reparent to
2657 // root, then we have to do it for them
2658 XReparentWindow(blackbox
->getXDisplay(), client
.window
,
2659 screen
->getRootWindow(),
2660 client
.rect
.x(), client
.rect
.y());
2663 if (remap
) XMapWindow(blackbox
->getXDisplay(), client
.window
);
2667 // timer for autoraise
2668 void BlackboxWindow::timeout(void) {
2669 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2673 void BlackboxWindow::changeBlackboxHints(BlackboxHints
*net
) {
2674 if ((net
->flags
& AttribShaded
) &&
2675 ((blackbox_attrib
.attrib
& AttribShaded
) !=
2676 (net
->attrib
& AttribShaded
)))
2679 if (flags
.visible
&& // watch out for requests when we can not be seen
2680 (net
->flags
& (AttribMaxVert
| AttribMaxHoriz
)) &&
2681 ((blackbox_attrib
.attrib
& (AttribMaxVert
| AttribMaxHoriz
)) !=
2682 (net
->attrib
& (AttribMaxVert
| AttribMaxHoriz
)))) {
2683 if (flags
.maximized
) {
2688 if ((net
->flags
& AttribMaxHoriz
) && (net
->flags
& AttribMaxVert
))
2689 button
= ((net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0);
2690 else if (net
->flags
& AttribMaxVert
)
2691 button
= ((net
->attrib
& AttribMaxVert
) ? 2 : 0);
2692 else if (net
->flags
& AttribMaxHoriz
)
2693 button
= ((net
->attrib
& AttribMaxHoriz
) ? 3 : 0);
2699 if ((net
->flags
& AttribOmnipresent
) &&
2700 ((blackbox_attrib
.attrib
& AttribOmnipresent
) !=
2701 (net
->attrib
& AttribOmnipresent
)))
2704 if ((net
->flags
& AttribWorkspace
) &&
2705 (blackbox_attrib
.workspace
!= net
->workspace
)) {
2706 screen
->reassociateWindow(this, net
->workspace
, True
);
2708 if (screen
->getCurrentWorkspaceID() != net
->workspace
) {
2712 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2716 if (net
->flags
& AttribDecoration
) {
2717 switch (net
->decoration
) {
2719 // clear all decorations except close
2720 decorations
&= Decor_Close
;
2726 decorations
|= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
2727 Decor_Iconify
| Decor_Maximize
;
2732 decorations
|= Decor_Titlebar
| Decor_Iconify
;
2733 decorations
&= ~(Decor_Border
| Decor_Handle
| Decor_Maximize
);
2738 decorations
|= Decor_Titlebar
;
2739 decorations
&= ~(Decor_Iconify
| Decor_Border
| Decor_Handle
);
2740 functions
|= Func_Move
;
2745 // we can not be shaded if we lack a titlebar
2746 if (flags
.shaded
&& ! (decorations
& Decor_Titlebar
))
2750 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
2751 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
2755 setState(current_state
);
2761 * Set the sizes of all components of the window frame
2762 * (the window decorations).
2763 * These values are based upon the current style settings and the client
2764 * window's dimensions.
2766 void BlackboxWindow::upsize(void) {
2767 frame
.bevel_w
= screen
->getBevelWidth();
2769 if (decorations
& Decor_Border
) {
2770 frame
.border_w
= screen
->getBorderWidth();
2771 if (! isTransient())
2772 frame
.mwm_border_w
= screen
->getFrameWidth();
2774 frame
.mwm_border_w
= 0;
2776 frame
.mwm_border_w
= frame
.border_w
= 0;
2779 if (decorations
& Decor_Titlebar
) {
2780 // the height of the titlebar is based upon the height of the font being
2781 // used to display the window's title
2782 WindowStyle
*style
= screen
->getWindowStyle();
2783 if (i18n
.multibyte())
2784 frame
.title_h
= (style
->fontset_extents
->max_ink_extent
.height
+
2785 (frame
.bevel_w
* 2) + 2);
2787 frame
.title_h
= (style
->font
->ascent
+ style
->font
->descent
+
2788 (frame
.bevel_w
* 2) + 2);
2790 frame
.label_h
= frame
.title_h
- (frame
.bevel_w
* 2);
2791 frame
.button_w
= (frame
.label_h
- 2);
2793 // set the top frame margin
2794 frame
.margin
.top
= frame
.border_w
+ frame
.title_h
+
2795 frame
.border_w
+ frame
.mwm_border_w
;
2801 // set the top frame margin
2802 frame
.margin
.top
= frame
.border_w
+ frame
.mwm_border_w
;
2805 // set the left/right frame margin
2806 frame
.margin
.left
= frame
.margin
.right
= frame
.border_w
+ frame
.mwm_border_w
;
2808 if (decorations
& Decor_Handle
) {
2809 frame
.grip_w
= frame
.button_w
* 2;
2810 frame
.handle_h
= screen
->getHandleWidth();
2812 // set the bottom frame margin
2813 frame
.margin
.bottom
= frame
.border_w
+ frame
.handle_h
+
2814 frame
.border_w
+ frame
.mwm_border_w
;
2819 // set the bottom frame margin
2820 frame
.margin
.bottom
= frame
.border_w
+ frame
.mwm_border_w
;
2823 // set the frame rect
2824 frame
.rect
.setSize(client
.rect
.width() + frame
.margin
.left
+
2826 client
.rect
.height() + frame
.margin
.top
+
2827 frame
.margin
.bottom
);
2828 frame
.inside_w
= frame
.rect
.width() - (frame
.border_w
* 2);
2829 frame
.inside_h
= frame
.rect
.height() - (frame
.border_w
* 2);
2834 * Calculate the size of the client window and constrain it to the
2835 * size specified by the size hints of the client window.
2837 * The logical width and height are placed into pw and ph, if they
2838 * are non-zero. Logical size refers to the users perception of
2839 * the window size (for example an xterm has resizes in cells, not in
2842 * The physical geometry is placed into frame.changing_{x,y,width,height}.
2843 * Physical geometry refers to the geometry of the window in pixels.
2845 void BlackboxWindow::constrain(Corner anchor
, int *pw
, int *ph
) {
2846 // frame.changing represents the requested frame size, we need to
2847 // strip the frame margin off and constrain the client size
2848 frame
.changing
.setCoords(frame
.changing
.left() + frame
.margin
.left
,
2849 frame
.changing
.top() + frame
.margin
.top
,
2850 frame
.changing
.right() - frame
.margin
.right
,
2851 frame
.changing
.bottom() - frame
.margin
.bottom
);
2853 int dw
= frame
.changing
.width(), dh
= frame
.changing
.height(),
2854 base_width
= (client
.base_width
) ? client
.base_width
: client
.min_width
,
2855 base_height
= (client
.base_height
) ? client
.base_height
:
2859 if (dw
< static_cast<signed>(client
.min_width
)) dw
= client
.min_width
;
2860 if (dh
< static_cast<signed>(client
.min_height
)) dh
= client
.min_height
;
2861 if (dw
> static_cast<signed>(client
.max_width
)) dw
= client
.max_width
;
2862 if (dh
> static_cast<signed>(client
.max_height
)) dh
= client
.max_height
;
2865 dw
/= client
.width_inc
;
2867 dh
/= client
.height_inc
;
2872 dw
*= client
.width_inc
;
2874 dh
*= client
.height_inc
;
2877 frame
.changing
.setSize(dw
, dh
);
2879 // add the frame margin back onto frame.changing
2880 frame
.changing
.setCoords(frame
.changing
.left() - frame
.margin
.left
,
2881 frame
.changing
.top() - frame
.margin
.top
,
2882 frame
.changing
.right() + frame
.margin
.right
,
2883 frame
.changing
.bottom() + frame
.margin
.bottom
);
2885 // move frame.changing to the specified anchor
2892 int dx
= frame
.rect
.right() - frame
.changing
.right();
2893 frame
.changing
.setPos(frame
.changing
.x() + dx
, frame
.changing
.y());
2899 int WindowStyle::doJustify(const char *text
, int &start_pos
,
2900 unsigned int max_length
, unsigned int modifier
,
2901 bool multibyte
) const {
2902 size_t text_len
= strlen(text
);
2903 unsigned int length
;
2907 XRectangle ink
, logical
;
2908 XmbTextExtents(fontset
, text
, text_len
, &ink
, &logical
);
2909 length
= logical
.width
;
2911 length
= XTextWidth(font
, text
, text_len
);
2914 } while (length
> max_length
&& text_len
-- > 0);
2918 start_pos
+= max_length
- length
;
2922 start_pos
+= (max_length
- length
) / 2;
2934 BWindowGroup::BWindowGroup(Blackbox
*b
, Window _group
)
2935 : blackbox(b
), group(_group
) {
2936 // watch for destroy notify on the group window
2937 XSelectInput(blackbox
->getXDisplay(), group
, StructureNotifyMask
);
2938 blackbox
->saveGroupSearch(group
, this);
2942 BWindowGroup::~BWindowGroup(void) {
2943 blackbox
->removeGroupSearch(group
);
2948 BWindowGroup::find(BScreen
*screen
, bool allow_transients
) const {
2949 BlackboxWindow
*ret
= blackbox
->getFocusedWindow();
2951 // does the focus window match (or any transient_fors)?
2953 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
2954 if (ret
->isTransient() && allow_transients
) break;
2955 else if (! ret
->isTransient()) break;
2958 ret
= ret
->getTransientFor();
2961 if (ret
) return ret
;
2963 // the focus window didn't match, look in the group's window list
2964 BlackboxWindowList::const_iterator it
, end
= windowList
.end();
2965 for (it
= windowList
.begin(); it
!= end
; ++it
) {
2967 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
2968 if (ret
->isTransient() && allow_transients
) break;
2969 else if (! ret
->isTransient()) break;