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
44 #endif // HAVE_STDLIB_H
48 #include "blackbox.hh"
49 #include "Clientmenu.hh"
52 #include "Iconmenu.hh"
58 #include "Windowmenu.hh"
59 #include "Workspace.hh"
64 // change this to change what modifier keys openbox uses for mouse bindings
65 // for example: Mod1Mask | ControlMask
66 // or: ControlMask| ShiftMask
67 const unsigned int ModMask
= Mod1Mask
;
70 * Initializes the class with default values/the window's set initial values.
72 BlackboxWindow::BlackboxWindow(Blackbox
*b
, Window w
, BScreen
*s
) {
73 // fprintf(stderr, "BlackboxWindow size: %d bytes\n",
74 // sizeof(BlackboxWindow));
77 fprintf(stderr
, "BlackboxWindow::BlackboxWindow(): creating 0x%lx\n", w
);
81 set timer to zero... it is initialized properly later, so we check
82 if timer is zero in the destructor, and assume that the window is not
83 fully constructed if timer is zero...
89 xatom
= blackbox
->getXAtom();
91 if (! validateClient()) {
96 // fetch client size and placement
97 XWindowAttributes wattrib
;
98 if (! XGetWindowAttributes(blackbox
->getXDisplay(),
99 client
.window
, &wattrib
) ||
100 ! wattrib
.screen
|| wattrib
.override_redirect
) {
103 "BlackboxWindow::BlackboxWindow(): XGetWindowAttributes failed\n");
111 fprintf(stderr
, "0x%lx: initial (%d, %d) w: %d, h: %d\n", client
.window
,
112 wattrib
.x
, wattrib
.y
, wattrib
.width
, wattrib
.height
);
115 // set the eventmask early in the game so that we make sure we get
116 // all the events we are interested in
117 XSetWindowAttributes attrib_set
;
118 attrib_set
.event_mask
= PropertyChangeMask
| FocusChangeMask
|
120 attrib_set
.do_not_propagate_mask
= ButtonPressMask
| ButtonReleaseMask
|
122 XChangeWindowAttributes(blackbox
->getXDisplay(), client
.window
,
123 CWEventMask
|CWDontPropagate
, &attrib_set
);
125 flags
.moving
= flags
.resizing
= flags
.shaded
= flags
.visible
=
126 flags
.iconic
= flags
.focused
= flags
.stuck
= flags
.modal
=
127 flags
.send_focus_message
= flags
.shaped
= flags
.skip_taskbar
=
128 flags
.skip_pager
= flags
.fullscreen
= False
;
131 blackbox_attrib
.workspace
= window_number
= BSENTINEL
;
133 blackbox_attrib
.flags
= blackbox_attrib
.attrib
= blackbox_attrib
.stack
134 = blackbox_attrib
.decoration
= 0l;
135 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
136 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
139 frame
.window
= frame
.plate
= frame
.title
= frame
.handle
= None
;
140 frame
.close_button
= frame
.iconify_button
= frame
.maximize_button
= None
;
141 frame
.right_grip
= frame
.left_grip
= None
;
143 frame
.ulabel_pixel
= frame
.flabel_pixel
= frame
.utitle_pixel
=
144 frame
.ftitle_pixel
= frame
.uhandle_pixel
= frame
.fhandle_pixel
=
145 frame
.ubutton_pixel
= frame
.fbutton_pixel
= frame
.pbutton_pixel
=
146 frame
.uborder_pixel
= frame
.fborder_pixel
= frame
.ugrip_pixel
=
147 frame
.fgrip_pixel
= 0;
148 frame
.utitle
= frame
.ftitle
= frame
.uhandle
= frame
.fhandle
= None
;
149 frame
.ulabel
= frame
.flabel
= frame
.ubutton
= frame
.fbutton
= None
;
150 frame
.pbutton
= frame
.ugrip
= frame
.fgrip
= None
;
152 decorations
= Decor_Titlebar
| Decor_Border
| Decor_Handle
|
153 Decor_Iconify
| Decor_Maximize
;
154 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
156 client
.normal_hint_flags
= 0;
157 client
.window_group
= None
;
158 client
.transient_for
= 0;
160 current_state
= NormalState
;
163 get the initial size and location of client window (relative to the
164 _root window_). This position is the reference point used with the
165 window's gravity to find the window's initial position.
167 client
.rect
.setRect(wattrib
.x
, wattrib
.y
, wattrib
.width
, wattrib
.height
);
168 client
.old_bw
= wattrib
.border_width
;
171 lastButtonPressTime
= 0;
173 timer
= new BTimer(blackbox
, this);
174 timer
->setTimeout(blackbox
->getAutoRaiseDelay());
176 if (! getBlackboxHints()) {
181 // get size, aspect, minimum/maximum size and other hints set by the
188 fprintf(stderr
, "0x%lx: after hints (%d, %d) w: %d, h: %d\n", client
.window
,
189 client
.rect
.x(), client
.rect
.y(),
190 client
.rect
.width(), client
.rect
.height());
193 frame
.window
= createToplevelWindow();
194 frame
.plate
= createChildWindow(frame
.window
);
195 associateClientWindow();
197 blackbox
->saveWindowSearch(frame
.window
, this);
198 blackbox
->saveWindowSearch(frame
.plate
, this);
199 blackbox
->saveWindowSearch(client
.window
, this);
201 // determine if this is a transient window
204 // determine the window's type, so we can decide its decorations and
205 // functionality, or if we should not manage it at all
208 // adjust the window decorations/behavior based on the window type
209 switch (window_type
) {
216 // none of these windows are decorated or manipulated by the window manager
219 blackbox_attrib
.workspace
= 0; // we do need to belong to a workspace
220 flags
.stuck
= True
; // we show up on all workspaces
224 // dialogs cannot be maximized, and don't display a handle
225 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
226 functions
&= ~Func_Maximize
;
230 // normal windows retain all of the possible decorations and functionality
234 // further adjeust the window's decorations/behavior based on window sizes
235 if ((client
.normal_hint_flags
& PMinSize
) &&
236 (client
.normal_hint_flags
& PMaxSize
) &&
237 client
.max_width
<= client
.min_width
&&
238 client
.max_height
<= client
.min_height
) {
239 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
240 functions
&= ~(Func_Resize
| Func_Maximize
);
245 fprintf(stderr
, "0x%lx: sizes reflect the frame from now on\n",
247 fprintf(stderr
, "0x%lx: after upsize (%d, %d) w: %d, h: %d\n", client
.window
,
248 frame
.rect
.x(), frame
.rect
.y(),
249 frame
.rect
.width(), frame
.rect
.height());
254 bool place_window
= True
;
255 if (blackbox
->isStartup() || isTransient() ||
256 client
.normal_hint_flags
& (PPosition
|USPosition
)) {
257 applyGravity(frame
.rect
);
259 if (blackbox
->isStartup() || client
.rect
.intersects(screen
->getRect()))
260 place_window
= False
;
264 fprintf(stderr
, "0x%lx: after gravity (%d, %d) w: %d, h: %d\n",
266 frame
.rect
.x(), frame
.rect
.y(),
267 frame
.rect
.width(), frame
.rect
.height());
270 // add the window's strut. note this is done *after* placing the window.
271 screen
->addStrut(&client
.strut
);
274 if (decorations
& Decor_Titlebar
)
277 if (decorations
& Decor_Handle
)
281 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
286 windowmenu
= new Windowmenu(this);
288 if (blackbox_attrib
.workspace
>= screen
->getWorkspaceCount())
289 screen
->getCurrentWorkspace()->addWindow(this, place_window
);
291 screen
->getWorkspace(blackbox_attrib
.workspace
)->
292 addWindow(this, place_window
);
294 if (! place_window
) {
295 // don't need to call configure if we are letting the workspace
297 configure(frame
.rect
.x(), frame
.rect
.y(),
298 frame
.rect
.width(), frame
.rect
.height());
301 fprintf(stderr
, "0x%lx: after configure (%d, %d) w: %d, h: %d\n",
303 frame
.rect
.x(), frame
.rect
.y(),
304 frame
.rect
.width(), frame
.rect
.height());
308 // preserve the window's initial state on first map, and its current state
310 unsigned long initial_state
= current_state
;
312 current_state
= initial_state
;
314 // get sticky state from our parent window if we've got one
315 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
316 client
.transient_for
->isStuck() != flags
.stuck
)
320 flags
.shaded
= False
;
321 initial_state
= current_state
;
325 At this point in the life of a window, current_state should only be set
326 to IconicState if the window was an *icon*, not if it was shaded.
328 if (initial_state
!= IconicState
)
329 current_state
= NormalState
;
337 if (flags
.maximized
&& (functions
& Func_Maximize
))
341 When the window is mapped (and also when its attributes are restored), the
342 current_state that was set here will be used.
343 It is set to Normal if the window is to be mapped or it is set to Iconic
344 if the window is to be iconified.
345 *Note* that for sticky windows, the same rules apply here, they are in
346 fact never set to Iconic since there is no way for us to tell if a sticky
347 window was iconified previously.
354 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
359 fprintf(stderr
, "0x%lx: end of constructor (%d, %d) w: %d, h: %d\n",
361 frame
.rect
.x(), frame
.rect
.y(),
362 frame
.rect
.width(), frame
.rect
.height());
367 BlackboxWindow::~BlackboxWindow(void) {
369 fprintf(stderr
, "BlackboxWindow::~BlackboxWindow: destroying 0x%lx\n",
373 if (! timer
) // window not managed...
376 screen
->removeStrut(&client
.strut
);
377 screen
->updateAvailableArea();
379 // We don't need to worry about resizing because resizing always grabs the X
380 // server. This should only ever happen if using opaque moving.
388 if (client
.window_group
) {
389 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
390 if (group
) group
->removeWindow(this);
393 // remove ourselves from our transient_for
395 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
396 client
.transient_for
->client
.transientList
.remove(this);
398 client
.transient_for
= (BlackboxWindow
*) 0;
401 if (client
.transientList
.size() > 0) {
402 // reset transient_for for all transients
403 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
404 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
405 (*it
)->client
.transient_for
= (BlackboxWindow
*) 0;
416 blackbox
->removeWindowSearch(frame
.plate
);
417 XDestroyWindow(blackbox
->getXDisplay(), frame
.plate
);
421 blackbox
->removeWindowSearch(frame
.window
);
422 XDestroyWindow(blackbox
->getXDisplay(), frame
.window
);
425 blackbox
->removeWindowSearch(client
.window
);
430 * Creates a new top level window, with a given location, size, and border
432 * Returns: the newly created window
434 Window
BlackboxWindow::createToplevelWindow(void) {
435 XSetWindowAttributes attrib_create
;
436 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
| CWColormap
|
437 CWOverrideRedirect
| CWEventMask
;
439 attrib_create
.background_pixmap
= None
;
440 attrib_create
.colormap
= screen
->getColormap();
441 attrib_create
.override_redirect
= True
;
442 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
443 ButtonMotionMask
| EnterWindowMask
;
445 return XCreateWindow(blackbox
->getXDisplay(), screen
->getRootWindow(),
446 0, 0, 1, 1, frame
.border_w
, screen
->getDepth(),
447 InputOutput
, screen
->getVisual(), create_mask
,
453 * Creates a child window, and optionally associates a given cursor with
456 Window
BlackboxWindow::createChildWindow(Window parent
, Cursor cursor
) {
457 XSetWindowAttributes attrib_create
;
458 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
|
461 attrib_create
.background_pixmap
= None
;
462 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
463 ButtonMotionMask
| ExposureMask
;
466 create_mask
|= CWCursor
;
467 attrib_create
.cursor
= cursor
;
470 return XCreateWindow(blackbox
->getXDisplay(), parent
, 0, 0, 1, 1, 0,
471 screen
->getDepth(), InputOutput
, screen
->getVisual(),
472 create_mask
, &attrib_create
);
476 void BlackboxWindow::associateClientWindow(void) {
477 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, 0);
481 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeInsert
);
483 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, SubstructureRedirectMask
);
485 XGrabServer(blackbox
->getXDisplay());
487 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
489 XSelectInput(blackbox
->getXDisplay(), client
.window
,
490 event_mask
& ~StructureNotifyMask
);
491 XReparentWindow(blackbox
->getXDisplay(), client
.window
, frame
.plate
, 0, 0);
492 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
494 XUngrabServer(blackbox
->getXDisplay());
496 XRaiseWindow(blackbox
->getXDisplay(), frame
.plate
);
497 XMapSubwindows(blackbox
->getXDisplay(), frame
.plate
);
501 if (blackbox
->hasShapeExtensions()) {
502 XShapeSelectInput(blackbox
->getXDisplay(), client
.window
,
509 XShapeQueryExtents(blackbox
->getXDisplay(), client
.window
, &shaped
,
510 &foo
, &foo
, &ufoo
, &ufoo
, &foo
, &foo
, &foo
,
512 flags
.shaped
= shaped
;
518 void BlackboxWindow::decorate(void) {
521 texture
= &(screen
->getWindowStyle()->b_focus
);
522 frame
.fbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
525 frame
.fbutton_pixel
= texture
->color().pixel();
527 texture
= &(screen
->getWindowStyle()->b_unfocus
);
528 frame
.ubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
531 frame
.ubutton_pixel
= texture
->color().pixel();
533 texture
= &(screen
->getWindowStyle()->b_pressed
);
534 frame
.pbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
537 frame
.pbutton_pixel
= texture
->color().pixel();
539 if (decorations
& Decor_Titlebar
) {
540 texture
= &(screen
->getWindowStyle()->t_focus
);
541 frame
.ftitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
544 frame
.ftitle_pixel
= texture
->color().pixel();
546 texture
= &(screen
->getWindowStyle()->t_unfocus
);
547 frame
.utitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
550 frame
.utitle_pixel
= texture
->color().pixel();
552 XSetWindowBorder(blackbox
->getXDisplay(), frame
.title
,
553 screen
->getBorderColor()->pixel());
558 if (decorations
& Decor_Border
) {
559 frame
.fborder_pixel
= screen
->getWindowStyle()->f_focus
.pixel();
560 frame
.uborder_pixel
= screen
->getWindowStyle()->f_unfocus
.pixel();
561 blackbox_attrib
.flags
|= AttribDecoration
;
562 blackbox_attrib
.decoration
= DecorNormal
;
564 blackbox_attrib
.flags
|= AttribDecoration
;
565 blackbox_attrib
.decoration
= DecorNone
;
568 if (decorations
& Decor_Handle
) {
569 texture
= &(screen
->getWindowStyle()->h_focus
);
570 frame
.fhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
573 frame
.fhandle_pixel
= texture
->color().pixel();
575 texture
= &(screen
->getWindowStyle()->h_unfocus
);
576 frame
.uhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
579 frame
.uhandle_pixel
= texture
->color().pixel();
581 texture
= &(screen
->getWindowStyle()->g_focus
);
582 frame
.fgrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.fgrip
);
584 frame
.fgrip_pixel
= texture
->color().pixel();
586 texture
= &(screen
->getWindowStyle()->g_unfocus
);
587 frame
.ugrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.ugrip
);
589 frame
.ugrip_pixel
= texture
->color().pixel();
591 XSetWindowBorder(blackbox
->getXDisplay(), frame
.handle
,
592 screen
->getBorderColor()->pixel());
593 XSetWindowBorder(blackbox
->getXDisplay(), frame
.left_grip
,
594 screen
->getBorderColor()->pixel());
595 XSetWindowBorder(blackbox
->getXDisplay(), frame
.right_grip
,
596 screen
->getBorderColor()->pixel());
599 XSetWindowBorder(blackbox
->getXDisplay(), frame
.window
,
600 screen
->getBorderColor()->pixel());
604 void BlackboxWindow::decorateLabel(void) {
607 texture
= &(screen
->getWindowStyle()->l_focus
);
608 frame
.flabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.flabel
);
610 frame
.flabel_pixel
= texture
->color().pixel();
612 texture
= &(screen
->getWindowStyle()->l_unfocus
);
613 frame
.ulabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.ulabel
);
615 frame
.ulabel_pixel
= texture
->color().pixel();
619 void BlackboxWindow::createHandle(void) {
620 frame
.handle
= createChildWindow(frame
.window
);
621 blackbox
->saveWindowSearch(frame
.handle
, this);
624 createChildWindow(frame
.handle
, blackbox
->getLowerLeftAngleCursor());
625 blackbox
->saveWindowSearch(frame
.left_grip
, this);
628 createChildWindow(frame
.handle
, blackbox
->getLowerRightAngleCursor());
629 blackbox
->saveWindowSearch(frame
.right_grip
, this);
633 void BlackboxWindow::destroyHandle(void) {
635 screen
->getImageControl()->removeImage(frame
.fhandle
);
638 screen
->getImageControl()->removeImage(frame
.uhandle
);
641 screen
->getImageControl()->removeImage(frame
.fgrip
);
644 screen
->getImageControl()->removeImage(frame
.ugrip
);
646 blackbox
->removeWindowSearch(frame
.left_grip
);
647 blackbox
->removeWindowSearch(frame
.right_grip
);
649 XDestroyWindow(blackbox
->getXDisplay(), frame
.left_grip
);
650 XDestroyWindow(blackbox
->getXDisplay(), frame
.right_grip
);
651 frame
.left_grip
= frame
.right_grip
= None
;
653 blackbox
->removeWindowSearch(frame
.handle
);
654 XDestroyWindow(blackbox
->getXDisplay(), frame
.handle
);
659 void BlackboxWindow::createTitlebar(void) {
660 frame
.title
= createChildWindow(frame
.window
);
661 frame
.label
= createChildWindow(frame
.title
);
662 blackbox
->saveWindowSearch(frame
.title
, this);
663 blackbox
->saveWindowSearch(frame
.label
, this);
665 if (decorations
& Decor_Iconify
) createIconifyButton();
666 if (decorations
& Decor_Maximize
) createMaximizeButton();
667 if (decorations
& Decor_Close
) createCloseButton();
671 void BlackboxWindow::destroyTitlebar(void) {
672 if (frame
.close_button
)
673 destroyCloseButton();
675 if (frame
.iconify_button
)
676 destroyIconifyButton();
678 if (frame
.maximize_button
)
679 destroyMaximizeButton();
682 screen
->getImageControl()->removeImage(frame
.ftitle
);
685 screen
->getImageControl()->removeImage(frame
.utitle
);
688 screen
->getImageControl()->removeImage(frame
.flabel
);
691 screen
->getImageControl()->removeImage(frame
.ulabel
);
694 screen
->getImageControl()->removeImage(frame
.fbutton
);
697 screen
->getImageControl()->removeImage(frame
.ubutton
);
700 screen
->getImageControl()->removeImage(frame
.pbutton
);
702 blackbox
->removeWindowSearch(frame
.title
);
703 blackbox
->removeWindowSearch(frame
.label
);
705 XDestroyWindow(blackbox
->getXDisplay(), frame
.label
);
706 XDestroyWindow(blackbox
->getXDisplay(), frame
.title
);
707 frame
.title
= frame
.label
= None
;
711 void BlackboxWindow::createCloseButton(void) {
712 if (frame
.title
!= None
) {
713 frame
.close_button
= createChildWindow(frame
.title
);
714 blackbox
->saveWindowSearch(frame
.close_button
, this);
719 void BlackboxWindow::destroyCloseButton(void) {
720 blackbox
->removeWindowSearch(frame
.close_button
);
721 XDestroyWindow(blackbox
->getXDisplay(), frame
.close_button
);
722 frame
.close_button
= None
;
726 void BlackboxWindow::createIconifyButton(void) {
727 if (frame
.title
!= None
) {
728 frame
.iconify_button
= createChildWindow(frame
.title
);
729 blackbox
->saveWindowSearch(frame
.iconify_button
, this);
734 void BlackboxWindow::destroyIconifyButton(void) {
735 blackbox
->removeWindowSearch(frame
.iconify_button
);
736 XDestroyWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
737 frame
.iconify_button
= None
;
741 void BlackboxWindow::createMaximizeButton(void) {
742 if (frame
.title
!= None
) {
743 frame
.maximize_button
= createChildWindow(frame
.title
);
744 blackbox
->saveWindowSearch(frame
.maximize_button
, this);
749 void BlackboxWindow::destroyMaximizeButton(void) {
750 blackbox
->removeWindowSearch(frame
.maximize_button
);
751 XDestroyWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
752 frame
.maximize_button
= None
;
756 void BlackboxWindow::positionButtons(bool redecorate_label
) {
757 string layout
= blackbox
->getTitlebarLayout();
760 bool hasclose
, hasiconify
, hasmaximize
, haslabel
;
761 hasclose
= hasiconify
= hasmaximize
= haslabel
= false;
763 string::const_iterator it
, end
;
764 for (it
= layout
.begin(), end
= layout
.end(); it
!= end
; ++it
) {
767 if (! hasclose
&& (decorations
& Decor_Close
)) {
773 if (! hasiconify
&& (decorations
& Decor_Iconify
)) {
779 if (! hasmaximize
&& (decorations
& Decor_Maximize
)) {
791 if (! hasclose
&& frame
.close_button
)
792 destroyCloseButton();
793 if (! hasiconify
&& frame
.iconify_button
)
794 destroyIconifyButton();
795 if (! hasmaximize
&& frame
.maximize_button
)
796 destroyMaximizeButton();
798 parsed
+= 'L'; // require that the label be in the layout
800 const unsigned int bsep
= frame
.bevel_w
+ 1; // separation between elements
801 const unsigned int by
= frame
.bevel_w
+ 1;
802 const unsigned int ty
= frame
.bevel_w
;
804 frame
.label_w
= frame
.inside_w
- bsep
* 2 -
805 (frame
.button_w
+ bsep
) * (parsed
.size() - 1);
807 unsigned int x
= bsep
;
808 for (it
= parsed
.begin(), end
= parsed
.end(); it
!= end
; ++it
) {
811 if (! frame
.close_button
) createCloseButton();
812 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.close_button
, x
, by
,
813 frame
.button_w
, frame
.button_w
);
814 x
+= frame
.button_w
+ bsep
;
817 if (! frame
.iconify_button
) createIconifyButton();
818 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.iconify_button
, x
, by
,
819 frame
.button_w
, frame
.button_w
);
820 x
+= frame
.button_w
+ bsep
;
823 if (! frame
.maximize_button
) createMaximizeButton();
824 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.maximize_button
, x
, by
,
825 frame
.button_w
, frame
.button_w
);
826 x
+= frame
.button_w
+ bsep
;
829 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.label
, x
, ty
,
830 frame
.label_w
, frame
.label_h
);
831 x
+= frame
.label_w
+ bsep
;
836 if (redecorate_label
) decorateLabel();
842 void BlackboxWindow::reconfigure(void) {
843 restoreGravity(client
.rect
);
845 applyGravity(frame
.rect
);
854 windowmenu
->move(windowmenu
->getX(), frame
.rect
.y() + frame
.title_h
);
855 windowmenu
->reconfigure();
860 void BlackboxWindow::grabButtons(void) {
861 if (! screen
->isSloppyFocus() || screen
->doClickRaise())
862 // grab button 1 for changing focus/raising
863 blackbox
->grabButton(Button1
, 0, frame
.plate
, True
, ButtonPressMask
,
864 GrabModeSync
, GrabModeSync
, frame
.plate
, None
,
865 screen
->allowScrollLock());
867 if (functions
& Func_Move
)
868 blackbox
->grabButton(Button1
, ModMask
, frame
.window
, True
,
869 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
870 GrabModeAsync
, frame
.window
, None
,
871 screen
->allowScrollLock());
872 if (functions
& Func_Resize
)
873 blackbox
->grabButton(Button3
, ModMask
, frame
.window
, True
,
874 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
875 GrabModeAsync
, frame
.window
, None
,
876 screen
->allowScrollLock());
877 // alt+middle lowers the window
878 blackbox
->grabButton(Button2
, ModMask
, frame
.window
, True
,
879 ButtonReleaseMask
, GrabModeAsync
, GrabModeAsync
,
881 screen
->allowScrollLock());
885 void BlackboxWindow::ungrabButtons(void) {
886 if (! screen
->isSloppyFocus() || screen
->doClickRaise())
887 blackbox
->ungrabButton(Button1
, 0, frame
.plate
);
889 blackbox
->ungrabButton(Button1
, ModMask
, frame
.window
);
890 blackbox
->ungrabButton(Button2
, ModMask
, frame
.window
);
891 blackbox
->ungrabButton(Button3
, ModMask
, frame
.window
);
895 void BlackboxWindow::positionWindows(void) {
896 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.window
,
897 frame
.rect
.x(), frame
.rect
.y(), frame
.inside_w
,
898 (flags
.shaded
) ? frame
.title_h
: frame
.inside_h
);
899 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.window
,
901 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.plate
,
903 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.plate
,
904 frame
.margin
.left
- frame
.mwm_border_w
- frame
.border_w
,
905 frame
.margin
.top
- frame
.mwm_border_w
- frame
.border_w
,
906 client
.rect
.width(), client
.rect
.height());
907 XMoveResizeWindow(blackbox
->getXDisplay(), client
.window
,
908 0, 0, client
.rect
.width(), client
.rect
.height());
909 // ensure client.rect contains the real location
910 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
911 frame
.rect
.top() + frame
.margin
.top
);
913 if (decorations
& Decor_Titlebar
) {
914 if (frame
.title
== None
) createTitlebar();
916 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.title
,
918 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.title
, -frame
.border_w
,
919 -frame
.border_w
, frame
.inside_w
, frame
.title_h
);
922 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
923 XMapWindow(blackbox
->getXDisplay(), frame
.title
);
924 } else if (frame
.title
) {
927 if (decorations
& Decor_Handle
) {
928 if (frame
.handle
== None
) createHandle();
929 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.handle
,
931 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.left_grip
,
933 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.right_grip
,
936 // use client.rect here so the value is correct even if shaded
937 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.handle
,
939 client
.rect
.height() + frame
.margin
.top
+
940 frame
.mwm_border_w
- frame
.border_w
,
941 frame
.inside_w
, frame
.handle_h
);
942 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.left_grip
,
943 -frame
.border_w
, -frame
.border_w
,
944 frame
.grip_w
, frame
.handle_h
);
945 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.right_grip
,
946 frame
.inside_w
- frame
.grip_w
- frame
.border_w
,
947 -frame
.border_w
, frame
.grip_w
, frame
.handle_h
);
949 XMapSubwindows(blackbox
->getXDisplay(), frame
.handle
);
950 XMapWindow(blackbox
->getXDisplay(), frame
.handle
);
951 } else if (frame
.handle
) {
954 XSync(blackbox
->getXDisplay(), False
);
958 void BlackboxWindow::updateStrut(void) {
959 unsigned long num
= 4;
961 if (! xatom
->getValue(client
.window
, XAtom::net_wm_strut
, XAtom::cardinal
,
966 client
.strut
.left
= data
[0];
967 client
.strut
.right
= data
[1];
968 client
.strut
.top
= data
[2];
969 client
.strut
.bottom
= data
[3];
971 screen
->updateAvailableArea();
978 void BlackboxWindow::getWindowType(void) {
980 if (xatom
->getValue(client
.window
, XAtom::net_wm_window_type
, XAtom::atom
,
982 if (val
== xatom
->getAtom(XAtom::net_wm_window_type_desktop
))
983 window_type
= Type_Desktop
;
984 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_dock
))
985 window_type
= Type_Dock
;
986 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_toolbar
))
987 window_type
= Type_Toolbar
;
988 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_menu
))
989 window_type
= Type_Menu
;
990 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_utility
))
991 window_type
= Type_Utility
;
992 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_splash
))
993 window_type
= Type_Splash
;
994 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_dialog
))
995 window_type
= Type_Dialog
;
996 else //if (val[0] == xatom->getAtom(XAtom::net_wm_window_type_normal))
997 window_type
= Type_Normal
;
1002 * the window type hint was not set, which means we either classify ourself
1003 * as a normal window or a dialog, depending on if we are a transient.
1006 window_type
= Type_Dialog
;
1008 window_type
= Type_Normal
;
1012 void BlackboxWindow::getWMName(void) {
1013 if (xatom
->getValue(client
.window
, XAtom::net_wm_name
,
1014 XAtom::utf8
, client
.title
) &&
1015 !client
.title
.empty()) {
1016 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
1019 //fall through to using WM_NAME
1020 if (xatom
->getValue(client
.window
, XAtom::wm_name
, XAtom::ansi
, client
.title
)
1021 && !client
.title
.empty()) {
1022 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
1025 // fall back to an internal default
1026 client
.title
= i18n(WindowSet
, WindowUnnamed
, "Unnamed");
1027 xatom
->setValue(client
.window
, XAtom::net_wm_visible_name
, XAtom::utf8
,
1032 void BlackboxWindow::getWMIconName(void) {
1033 if (xatom
->getValue(client
.window
, XAtom::net_wm_icon_name
,
1034 XAtom::utf8
, client
.icon_title
) &&
1035 !client
.icon_title
.empty()) {
1036 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1039 //fall through to using WM_ICON_NAME
1040 if (xatom
->getValue(client
.window
, XAtom::wm_icon_name
, XAtom::ansi
,
1041 client
.icon_title
) &&
1042 !client
.icon_title
.empty()) {
1043 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1046 // fall back to using the main name
1047 client
.icon_title
= client
.title
;
1048 xatom
->setValue(client
.window
, XAtom::net_wm_visible_icon_name
, XAtom::utf8
,
1054 * Retrieve which WM Protocols are supported by the client window.
1055 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
1056 * window's decorations and allow the close behavior.
1057 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
1060 void BlackboxWindow::getWMProtocols(void) {
1064 if (XGetWMProtocols(blackbox
->getXDisplay(), client
.window
,
1065 &proto
, &num_return
)) {
1066 for (int i
= 0; i
< num_return
; ++i
) {
1067 if (proto
[i
] == xatom
->getAtom(XAtom::wm_delete_window
)) {
1068 decorations
|= Decor_Close
;
1069 functions
|= Func_Close
;
1070 } else if (proto
[i
] == xatom
->getAtom(XAtom::wm_take_focus
)) {
1071 flags
.send_focus_message
= True
;
1081 * Gets the value of the WM_HINTS property.
1082 * If the property is not set, then use a set of default values.
1084 void BlackboxWindow::getWMHints(void) {
1085 focus_mode
= F_Passive
;
1087 // remove from current window group
1088 if (client
.window_group
) {
1089 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1090 if (group
) group
->removeWindow(this);
1092 client
.window_group
= None
;
1094 XWMHints
*wmhint
= XGetWMHints(blackbox
->getXDisplay(), client
.window
);
1099 if (wmhint
->flags
& InputHint
) {
1100 if (wmhint
->input
== True
) {
1101 if (flags
.send_focus_message
)
1102 focus_mode
= F_LocallyActive
;
1104 if (flags
.send_focus_message
)
1105 focus_mode
= F_GloballyActive
;
1107 focus_mode
= F_NoInput
;
1111 if (wmhint
->flags
& StateHint
)
1112 current_state
= wmhint
->initial_state
;
1114 if (wmhint
->flags
& WindowGroupHint
) {
1115 client
.window_group
= wmhint
->window_group
;
1117 // add window to the appropriate group
1118 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1119 if (! group
) { // no group found, create it!
1120 new BWindowGroup(blackbox
, client
.window_group
);
1121 group
= blackbox
->searchGroup(client
.window_group
);
1124 group
->addWindow(this);
1132 * Gets the value of the WM_NORMAL_HINTS property.
1133 * If the property is not set, then use a set of default values.
1135 void BlackboxWindow::getWMNormalHints(void) {
1137 XSizeHints sizehint
;
1139 client
.min_width
= client
.min_height
=
1140 client
.width_inc
= client
.height_inc
= 1;
1141 client
.base_width
= client
.base_height
= 0;
1142 client
.win_gravity
= NorthWestGravity
;
1144 client
.min_aspect_x
= client
.min_aspect_y
=
1145 client
.max_aspect_x
= client
.max_aspect_y
= 1;
1149 use the full screen, not the strut modified size. otherwise when the
1150 availableArea changes max_width/height will be incorrect and lead to odd
1153 const Rect
& screen_area
= screen
->getRect();
1154 client
.max_width
= screen_area
.width();
1155 client
.max_height
= screen_area
.height();
1157 if (! XGetWMNormalHints(blackbox
->getXDisplay(), client
.window
,
1158 &sizehint
, &icccm_mask
))
1161 client
.normal_hint_flags
= sizehint
.flags
;
1163 if (sizehint
.flags
& PMinSize
) {
1164 if (sizehint
.min_width
>= 0)
1165 client
.min_width
= sizehint
.min_width
;
1166 if (sizehint
.min_height
>= 0)
1167 client
.min_height
= sizehint
.min_height
;
1170 if (sizehint
.flags
& PMaxSize
) {
1171 if (sizehint
.max_width
> static_cast<signed>(client
.min_width
))
1172 client
.max_width
= sizehint
.max_width
;
1174 client
.max_width
= client
.min_width
;
1176 if (sizehint
.max_height
> static_cast<signed>(client
.min_height
))
1177 client
.max_height
= sizehint
.max_height
;
1179 client
.max_height
= client
.min_height
;
1182 if (sizehint
.flags
& PResizeInc
) {
1183 client
.width_inc
= sizehint
.width_inc
;
1184 client
.height_inc
= sizehint
.height_inc
;
1187 #if 0 // we do not support this at the moment
1188 if (sizehint
.flags
& PAspect
) {
1189 client
.min_aspect_x
= sizehint
.min_aspect
.x
;
1190 client
.min_aspect_y
= sizehint
.min_aspect
.y
;
1191 client
.max_aspect_x
= sizehint
.max_aspect
.x
;
1192 client
.max_aspect_y
= sizehint
.max_aspect
.y
;
1196 if (sizehint
.flags
& PBaseSize
) {
1197 client
.base_width
= sizehint
.base_width
;
1198 client
.base_height
= sizehint
.base_height
;
1201 if (sizehint
.flags
& PWinGravity
)
1202 client
.win_gravity
= sizehint
.win_gravity
;
1207 * Gets the NETWM hints for the class' contained window.
1209 void BlackboxWindow::getNetWMHints(void) {
1210 unsigned long workspace
;
1212 if (xatom
->getValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1214 if (workspace
== 0xffffffff)
1217 blackbox_attrib
.workspace
= workspace
;
1220 unsigned long *state
;
1221 unsigned long num
= (unsigned) -1;
1222 if (xatom
->getValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
1226 for (unsigned long i
= 0; i
< num
; ++i
) {
1227 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
))
1229 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_shaded
))
1230 flags
.shaded
= True
;
1231 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
))
1232 flags
.skip_taskbar
= True
;
1233 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_pager
))
1234 flags
.skip_pager
= True
;
1235 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_fullscreen
))
1236 flags
.fullscreen
= True
;
1237 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_hidden
))
1238 setState(IconicState
);
1239 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_vert
))
1241 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_horz
))
1245 flags
.maximized
= 1;
1247 flags
.maximized
= 2;
1249 flags
.maximized
= 3;
1257 * Gets the MWM hints for the class' contained window.
1258 * This is used while initializing the window to its first state, and not
1260 * Returns: true if the MWM hints are successfully retreived and applied;
1261 * false if they are not.
1263 void BlackboxWindow::getMWMHints(void) {
1267 num
= PropMwmHintsElements
;
1268 if (! xatom
->getValue(client
.window
, XAtom::motif_wm_hints
,
1269 XAtom::motif_wm_hints
, num
,
1270 (unsigned long **)&mwm_hint
))
1272 if (num
< PropMwmHintsElements
) {
1277 if (mwm_hint
->flags
& MwmHintsDecorations
) {
1278 if (mwm_hint
->decorations
& MwmDecorAll
) {
1279 decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
1280 Decor_Iconify
| Decor_Maximize
| Decor_Close
;
1284 if (mwm_hint
->decorations
& MwmDecorBorder
)
1285 decorations
|= Decor_Border
;
1286 if (mwm_hint
->decorations
& MwmDecorHandle
)
1287 decorations
|= Decor_Handle
;
1288 if (mwm_hint
->decorations
& MwmDecorTitle
)
1289 decorations
|= Decor_Titlebar
;
1290 if (mwm_hint
->decorations
& MwmDecorIconify
)
1291 decorations
|= Decor_Iconify
;
1292 if (mwm_hint
->decorations
& MwmDecorMaximize
)
1293 decorations
|= Decor_Maximize
;
1297 if (mwm_hint
->flags
& MwmHintsFunctions
) {
1298 if (mwm_hint
->functions
& MwmFuncAll
) {
1299 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
|
1304 if (mwm_hint
->functions
& MwmFuncResize
)
1305 functions
|= Func_Resize
;
1306 if (mwm_hint
->functions
& MwmFuncMove
)
1307 functions
|= Func_Move
;
1308 if (mwm_hint
->functions
& MwmFuncIconify
)
1309 functions
|= Func_Iconify
;
1310 if (mwm_hint
->functions
& MwmFuncMaximize
)
1311 functions
|= Func_Maximize
;
1312 if (mwm_hint
->functions
& MwmFuncClose
)
1313 functions
|= Func_Close
;
1321 * Gets the blackbox hints from the class' contained window.
1322 * This is used while initializing the window to its first state, and not
1324 * Returns: true if the hints are successfully retreived and applied; false if
1327 bool BlackboxWindow::getBlackboxHints(void) {
1329 BlackboxHints
*blackbox_hint
;
1331 num
= PropBlackboxHintsElements
;
1332 if (! xatom
->getValue(client
.window
, XAtom::blackbox_hints
,
1333 XAtom::blackbox_hints
, num
,
1334 (unsigned long **)&blackbox_hint
))
1336 if (num
< PropBlackboxHintsElements
) {
1337 delete [] blackbox_hint
;
1341 if (blackbox_hint
->flags
& AttribShaded
)
1342 flags
.shaded
= (blackbox_hint
->attrib
& AttribShaded
);
1344 if ((blackbox_hint
->flags
& AttribMaxHoriz
) &&
1345 (blackbox_hint
->flags
& AttribMaxVert
))
1346 flags
.maximized
= (blackbox_hint
->attrib
&
1347 (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1348 else if (blackbox_hint
->flags
& AttribMaxVert
)
1349 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxVert
) ? 2 : 0;
1350 else if (blackbox_hint
->flags
& AttribMaxHoriz
)
1351 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1353 if (blackbox_hint
->flags
& AttribOmnipresent
)
1354 flags
.stuck
= (blackbox_hint
->attrib
& AttribOmnipresent
);
1356 if (blackbox_hint
->flags
& AttribWorkspace
)
1357 blackbox_attrib
.workspace
= blackbox_hint
->workspace
;
1359 // if (blackbox_hint->flags & AttribStack)
1360 // don't yet have always on top/bottom for blackbox yet... working
1363 if (blackbox_hint
->flags
& AttribDecoration
) {
1364 switch (blackbox_hint
->decoration
) {
1370 decorations
|= Decor_Titlebar
| Decor_Iconify
;
1371 decorations
&= ~(Decor_Border
| Decor_Handle
| Decor_Maximize
);
1372 functions
&= ~(Func_Resize
| Func_Maximize
);
1377 decorations
|= Decor_Titlebar
;
1378 decorations
&= ~(Decor_Iconify
| Decor_Border
| Decor_Handle
);
1379 functions
&= ~(Func_Resize
| Func_Maximize
| Func_Iconify
);
1385 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Handle
|
1386 Decor_Iconify
| Decor_Maximize
;
1393 delete [] blackbox_hint
;
1399 void BlackboxWindow::getTransientInfo(void) {
1400 if (client
.transient_for
&&
1401 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1402 // reset transient_for in preparation of looking for a new owner
1403 client
.transient_for
->client
.transientList
.remove(this);
1406 // we have no transient_for until we find a new one
1407 client
.transient_for
= 0;
1410 if (! XGetTransientForHint(blackbox
->getXDisplay(), client
.window
,
1412 // transient_for hint not set
1416 if (trans_for
== client
.window
) {
1417 // wierd client... treat this window as a normal window
1421 if (trans_for
== None
|| trans_for
== screen
->getRootWindow()) {
1422 // this is an undocumented interpretation of the ICCCM. a transient
1423 // associated with None/Root/itself is assumed to be a modal root
1424 // transient. we don't support the concept of a global transient,
1425 // so we just associate this transient with nothing, and perhaps
1426 // we will add support later for global modality.
1427 client
.transient_for
= (BlackboxWindow
*) ~0ul;
1432 client
.transient_for
= blackbox
->searchWindow(trans_for
);
1433 if (! client
.transient_for
&&
1434 client
.window_group
&& trans_for
== client
.window_group
) {
1435 // no direct transient_for, perhaps this is a group transient?
1436 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1437 if (group
) client
.transient_for
= group
->find(screen
);
1440 if (! client
.transient_for
|| client
.transient_for
== this) {
1441 // no transient_for found, or we have a wierd client that wants to be
1442 // a transient for itself, so we treat this window as a normal window
1443 client
.transient_for
= (BlackboxWindow
*) 0;
1447 // register ourselves with our new transient_for
1448 client
.transient_for
->client
.transientList
.push_back(this);
1449 flags
.stuck
= client
.transient_for
->flags
.stuck
;
1453 BlackboxWindow
*BlackboxWindow::getTransientFor(void) const {
1454 if (client
.transient_for
&&
1455 client
.transient_for
!= (BlackboxWindow
*) ~0ul)
1456 return client
.transient_for
;
1462 * This function is responsible for updating both the client and the frame
1464 * According to the ICCCM a client message is not sent for a resize, only a
1467 void BlackboxWindow::configure(int dx
, int dy
,
1468 unsigned int dw
, unsigned int dh
) {
1469 bool send_event
= ((frame
.rect
.x() != dx
|| frame
.rect
.y() != dy
) &&
1472 if (dw
!= frame
.rect
.width() || dh
!= frame
.rect
.height()) {
1473 frame
.rect
.setRect(dx
, dy
, dw
, dh
);
1474 frame
.inside_w
= frame
.rect
.width() - (frame
.border_w
* 2);
1475 frame
.inside_h
= frame
.rect
.height() - (frame
.border_w
* 2);
1477 if (frame
.rect
.right() <= 0 || frame
.rect
.bottom() <= 0)
1478 frame
.rect
.setPos(0, 0);
1480 client
.rect
.setCoords(frame
.rect
.left() + frame
.margin
.left
,
1481 frame
.rect
.top() + frame
.margin
.top
,
1482 frame
.rect
.right() - frame
.margin
.right
,
1483 frame
.rect
.bottom() - frame
.margin
.bottom
);
1486 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
1493 redrawWindowFrame();
1495 frame
.rect
.setPos(dx
, dy
);
1497 XMoveWindow(blackbox
->getXDisplay(), frame
.window
,
1498 frame
.rect
.x(), frame
.rect
.y());
1500 we may have been called just after an opaque window move, so even though
1501 the old coords match the new ones no ConfigureNotify has been sent yet.
1502 There are likely other times when this will be relevant as well.
1504 if (! flags
.moving
) send_event
= True
;
1508 // if moving, the update and event will occur when the move finishes
1509 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1510 frame
.rect
.top() + frame
.margin
.top
);
1513 event
.type
= ConfigureNotify
;
1515 event
.xconfigure
.display
= blackbox
->getXDisplay();
1516 event
.xconfigure
.event
= client
.window
;
1517 event
.xconfigure
.window
= client
.window
;
1518 event
.xconfigure
.x
= client
.rect
.x();
1519 event
.xconfigure
.y
= client
.rect
.y();
1520 event
.xconfigure
.width
= client
.rect
.width();
1521 event
.xconfigure
.height
= client
.rect
.height();
1522 event
.xconfigure
.border_width
= client
.old_bw
;
1523 event
.xconfigure
.above
= frame
.window
;
1524 event
.xconfigure
.override_redirect
= False
;
1526 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1527 StructureNotifyMask
, &event
);
1528 screen
->updateNetizenConfigNotify(&event
);
1529 XFlush(blackbox
->getXDisplay());
1535 void BlackboxWindow::configureShape(void) {
1536 XShapeCombineShape(blackbox
->getXDisplay(), frame
.window
, ShapeBounding
,
1537 frame
.margin
.left
- frame
.border_w
,
1538 frame
.margin
.top
- frame
.border_w
,
1539 client
.window
, ShapeBounding
, ShapeSet
);
1542 XRectangle xrect
[2];
1544 if (decorations
& Decor_Titlebar
) {
1545 xrect
[0].x
= xrect
[0].y
= -frame
.border_w
;
1546 xrect
[0].width
= frame
.rect
.width();
1547 xrect
[0].height
= frame
.title_h
+ (frame
.border_w
* 2);
1551 if (decorations
& Decor_Handle
) {
1552 xrect
[1].x
= -frame
.border_w
;
1553 xrect
[1].y
= frame
.rect
.height() - frame
.margin
.bottom
+
1554 frame
.mwm_border_w
- frame
.border_w
;
1555 xrect
[1].width
= frame
.rect
.width();
1556 xrect
[1].height
= frame
.handle_h
+ (frame
.border_w
* 2);
1560 XShapeCombineRectangles(blackbox
->getXDisplay(), frame
.window
,
1561 ShapeBounding
, 0, 0, xrect
, num
,
1562 ShapeUnion
, Unsorted
);
1567 bool BlackboxWindow::setInputFocus(void) {
1568 if (flags
.focused
) return True
;
1570 assert(! flags
.iconic
&&
1571 (flags
.stuck
|| // window must be on the current workspace or sticky
1572 blackbox_attrib
.workspace
== screen
->getCurrentWorkspaceID()));
1575 We only do this check for normal windows and dialogs because other windows
1576 do this on purpose, such as kde's kicker, and we don't want to go moving
1579 if (window_type
== Type_Normal
|| window_type
== Type_Dialog
)
1580 if (! frame
.rect
.intersects(screen
->getRect())) {
1581 // client is outside the screen, move it to the center
1582 configure((screen
->getWidth() - frame
.rect
.width()) / 2,
1583 (screen
->getHeight() - frame
.rect
.height()) / 2,
1584 frame
.rect
.width(), frame
.rect
.height());
1587 if (client
.transientList
.size() > 0) {
1588 // transfer focus to any modal transients
1589 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1590 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1591 if ((*it
)->flags
.modal
) return (*it
)->setInputFocus();
1596 if (focus_mode
== F_LocallyActive
|| focus_mode
== F_Passive
) {
1597 XSetInputFocus(blackbox
->getXDisplay(), client
.window
,
1598 RevertToPointerRoot
, CurrentTime
);
1600 /* we could set the focus to none, since the window doesn't accept focus,
1601 * but we shouldn't set focus to nothing since this would surely make
1607 if (flags
.send_focus_message
) {
1609 ce
.xclient
.type
= ClientMessage
;
1610 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1611 ce
.xclient
.display
= blackbox
->getXDisplay();
1612 ce
.xclient
.window
= client
.window
;
1613 ce
.xclient
.format
= 32;
1614 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_take_focus
);
1615 ce
.xclient
.data
.l
[1] = blackbox
->getLastTime();
1616 ce
.xclient
.data
.l
[2] = 0l;
1617 ce
.xclient
.data
.l
[3] = 0l;
1618 ce
.xclient
.data
.l
[4] = 0l;
1619 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1621 XFlush(blackbox
->getXDisplay());
1628 void BlackboxWindow::iconify(void) {
1629 if (flags
.iconic
) return;
1631 // We don't need to worry about resizing because resizing always grabs the X
1632 // server. This should only ever happen if using opaque moving.
1636 if (windowmenu
) windowmenu
->hide();
1639 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1640 * we need to clear the event mask on client.window for a split second.
1641 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1642 * split second, leaving us with a ghost window... so, we need to do this
1643 * while the X server is grabbed
1645 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1646 StructureNotifyMask
;
1647 XGrabServer(blackbox
->getXDisplay());
1648 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1649 event_mask
& ~StructureNotifyMask
);
1650 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1651 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1652 XUngrabServer(blackbox
->getXDisplay());
1654 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1655 flags
.visible
= False
;
1656 flags
.iconic
= True
;
1658 setState(IconicState
);
1660 screen
->getWorkspace(blackbox_attrib
.workspace
)->removeWindow(this);
1662 if (isTransient()) {
1663 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1664 ! client
.transient_for
->flags
.iconic
) {
1665 // iconify our transient_for
1666 client
.transient_for
->iconify();
1670 screen
->addIcon(this);
1672 if (client
.transientList
.size() > 0) {
1673 // iconify all transients
1674 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1675 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1676 if (! (*it
)->flags
.iconic
) (*it
)->iconify();
1679 screen
->updateStackingList();
1683 void BlackboxWindow::show(void) {
1684 flags
.visible
= True
;
1685 flags
.iconic
= False
;
1687 current_state
= (flags
.shaded
) ? IconicState
: NormalState
;
1688 setState(current_state
);
1690 XMapWindow(blackbox
->getXDisplay(), client
.window
);
1691 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
1692 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
1697 XTranslateCoordinates(blackbox
->getXDisplay(), client
.window
,
1698 screen
->getRootWindow(),
1699 0, 0, &real_x
, &real_y
, &child
);
1700 fprintf(stderr
, "%s -- assumed: (%d, %d), real: (%d, %d)\n", getTitle(),
1701 client
.rect
.left(), client
.rect
.top(), real_x
, real_y
);
1702 assert(client
.rect
.left() == real_x
&& client
.rect
.top() == real_y
);
1707 void BlackboxWindow::deiconify(bool reassoc
, bool raise
) {
1708 if (flags
.iconic
|| reassoc
)
1709 screen
->reassociateWindow(this, BSENTINEL
, False
);
1710 else if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID())
1715 // reassociate and deiconify all transients
1716 if (reassoc
&& client
.transientList
.size() > 0) {
1717 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1718 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1719 (*it
)->deiconify(True
, False
);
1724 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1728 void BlackboxWindow::close(void) {
1730 ce
.xclient
.type
= ClientMessage
;
1731 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1732 ce
.xclient
.display
= blackbox
->getXDisplay();
1733 ce
.xclient
.window
= client
.window
;
1734 ce
.xclient
.format
= 32;
1735 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_delete_window
);
1736 ce
.xclient
.data
.l
[1] = CurrentTime
;
1737 ce
.xclient
.data
.l
[2] = 0l;
1738 ce
.xclient
.data
.l
[3] = 0l;
1739 ce
.xclient
.data
.l
[4] = 0l;
1740 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
, NoEventMask
, &ce
);
1741 XFlush(blackbox
->getXDisplay());
1745 void BlackboxWindow::withdraw(void) {
1746 // We don't need to worry about resizing because resizing always grabs the X
1747 // server. This should only ever happen if using opaque moving.
1751 flags
.visible
= False
;
1752 flags
.iconic
= False
;
1754 setState(current_state
);
1756 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1758 XGrabServer(blackbox
->getXDisplay());
1760 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1761 StructureNotifyMask
;
1762 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1763 event_mask
& ~StructureNotifyMask
);
1764 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1765 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1767 XUngrabServer(blackbox
->getXDisplay());
1769 if (windowmenu
) windowmenu
->hide();
1773 void BlackboxWindow::maximize(unsigned int button
) {
1774 // We don't need to worry about resizing because resizing always grabs the X
1775 // server. This should only ever happen if using opaque moving.
1779 // handle case where menu is open then the max button is used instead
1780 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
1782 if (flags
.maximized
) {
1783 flags
.maximized
= 0;
1785 blackbox_attrib
.flags
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1786 blackbox_attrib
.attrib
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1789 when a resize finishes, maximize(0) is called to clear any maximization
1790 flags currently set. Otherwise it still thinks it is maximized.
1791 so we do not need to call configure() because resizing will handle it
1793 if (! flags
.resizing
)
1794 configure(blackbox_attrib
.premax_x
, blackbox_attrib
.premax_y
,
1795 blackbox_attrib
.premax_w
, blackbox_attrib
.premax_h
);
1797 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
1798 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
1800 redrawAllButtons(); // in case it is not called in configure()
1801 setState(current_state
);
1805 blackbox_attrib
.premax_x
= frame
.rect
.x();
1806 blackbox_attrib
.premax_y
= frame
.rect
.y();
1807 blackbox_attrib
.premax_w
= frame
.rect
.width();
1808 // use client.rect so that clients can be restored even if shaded
1809 blackbox_attrib
.premax_h
=
1810 client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
;
1813 if (screen
->isXineramaActive() && blackbox
->doXineramaMaximizing()) {
1814 // find the area to use
1815 RectList availableAreas
= screen
->allAvailableAreas();
1816 RectList::iterator it
, end
= availableAreas
.end();
1818 for (it
= availableAreas
.begin(); it
!= end
; ++it
)
1819 if (it
->intersects(frame
.rect
)) break;
1820 if (it
== end
) // the window isn't inside an area
1821 it
= availableAreas
.begin(); // so just default to the first one
1823 frame
.changing
= *it
;
1826 frame
.changing
= screen
->availableArea();
1830 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1831 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1835 blackbox_attrib
.flags
|= AttribMaxVert
;
1836 blackbox_attrib
.attrib
|= AttribMaxVert
;
1838 frame
.changing
.setX(frame
.rect
.x());
1839 frame
.changing
.setWidth(frame
.rect
.width());
1843 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1844 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1846 frame
.changing
.setY(frame
.rect
.y());
1847 frame
.changing
.setHeight(frame
.rect
.height());
1854 blackbox_attrib
.flags
^= AttribShaded
;
1855 blackbox_attrib
.attrib
^= AttribShaded
;
1856 flags
.shaded
= False
;
1859 flags
.maximized
= button
;
1861 configure(frame
.changing
.x(), frame
.changing
.y(),
1862 frame
.changing
.width(), frame
.changing
.height());
1864 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1865 redrawAllButtons(); // in case it is not called in configure()
1866 setState(current_state
);
1870 // re-maximizes the window to take into account availableArea changes
1871 void BlackboxWindow::remaximize(void) {
1873 // we only update the window's attributes otherwise we lose the shade bit
1874 switch(flags
.maximized
) {
1876 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1877 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1881 blackbox_attrib
.flags
|= AttribMaxVert
;
1882 blackbox_attrib
.attrib
|= AttribMaxVert
;
1886 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1887 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1893 // save the original dimensions because maximize will wipe them out
1894 int premax_x
= blackbox_attrib
.premax_x
,
1895 premax_y
= blackbox_attrib
.premax_y
,
1896 premax_w
= blackbox_attrib
.premax_w
,
1897 premax_h
= blackbox_attrib
.premax_h
;
1899 unsigned int button
= flags
.maximized
;
1900 flags
.maximized
= 0; // trick maximize() into working
1903 // restore saved values
1904 blackbox_attrib
.premax_x
= premax_x
;
1905 blackbox_attrib
.premax_y
= premax_y
;
1906 blackbox_attrib
.premax_w
= premax_w
;
1907 blackbox_attrib
.premax_h
= premax_h
;
1911 void BlackboxWindow::setWorkspace(unsigned int n
) {
1912 blackbox_attrib
.flags
|= AttribWorkspace
;
1913 blackbox_attrib
.workspace
= n
;
1914 if (n
== BSENTINEL
) { // iconified window
1916 we set the workspace to 'all workspaces' so that taskbars will show the
1917 window. otherwise, it made uniconifying a window imposible without the
1918 blackbox workspace menu
1922 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
, n
);
1926 void BlackboxWindow::shade(void) {
1928 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1929 frame
.inside_w
, frame
.inside_h
);
1930 flags
.shaded
= False
;
1931 blackbox_attrib
.flags
^= AttribShaded
;
1932 blackbox_attrib
.attrib
^= AttribShaded
;
1934 setState(NormalState
);
1936 // set the frame rect to the normal size
1937 frame
.rect
.setHeight(client
.rect
.height() + frame
.margin
.top
+
1938 frame
.margin
.bottom
);
1940 if (! (decorations
& Decor_Titlebar
))
1941 return; // can't shade it without a titlebar!
1943 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1944 frame
.inside_w
, frame
.title_h
);
1945 flags
.shaded
= True
;
1946 blackbox_attrib
.flags
|= AttribShaded
;
1947 blackbox_attrib
.attrib
|= AttribShaded
;
1949 setState(IconicState
);
1951 // set the frame rect to the shaded size
1952 frame
.rect
.setHeight(frame
.title_h
+ (frame
.border_w
* 2));
1958 * (Un)Sticks a window and its relatives.
1960 void BlackboxWindow::stick(void) {
1962 blackbox_attrib
.flags
^= AttribOmnipresent
;
1963 blackbox_attrib
.attrib
^= AttribOmnipresent
;
1965 flags
.stuck
= False
;
1968 screen
->reassociateWindow(this, BSENTINEL
, True
);
1969 // temporary fix since sticky windows suck. set the hint to what we
1970 // actually hold in our data.
1971 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1972 blackbox_attrib
.workspace
);
1974 setState(current_state
);
1978 blackbox_attrib
.flags
|= AttribOmnipresent
;
1979 blackbox_attrib
.attrib
|= AttribOmnipresent
;
1981 // temporary fix since sticky windows suck. set the hint to a different
1982 // value than that contained in the class' data.
1983 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1986 setState(current_state
);
1989 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1990 client
.transient_for
->isStuck() != flags
.stuck
)
1991 client
.transient_for
->stick();
1992 // go down the chain
1993 BlackboxWindowList::iterator it
;
1994 const BlackboxWindowList::iterator end
= client
.transientList
.end();
1995 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1996 if ((*it
)->isStuck() != flags
.stuck
)
2001 void BlackboxWindow::redrawWindowFrame(void) const {
2002 if (decorations
& Decor_Titlebar
) {
2003 if (flags
.focused
) {
2005 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2006 frame
.title
, frame
.ftitle
);
2008 XSetWindowBackground(blackbox
->getXDisplay(),
2009 frame
.title
, frame
.ftitle_pixel
);
2012 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2013 frame
.title
, frame
.utitle
);
2015 XSetWindowBackground(blackbox
->getXDisplay(),
2016 frame
.title
, frame
.utitle_pixel
);
2018 XClearWindow(blackbox
->getXDisplay(), frame
.title
);
2024 if (decorations
& Decor_Handle
) {
2025 if (flags
.focused
) {
2027 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2028 frame
.handle
, frame
.fhandle
);
2030 XSetWindowBackground(blackbox
->getXDisplay(),
2031 frame
.handle
, frame
.fhandle_pixel
);
2034 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2035 frame
.left_grip
, frame
.fgrip
);
2036 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2037 frame
.right_grip
, frame
.fgrip
);
2039 XSetWindowBackground(blackbox
->getXDisplay(),
2040 frame
.left_grip
, frame
.fgrip_pixel
);
2041 XSetWindowBackground(blackbox
->getXDisplay(),
2042 frame
.right_grip
, frame
.fgrip_pixel
);
2046 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2047 frame
.handle
, frame
.uhandle
);
2049 XSetWindowBackground(blackbox
->getXDisplay(),
2050 frame
.handle
, frame
.uhandle_pixel
);
2053 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2054 frame
.left_grip
, frame
.ugrip
);
2055 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2056 frame
.right_grip
, frame
.ugrip
);
2058 XSetWindowBackground(blackbox
->getXDisplay(),
2059 frame
.left_grip
, frame
.ugrip_pixel
);
2060 XSetWindowBackground(blackbox
->getXDisplay(),
2061 frame
.right_grip
, frame
.ugrip_pixel
);
2064 XClearWindow(blackbox
->getXDisplay(), frame
.handle
);
2065 XClearWindow(blackbox
->getXDisplay(), frame
.left_grip
);
2066 XClearWindow(blackbox
->getXDisplay(), frame
.right_grip
);
2069 if (decorations
& Decor_Border
) {
2071 XSetWindowBorder(blackbox
->getXDisplay(),
2072 frame
.plate
, frame
.fborder_pixel
);
2074 XSetWindowBorder(blackbox
->getXDisplay(),
2075 frame
.plate
, frame
.uborder_pixel
);
2080 void BlackboxWindow::setFocusFlag(bool focus
) {
2081 // only focus a window if it is visible
2082 if (focus
&& !flags
.visible
)
2085 flags
.focused
= focus
;
2087 redrawWindowFrame();
2089 if (screen
->isSloppyFocus() && screen
->doAutoRaise()) {
2090 if (isFocused()) timer
->start();
2095 blackbox
->setFocusedWindow(this);
2097 if (! flags
.iconic
) {
2098 // iconic windows arent in a workspace menu!
2100 screen
->getWorkspace(blackbox_attrib
.workspace
)->getMenu();
2101 menu
->setItemSelected(window_number
, isFocused());
2106 void BlackboxWindow::installColormap(bool install
) {
2107 int i
= 0, ncmap
= 0;
2108 Colormap
*cmaps
= XListInstalledColormaps(blackbox
->getXDisplay(),
2109 client
.window
, &ncmap
);
2111 XWindowAttributes wattrib
;
2112 if (XGetWindowAttributes(blackbox
->getXDisplay(),
2113 client
.window
, &wattrib
)) {
2115 // install the window's colormap
2116 for (i
= 0; i
< ncmap
; i
++) {
2117 if (*(cmaps
+ i
) == wattrib
.colormap
)
2118 // this window is using an installed color map... do not install
2121 // otherwise, install the window's colormap
2123 XInstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2125 // uninstall the window's colormap
2126 for (i
= 0; i
< ncmap
; i
++) {
2127 if (*(cmaps
+ i
) == wattrib
.colormap
)
2128 // we found the colormap to uninstall
2129 XUninstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2139 void BlackboxWindow::setAllowedActions(void) {
2143 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_shade
);
2144 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_change_desktop
);
2145 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_close
);
2147 if (functions
& Func_Move
)
2148 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_move
);
2149 if (functions
& Func_Resize
)
2150 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_resize
);
2151 if (functions
& Func_Maximize
) {
2152 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_horz
);
2153 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_vert
);
2156 xatom
->setValue(client
.window
, XAtom::net_wm_allowed_actions
, XAtom::atom
,
2161 void BlackboxWindow::setState(unsigned long new_state
) {
2162 current_state
= new_state
;
2164 unsigned long state
[2];
2165 state
[0] = current_state
;
2167 xatom
->setValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
, state
, 2);
2169 xatom
->setValue(client
.window
, XAtom::blackbox_attributes
,
2170 XAtom::blackbox_attributes
, (unsigned long *)&blackbox_attrib
,
2171 PropBlackboxAttributesElements
);
2176 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_modal
);
2178 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_shaded
);
2180 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_hidden
);
2181 if (flags
.skip_taskbar
)
2182 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
);
2183 if (flags
.skip_pager
)
2184 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_pager
);
2185 if (flags
.fullscreen
)
2186 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_fullscreen
);
2187 if (flags
.maximized
== 1 || flags
.maximized
== 2)
2188 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_vert
);
2189 if (flags
.maximized
== 1 || flags
.maximized
== 3)
2190 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_horz
);
2191 xatom
->setValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
2196 bool BlackboxWindow::getState(void) {
2197 bool ret
= xatom
->getValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
,
2199 if (! ret
) current_state
= 0;
2204 void BlackboxWindow::restoreAttributes(void) {
2205 unsigned long num
= PropBlackboxAttributesElements
;
2206 BlackboxAttributes
*net
;
2207 if (! xatom
->getValue(client
.window
, XAtom::blackbox_attributes
,
2208 XAtom::blackbox_attributes
, num
,
2209 (unsigned long **)&net
))
2211 if (num
< PropBlackboxAttributesElements
) {
2216 if (net
->flags
& AttribShaded
&& net
->attrib
& AttribShaded
) {
2217 flags
.shaded
= False
;
2218 unsigned long orig_state
= current_state
;
2222 At this point in the life of a window, current_state should only be set
2223 to IconicState if the window was an *icon*, not if it was shaded.
2225 if (orig_state
!= IconicState
)
2226 current_state
= WithdrawnState
;
2229 if (net
->workspace
!= screen
->getCurrentWorkspaceID() &&
2230 net
->workspace
< screen
->getWorkspaceCount())
2231 screen
->reassociateWindow(this, net
->workspace
, True
);
2233 if ((blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID()) &&
2234 (blackbox_attrib
.workspace
< screen
->getWorkspaceCount())) {
2235 // set to WithdrawnState so it will be mapped on the new workspace
2236 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2237 } else if (current_state
== WithdrawnState
) {
2238 // the window is on this workspace and is Withdrawn, so it is waiting to
2240 current_state
= NormalState
;
2243 if (net
->flags
& AttribOmnipresent
&& net
->attrib
& AttribOmnipresent
) {
2244 flags
.stuck
= False
;
2247 // if the window was on another workspace, it was going to be hidden. this
2248 // specifies that the window should be mapped since it is sticky.
2249 if (current_state
== WithdrawnState
) current_state
= NormalState
;
2252 if (net
->flags
& AttribMaxHoriz
|| net
->flags
& AttribMaxVert
) {
2253 int x
= net
->premax_x
, y
= net
->premax_y
;
2254 unsigned int w
= net
->premax_w
, h
= net
->premax_h
;
2255 flags
.maximized
= 0;
2258 if ((net
->flags
& AttribMaxHoriz
) &&
2259 (net
->flags
& AttribMaxVert
))
2260 m
= (net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
2261 else if (net
->flags
& AttribMaxVert
)
2262 m
= (net
->attrib
& AttribMaxVert
) ? 2 : 0;
2263 else if (net
->flags
& AttribMaxHoriz
)
2264 m
= (net
->attrib
& AttribMaxHoriz
) ? 3 : 0;
2268 blackbox_attrib
.premax_x
= x
;
2269 blackbox_attrib
.premax_y
= y
;
2270 blackbox_attrib
.premax_w
= w
;
2271 blackbox_attrib
.premax_h
= h
;
2274 if (net
->flags
& AttribDecoration
) {
2275 switch (net
->decoration
) {
2283 decorations
|= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
2284 Decor_Iconify
| Decor_Maximize
;
2289 decorations
|= Decor_Titlebar
| Decor_Iconify
;
2290 decorations
&= ~(Decor_Border
| Decor_Handle
| Decor_Maximize
);
2295 decorations
|= Decor_Titlebar
;
2296 decorations
&= ~(Decor_Iconify
| Decor_Border
| Decor_Handle
);
2301 // sanity check the new decor
2302 if (! (functions
& Func_Resize
) || isTransient())
2303 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2304 if (! (functions
& Func_Maximize
))
2305 decorations
&= ~Decor_Maximize
;
2307 if (decorations
& Decor_Titlebar
) {
2308 if (functions
& Func_Close
) // close button is controlled by function
2309 decorations
|= Decor_Close
; // not decor type
2311 if (flags
.shaded
) // we can not be shaded if we lack a titlebar
2315 if (flags
.visible
&& frame
.window
) {
2316 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
2317 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
2321 setState(current_state
);
2324 // with the state set it will then be the map event's job to read the
2325 // window's state and behave accordingly
2332 * Positions the Rect r according the the client window position and
2335 void BlackboxWindow::applyGravity(Rect
&r
) {
2336 // apply horizontal window gravity
2337 switch (client
.win_gravity
) {
2339 case NorthWestGravity
:
2340 case SouthWestGravity
:
2342 r
.setX(client
.rect
.x());
2348 r
.setX(client
.rect
.x() - (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2351 case NorthEastGravity
:
2352 case SouthEastGravity
:
2354 r
.setX(client
.rect
.x() - frame
.margin
.left
- frame
.margin
.right
+ 2);
2359 r
.setX(client
.rect
.x() - frame
.margin
.left
);
2363 // apply vertical window gravity
2364 switch (client
.win_gravity
) {
2366 case NorthWestGravity
:
2367 case NorthEastGravity
:
2369 r
.setY(client
.rect
.y());
2375 r
.setY(client
.rect
.y() - (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2378 case SouthWestGravity
:
2379 case SouthEastGravity
:
2381 r
.setY(client
.rect
.y() - frame
.margin
.top
- frame
.margin
.bottom
+ 2);
2386 r
.setY(client
.rect
.y() - frame
.margin
.top
);
2393 * The reverse of the applyGravity function.
2395 * Positions the Rect r according to the frame window position and
2398 void BlackboxWindow::restoreGravity(Rect
&r
) {
2399 // restore horizontal window gravity
2400 switch (client
.win_gravity
) {
2402 case NorthWestGravity
:
2403 case SouthWestGravity
:
2405 r
.setX(frame
.rect
.x());
2411 r
.setX(frame
.rect
.x() + (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2414 case NorthEastGravity
:
2415 case SouthEastGravity
:
2417 r
.setX(frame
.rect
.x() + frame
.margin
.left
+ frame
.margin
.right
- 2);
2422 r
.setX(frame
.rect
.x() + frame
.margin
.left
);
2426 // restore vertical window gravity
2427 switch (client
.win_gravity
) {
2429 case NorthWestGravity
:
2430 case NorthEastGravity
:
2432 r
.setY(frame
.rect
.y());
2438 r
.setY(frame
.rect
.y() + (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2441 case SouthWestGravity
:
2442 case SouthEastGravity
:
2444 r
.setY(frame
.rect
.y() + frame
.margin
.top
+ frame
.margin
.bottom
- 2);
2449 r
.setY(frame
.rect
.y() + frame
.margin
.top
);
2455 void BlackboxWindow::redrawLabel(void) const {
2456 if (flags
.focused
) {
2458 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2459 frame
.label
, frame
.flabel
);
2461 XSetWindowBackground(blackbox
->getXDisplay(),
2462 frame
.label
, frame
.flabel_pixel
);
2465 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2466 frame
.label
, frame
.ulabel
);
2468 XSetWindowBackground(blackbox
->getXDisplay(),
2469 frame
.label
, frame
.ulabel_pixel
);
2471 XClearWindow(blackbox
->getXDisplay(), frame
.label
);
2473 WindowStyle
*style
= screen
->getWindowStyle();
2475 int pos
= frame
.bevel_w
* 2;
2476 style
->doJustify(client
.title
.c_str(), pos
, frame
.label_w
, frame
.bevel_w
* 4);
2477 style
->font
->drawString(frame
.label
, pos
, 1,
2478 (flags
.focused
? style
->l_text_focus
:
2479 style
->l_text_unfocus
),
2484 void BlackboxWindow::redrawAllButtons(void) const {
2485 if (frame
.iconify_button
) redrawIconifyButton(False
);
2486 if (frame
.maximize_button
) redrawMaximizeButton(flags
.maximized
);
2487 if (frame
.close_button
) redrawCloseButton(False
);
2491 void BlackboxWindow::redrawIconifyButton(bool pressed
) const {
2493 if (flags
.focused
) {
2495 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2496 frame
.iconify_button
, frame
.fbutton
);
2498 XSetWindowBackground(blackbox
->getXDisplay(),
2499 frame
.iconify_button
, frame
.fbutton_pixel
);
2502 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2503 frame
.iconify_button
, frame
.ubutton
);
2505 XSetWindowBackground(blackbox
->getXDisplay(), frame
.iconify_button
,
2506 frame
.ubutton_pixel
);
2510 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2511 frame
.iconify_button
, frame
.pbutton
);
2513 XSetWindowBackground(blackbox
->getXDisplay(),
2514 frame
.iconify_button
, frame
.pbutton_pixel
);
2516 XClearWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
2518 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2519 screen
->getWindowStyle()->b_pic_unfocus
);
2520 XDrawRectangle(blackbox
->getXDisplay(), frame
.iconify_button
, pen
.gc(),
2521 2, (frame
.button_w
- 5), (frame
.button_w
- 5), 2);
2525 void BlackboxWindow::redrawMaximizeButton(bool pressed
) const {
2527 if (flags
.focused
) {
2529 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2530 frame
.maximize_button
, frame
.fbutton
);
2532 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2533 frame
.fbutton_pixel
);
2536 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2537 frame
.maximize_button
, frame
.ubutton
);
2539 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2540 frame
.ubutton_pixel
);
2544 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2545 frame
.maximize_button
, frame
.pbutton
);
2547 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2548 frame
.pbutton_pixel
);
2550 XClearWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
2552 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2553 screen
->getWindowStyle()->b_pic_unfocus
);
2554 XDrawRectangle(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2555 2, 2, (frame
.button_w
- 5), (frame
.button_w
- 5));
2556 XDrawLine(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2557 2, 3, (frame
.button_w
- 3), 3);
2561 void BlackboxWindow::redrawCloseButton(bool pressed
) const {
2563 if (flags
.focused
) {
2565 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2568 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2569 frame
.fbutton_pixel
);
2572 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2575 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2576 frame
.ubutton_pixel
);
2580 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2581 frame
.close_button
, frame
.pbutton
);
2583 XSetWindowBackground(blackbox
->getXDisplay(),
2584 frame
.close_button
, frame
.pbutton_pixel
);
2586 XClearWindow(blackbox
->getXDisplay(), frame
.close_button
);
2588 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2589 screen
->getWindowStyle()->b_pic_unfocus
);
2590 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2591 2, 2, (frame
.button_w
- 3), (frame
.button_w
- 3));
2592 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2593 2, (frame
.button_w
- 3), (frame
.button_w
- 3), 2);
2597 void BlackboxWindow::mapRequestEvent(const XMapRequestEvent
*re
) {
2598 if (re
->window
!= client
.window
)
2602 fprintf(stderr
, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2606 switch (current_state
) {
2611 case WithdrawnState
:
2620 fprintf(stderr
, "0x%lx: just before show (%d, %d) w: %d, h: %d\n",
2622 frame
.rect
.x(), frame
.rect
.y(),
2623 frame
.rect
.width(), frame
.rect
.height());
2626 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2628 if (! blackbox
->isStartup()) {
2629 XSync(blackbox
->getXDisplay(), False
); // make sure the frame is mapped
2630 if (screen
->doFocusNew()|| (isTransient() && getTransientFor() &&
2631 getTransientFor()->isFocused())) {
2634 if (screen
->getPlacementPolicy() == BScreen::ClickMousePlacement
) {
2638 XQueryPointer(blackbox
->getXDisplay(), screen
->getRootWindow(),
2639 &r
, &c
, &rx
, &ry
, &x
, &y
, &m
);
2649 void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent
*ue
) {
2650 if (ue
->window
!= client
.window
)
2654 fprintf(stderr
, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2658 screen
->unmanageWindow(this, False
);
2662 void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent
*de
) {
2663 if (de
->window
!= client
.window
)
2667 fprintf(stderr
, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2671 screen
->unmanageWindow(this, False
);
2675 void BlackboxWindow::reparentNotifyEvent(const XReparentEvent
*re
) {
2676 if (re
->window
!= client
.window
|| re
->parent
== frame
.plate
)
2680 fprintf(stderr
, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2681 "0x%lx.\n", client
.window
, re
->parent
);
2686 XPutBackEvent(blackbox
->getXDisplay(), &ev
);
2687 screen
->unmanageWindow(this, True
);
2691 void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent
*pe
) {
2692 if (pe
->state
== PropertyDelete
)
2696 fprintf(stderr
, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n",
2702 case XA_WM_CLIENT_MACHINE
:
2706 case XA_WM_TRANSIENT_FOR
: {
2707 // determine if this is a transient window
2710 // adjust the window decorations based on transience
2711 if (isTransient()) {
2712 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2713 functions
&= ~Func_Maximize
;
2714 setAllowedActions();
2719 fprintf(stderr
, "0x%lx: transient hint (%d, %d) w: %d, h: %d\n",
2721 frame
.rect
.x(), frame
.rect
.y(),
2722 frame
.rect
.width(), frame
.rect
.height());
2731 case XA_WM_ICON_NAME
:
2733 if (flags
.iconic
) screen
->propagateWindowName(this);
2736 case XAtom::net_wm_name
:
2740 if (decorations
& Decor_Titlebar
)
2743 screen
->propagateWindowName(this);
2746 case XA_WM_NORMAL_HINTS
: {
2749 if ((client
.normal_hint_flags
& PMinSize
) &&
2750 (client
.normal_hint_flags
& PMaxSize
)) {
2751 // the window now can/can't resize itself, so the buttons need to be
2754 if (client
.max_width
<= client
.min_width
&&
2755 client
.max_height
<= client
.min_height
) {
2756 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2757 functions
&= ~(Func_Resize
| Func_Maximize
);
2759 if (! isTransient()) {
2760 decorations
|= Decor_Maximize
| Decor_Handle
;
2761 functions
|= Func_Maximize
;
2763 functions
|= Func_Resize
;
2766 setAllowedActions();
2769 Rect old_rect
= frame
.rect
;
2773 if (old_rect
!= frame
.rect
)
2777 fprintf(stderr
, "0x%lx: normal hint (%d, %d) w: %d, h: %d\n",
2779 frame
.rect
.x(), frame
.rect
.y(),
2780 frame
.rect
.width(), frame
.rect
.height());
2786 if (pe
->atom
== xatom
->getAtom(XAtom::wm_protocols
)) {
2789 if ((decorations
& Decor_Close
) && (! frame
.close_button
)) {
2790 createCloseButton();
2791 if (decorations
& Decor_Titlebar
) {
2792 positionButtons(True
);
2793 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
2795 if (windowmenu
) windowmenu
->reconfigure();
2797 } else if (pe
->atom
== xatom
->getAtom(XAtom::net_wm_strut
)) {
2806 void BlackboxWindow::exposeEvent(const XExposeEvent
*ee
) {
2808 fprintf(stderr
, "BlackboxWindow::exposeEvent() for 0x%lx\n", client
.window
);
2811 if (frame
.label
== ee
->window
&& (decorations
& Decor_Titlebar
))
2813 else if (frame
.close_button
== ee
->window
)
2814 redrawCloseButton(False
);
2815 else if (frame
.maximize_button
== ee
->window
)
2816 redrawMaximizeButton(flags
.maximized
);
2817 else if (frame
.iconify_button
== ee
->window
)
2818 redrawIconifyButton(False
);
2822 void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent
*cr
) {
2823 if (cr
->window
!= client
.window
|| flags
.iconic
)
2826 if (cr
->value_mask
& CWBorderWidth
)
2827 client
.old_bw
= cr
->border_width
;
2829 if (cr
->value_mask
& (CWX
| CWY
| CWWidth
| CWHeight
)) {
2830 Rect req
= frame
.rect
;
2832 if (cr
->value_mask
& (CWX
| CWY
)) {
2833 if (cr
->value_mask
& CWX
)
2834 client
.rect
.setX(cr
->x
);
2835 if (cr
->value_mask
& CWY
)
2836 client
.rect
.setY(cr
->y
);
2841 if (cr
->value_mask
& CWWidth
) {
2842 req
.setWidth(cr
->width
+ frame
.margin
.left
+ frame
.margin
.right
);
2844 fprintf(stderr
, "0x%lx: new width - %d\n", client
.window
, cr
->width
);
2848 if (cr
->value_mask
& CWHeight
) {
2849 req
.setHeight(cr
->height
+ frame
.margin
.top
+ frame
.margin
.bottom
);
2851 fprintf(stderr
, "0x%lx: new height - %d\n", client
.window
, cr
->height
);
2855 configure(req
.x(), req
.y(), req
.width(), req
.height());
2858 if (cr
->value_mask
& CWStackMode
&& !isDesktop()) {
2859 switch (cr
->detail
) {
2862 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2868 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2874 fprintf(stderr
, "0x%lx: change request (%d, %d) w: %d, h: %d\n",
2876 frame
.rect
.x(), frame
.rect
.y(),
2877 frame
.rect
.width(), frame
.rect
.height());
2882 void BlackboxWindow::buttonPressEvent(const XButtonEvent
*be
) {
2884 fprintf(stderr
, "BlackboxWindow::buttonPressEvent() for 0x%lx\n",
2888 if (frame
.maximize_button
== be
->window
&& be
->button
<= 3) {
2889 redrawMaximizeButton(True
);
2890 } else if (be
->button
== 1 || (be
->button
== 3 && be
->state
== ModMask
)) {
2891 if (! flags
.focused
)
2894 if (frame
.iconify_button
== be
->window
) {
2895 redrawIconifyButton(True
);
2896 } else if (frame
.close_button
== be
->window
) {
2897 redrawCloseButton(True
);
2898 } else if (frame
.plate
== be
->window
) {
2899 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2901 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2903 XAllowEvents(blackbox
->getXDisplay(), ReplayPointer
, be
->time
);
2905 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
2906 if (((be
->time
- lastButtonPressTime
) <=
2907 blackbox
->getDoubleClickInterval()) ||
2908 (be
->state
== ControlMask
)) {
2909 lastButtonPressTime
= 0;
2912 lastButtonPressTime
= be
->time
;
2916 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2918 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2920 } else if (be
->button
== 2 && (be
->window
!= frame
.iconify_button
) &&
2921 (be
->window
!= frame
.close_button
)) {
2922 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2923 } else if (windowmenu
&& be
->button
== 3 &&
2924 (frame
.title
== be
->window
|| frame
.label
== be
->window
||
2925 frame
.handle
== be
->window
|| frame
.window
== be
->window
)) {
2926 if (windowmenu
->isVisible()) {
2929 int mx
= be
->x_root
- windowmenu
->getWidth() / 2,
2930 my
= be
->y_root
- windowmenu
->getHeight() / 2;
2932 // snap the window menu into a corner/side if necessary
2933 int left_edge
, right_edge
, top_edge
, bottom_edge
;
2936 the " + (frame.border_w * 2) - 1" bits are to get the proper width
2937 and height of the menu, as the sizes returned by it do not include
2940 left_edge
= frame
.rect
.x();
2941 right_edge
= frame
.rect
.right() -
2942 (windowmenu
->getWidth() + (frame
.border_w
* 2) - 1);
2943 top_edge
= client
.rect
.top() - (frame
.border_w
+ frame
.mwm_border_w
);
2944 bottom_edge
= client
.rect
.bottom() -
2945 (windowmenu
->getHeight() + (frame
.border_w
* 2) - 1) +
2946 (frame
.border_w
+ frame
.mwm_border_w
);
2950 if (mx
> right_edge
)
2954 if (my
> bottom_edge
)
2957 windowmenu
->move(mx
, my
);
2959 XRaiseWindow(blackbox
->getXDisplay(), windowmenu
->getWindowID());
2960 XRaiseWindow(blackbox
->getXDisplay(),
2961 windowmenu
->getSendToMenu()->getWindowID());
2964 } else if (be
->button
== 4) {
2965 if ((be
->window
== frame
.label
||
2966 be
->window
== frame
.title
||
2967 be
->window
== frame
.maximize_button
||
2968 be
->window
== frame
.iconify_button
||
2969 be
->window
== frame
.close_button
) &&
2973 } else if (be
->button
== 5) {
2974 if ((be
->window
== frame
.label
||
2975 be
->window
== frame
.title
||
2976 be
->window
== frame
.maximize_button
||
2977 be
->window
== frame
.iconify_button
||
2978 be
->window
== frame
.close_button
) &&
2985 void BlackboxWindow::buttonReleaseEvent(const XButtonEvent
*re
) {
2987 fprintf(stderr
, "BlackboxWindow::buttonReleaseEvent() for 0x%lx\n",
2991 if (re
->window
== frame
.maximize_button
&&
2992 re
->button
>= 1 && re
->button
<= 3) {
2993 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2994 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2995 maximize(re
->button
);
2997 redrawMaximizeButton(flags
.maximized
);
2999 } else if (re
->window
== frame
.iconify_button
&& re
->button
== 1) {
3000 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3001 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
3004 redrawIconifyButton(False
);
3006 } else if (re
->window
== frame
.close_button
& re
->button
== 1) {
3007 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3008 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
)))
3010 redrawCloseButton(False
);
3011 } else if (flags
.moving
) {
3013 } else if (flags
.resizing
) {
3015 } else if (re
->window
== frame
.window
) {
3016 if (re
->button
== 2 && re
->state
== ModMask
)
3017 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3023 void BlackboxWindow::beginMove(int x_root
, int y_root
) {
3024 assert(! (flags
.resizing
|| flags
.moving
));
3027 Only one window can be moved/resized at a time. If another window is already
3028 being moved or resized, then stop it before whating to work with this one.
3030 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3031 if (changing
&& changing
!= this) {
3032 if (changing
->flags
.moving
)
3033 changing
->endMove();
3034 else // if (changing->flags.resizing)
3035 changing
->endResize();
3038 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3039 PointerMotionMask
| ButtonReleaseMask
,
3040 GrabModeAsync
, GrabModeAsync
,
3041 None
, blackbox
->getMoveCursor(), CurrentTime
);
3043 if (windowmenu
&& windowmenu
->isVisible())
3046 flags
.moving
= True
;
3047 blackbox
->setChangingWindow(this);
3049 if (! screen
->doOpaqueMove()) {
3050 XGrabServer(blackbox
->getXDisplay());
3052 frame
.changing
= frame
.rect
;
3053 screen
->showPosition(frame
.changing
.x(), frame
.changing
.y());
3055 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3059 frame
.changing
.width() - 1,
3060 frame
.changing
.height() - 1);
3063 frame
.grab_x
= x_root
- frame
.rect
.x() - frame
.border_w
;
3064 frame
.grab_y
= y_root
- frame
.rect
.y() - frame
.border_w
;
3068 void BlackboxWindow::doMove(int x_root
, int y_root
) {
3069 assert(flags
.moving
);
3070 assert(blackbox
->getChangingWindow() == this);
3072 int dx
= x_root
- frame
.grab_x
, dy
= y_root
- frame
.grab_y
;
3073 dx
-= frame
.border_w
;
3074 dy
-= frame
.border_w
;
3076 if (screen
->doWorkspaceWarping()) {
3077 // workspace warping
3079 unsigned int dest
= screen
->getCurrentWorkspaceID();
3083 if (dest
> 0) dest
--;
3084 else dest
= screen
->getNumberOfWorkspaces() - 1;
3086 } else if (x_root
>= screen
->getRect().right()) {
3089 if (dest
< screen
->getNumberOfWorkspaces() - 1) dest
++;
3094 bool focus
= flags
.focused
; // had focus while moving?
3096 screen
->reassociateWindow(this, dest
, False
);
3097 screen
->changeWorkspaceID(dest
);
3102 If the XWarpPointer is done after the configure, we can end up
3103 grabbing another window, so made sure you do it first.
3107 dest_x
= screen
->getRect().right() - 1;
3108 XWarpPointer(blackbox
->getXDisplay(), None
,
3109 screen
->getRootWindow(), 0, 0, 0, 0,
3112 configure(dx
+ (screen
->getRect().width() - 1), dy
,
3113 frame
.rect
.width(), frame
.rect
.height());
3116 XWarpPointer(blackbox
->getXDisplay(), None
,
3117 screen
->getRootWindow(), 0, 0, 0, 0,
3120 configure(dx
- (screen
->getRect().width() - 1), dy
,
3121 frame
.rect
.width(), frame
.rect
.height());
3124 beginMove(dest_x
, y_root
);
3129 const int snap_distance
= screen
->getEdgeSnapThreshold();
3131 if (snap_distance
) {
3133 const int wleft
= dx
,
3134 wright
= dx
+ frame
.rect
.width() - 1,
3136 wbottom
= dy
+ frame
.rect
.height() - 1;
3138 if (screen
->getWindowToWindowSnap()) {
3139 Workspace
*w
= screen
->getWorkspace(getWorkspaceNumber());
3142 // try snap to another window
3143 for (unsigned int i
= 0, c
= w
->getCount(); i
< c
; ++i
) {
3144 BlackboxWindow
*snapwin
= w
->getWindow(i
);
3145 if (snapwin
== this)
3146 continue; // don't snap to self
3148 bool snapped
= False
;
3150 const Rect
&winrect
= snapwin
->frameRect();
3151 int dleft
= abs(wright
- winrect
.left()),
3152 dright
= abs(wleft
- winrect
.right()),
3153 dtop
= abs(wbottom
- winrect
.top()),
3154 dbottom
= abs(wtop
- winrect
.bottom());
3156 if (wtop
>= (signed)(winrect
.y() - frame
.rect
.height() + 1) &&
3157 wtop
< (signed)(winrect
.y() + winrect
.height() - 1)) {
3159 // snap left of other window?
3160 if (dleft
< snap_distance
&& dleft
<= dright
) {
3161 dx
= winrect
.left() - frame
.rect
.width();
3164 // snap right of other window?
3165 else if (dright
< snap_distance
) {
3166 dx
= winrect
.right() + 1;
3171 if (screen
->getWindowCornerSnap()) {
3172 // try corner-snap to its other sides
3173 dtop
= abs(wtop
- winrect
.top());
3174 dbottom
= abs(wbottom
- winrect
.bottom());
3175 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3177 else if (dbottom
< snap_distance
)
3178 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
3185 if (wleft
>= (signed)(winrect
.x() - frame
.rect
.width() + 1) &&
3186 wleft
< (signed)(winrect
.x() + winrect
.width() - 1)) {
3188 // snap top of other window?
3189 if (dtop
< snap_distance
&& dtop
<= dbottom
) {
3190 dy
= winrect
.top() - frame
.rect
.height();
3193 // snap bottom of other window?
3194 else if (dbottom
< snap_distance
) {
3195 dy
= winrect
.bottom() + 1;
3200 if (screen
->getWindowCornerSnap()) {
3201 // try corner-snap to its other sides
3202 dleft
= abs(wleft
- winrect
.left());
3203 dright
= abs(wright
- winrect
.right());
3204 if (dleft
< snap_distance
&& dleft
<= dright
)
3205 dx
= winrect
.left();
3206 else if (dright
< snap_distance
)
3207 dx
= winrect
.right() - frame
.rect
.width() + 1;
3216 RectList snaplist
; // the list of rects we will try to snap to
3218 // snap to the strut (and screen boundaries for xinerama)
3220 if (screen
->isXineramaActive() && blackbox
->doXineramaSnapping()) {
3221 if (! screen
->doFullMax())
3222 snaplist
.insert(snaplist
.begin(),
3223 screen
->allAvailableAreas().begin(),
3224 screen
->allAvailableAreas().end());
3226 // always snap to the screen edges
3227 snaplist
.insert(snaplist
.begin(),
3228 screen
->getXineramaAreas().begin(),
3229 screen
->getXineramaAreas().end());
3233 if (! screen
->doFullMax())
3234 snaplist
.push_back(screen
->availableArea());
3236 // always snap to the screen edges
3237 snaplist
.push_back(screen
->getRect());
3240 RectList::const_iterator it
, end
= snaplist
.end();
3241 for (it
= snaplist
.begin(); it
!= end
; ++it
) {
3242 const Rect
&srect
= *it
;
3244 // if we're not in the rectangle then don't snap to it.
3245 if (! srect
.intersects(Rect(wleft
, wtop
, frame
.rect
.width(),
3246 frame
.rect
.height())))
3249 int dleft
= abs(wleft
- srect
.left()),
3250 dright
= abs(wright
- srect
.right()),
3251 dtop
= abs(wtop
- srect
.top()),
3252 dbottom
= abs(wbottom
- srect
.bottom());
3255 if (dleft
< snap_distance
&& dleft
<= dright
)
3258 else if (dright
< snap_distance
)
3259 dx
= srect
.right() - frame
.rect
.width() + 1;
3262 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3265 else if (dbottom
< snap_distance
)
3266 dy
= srect
.bottom() - frame
.rect
.height() + 1;
3270 if (screen
->doOpaqueMove()) {
3271 configure(dx
, dy
, frame
.rect
.width(), frame
.rect
.height());
3273 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3277 frame
.changing
.width() - 1,
3278 frame
.changing
.height() - 1);
3280 frame
.changing
.setPos(dx
, dy
);
3282 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3286 frame
.changing
.width() - 1,
3287 frame
.changing
.height() - 1);
3290 screen
->showPosition(dx
, dy
);
3294 void BlackboxWindow::endMove(void) {
3295 assert(flags
.moving
);
3296 assert(blackbox
->getChangingWindow() == this);
3298 flags
.moving
= False
;
3299 blackbox
->setChangingWindow(0);
3301 if (! screen
->doOpaqueMove()) {
3302 /* when drawing the rubber band, we need to make sure we only draw inside
3303 * the frame... frame.changing_* contain the new coords for the window,
3304 * so we need to subtract 1 from changing_w/changing_h every where we
3305 * draw the rubber band (for both moving and resizing)
3307 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3308 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3309 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3310 XUngrabServer(blackbox
->getXDisplay());
3312 configure(frame
.changing
.x(), frame
.changing
.y(),
3313 frame
.changing
.width(), frame
.changing
.height());
3315 configure(frame
.rect
.x(), frame
.rect
.y(),
3316 frame
.rect
.width(), frame
.rect
.height());
3318 screen
->hideGeometry();
3320 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3322 // if there are any left over motions from the move, drop them now
3323 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3325 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3330 void BlackboxWindow::beginResize(int x_root
, int y_root
, Corner dir
) {
3331 assert(! (flags
.resizing
|| flags
.moving
));
3334 Only one window can be moved/resized at a time. If another window is already
3335 being moved or resized, then stop it before whating to work with this one.
3337 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3338 if (changing
&& changing
!= this) {
3339 if (changing
->flags
.moving
)
3340 changing
->endMove();
3341 else // if (changing->flags.resizing)
3342 changing
->endResize();
3350 switch (resize_dir
) {
3353 cursor
= blackbox
->getLowerLeftAngleCursor();
3358 cursor
= blackbox
->getLowerRightAngleCursor();
3362 anchor
= BottomRight
;
3363 cursor
= blackbox
->getUpperLeftAngleCursor();
3367 anchor
= BottomLeft
;
3368 cursor
= blackbox
->getUpperRightAngleCursor();
3372 assert(false); // unhandled Corner
3373 return; // unreachable, for the compiler
3376 XGrabServer(blackbox
->getXDisplay());
3377 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3378 PointerMotionMask
| ButtonReleaseMask
,
3379 GrabModeAsync
, GrabModeAsync
, None
, cursor
, CurrentTime
);
3381 flags
.resizing
= True
;
3382 blackbox
->setChangingWindow(this);
3385 frame
.changing
= frame
.rect
;
3387 constrain(anchor
, &gw
, &gh
);
3389 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3390 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3391 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3393 screen
->showGeometry(gw
, gh
);
3395 frame
.grab_x
= x_root
;
3396 frame
.grab_y
= y_root
;
3400 void BlackboxWindow::doResize(int x_root
, int y_root
) {
3401 assert(flags
.resizing
);
3402 assert(blackbox
->getChangingWindow() == this);
3404 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3405 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3406 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3411 switch (resize_dir
) {
3414 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3415 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3419 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3420 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3423 anchor
= BottomRight
;
3424 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3425 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3428 anchor
= BottomLeft
;
3429 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3430 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3434 assert(false); // unhandled Corner
3435 return; // unreachable, for the compiler
3438 constrain(anchor
, &gw
, &gh
);
3440 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3441 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3442 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3444 screen
->showGeometry(gw
, gh
);
3448 void BlackboxWindow::endResize(void) {
3449 assert(flags
.resizing
);
3450 assert(blackbox
->getChangingWindow() == this);
3452 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3453 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3454 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3455 XUngrabServer(blackbox
->getXDisplay());
3457 // unset maximized state after resized when fully maximized
3458 if (flags
.maximized
== 1)
3461 flags
.resizing
= False
;
3462 blackbox
->setChangingWindow(0);
3464 configure(frame
.changing
.x(), frame
.changing
.y(),
3465 frame
.changing
.width(), frame
.changing
.height());
3466 screen
->hideGeometry();
3468 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3470 // if there are any left over motions from the resize, drop them now
3471 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3473 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3478 void BlackboxWindow::motionNotifyEvent(const XMotionEvent
*me
) {
3480 fprintf(stderr
, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n",
3485 doMove(me
->x_root
, me
->y_root
);
3486 } else if (flags
.resizing
) {
3487 doResize(me
->x_root
, me
->y_root
);
3489 if (!flags
.resizing
&& me
->state
& Button1Mask
&& (functions
& Func_Move
) &&
3490 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3491 frame
.handle
== me
->window
|| frame
.window
== me
->window
)) {
3492 beginMove(me
->x_root
, me
->y_root
);
3493 } else if ((functions
& Func_Resize
) &&
3494 (me
->state
& Button1Mask
&& (me
->window
== frame
.right_grip
||
3495 me
->window
== frame
.left_grip
)) ||
3496 (me
->state
& Button3Mask
&& me
->state
& ModMask
&&
3497 me
->window
== frame
.window
)) {
3498 unsigned int zones
= screen
->getResizeZones();
3501 if (me
->window
== frame
.left_grip
) {
3502 corner
= BottomLeft
;
3503 } else if (me
->window
== frame
.right_grip
|| zones
== 1) {
3504 corner
= BottomRight
;
3507 bool left
= (me
->x_root
- frame
.rect
.x() <=
3508 static_cast<signed>(frame
.rect
.width() / 2));
3511 else // (zones == 4)
3512 top
= (me
->y_root
- frame
.rect
.y() <=
3513 static_cast<signed>(frame
.rect
.height() / 2));
3514 corner
= (top
? (left
? TopLeft
: TopRight
) :
3515 (left
? BottomLeft
: BottomRight
));
3518 beginResize(me
->x_root
, me
->y_root
, corner
);
3525 void BlackboxWindow::shapeEvent(XShapeEvent
*) {
3526 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
3533 bool BlackboxWindow::validateClient(void) const {
3534 XSync(blackbox
->getXDisplay(), False
);
3537 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3538 DestroyNotify
, &e
) ||
3539 XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3541 XPutBackEvent(blackbox
->getXDisplay(), &e
);
3550 void BlackboxWindow::restore(bool remap
) {
3551 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeDelete
);
3552 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
3553 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, NoEventMask
);
3555 // do not leave a shaded window as an icon unless it was an icon
3556 if (flags
.shaded
&& ! flags
.iconic
) setState(NormalState
);
3558 restoreGravity(client
.rect
);
3560 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
3561 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
3563 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, client
.old_bw
);
3566 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3567 ReparentNotify
, &ev
)) {
3570 // according to the ICCCM - if the client doesn't reparent to
3571 // root, then we have to do it for them
3572 XReparentWindow(blackbox
->getXDisplay(), client
.window
,
3573 screen
->getRootWindow(),
3574 client
.rect
.x(), client
.rect
.y());
3577 if (remap
) XMapWindow(blackbox
->getXDisplay(), client
.window
);
3581 // timer for autoraise
3582 void BlackboxWindow::timeout(void) {
3583 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3587 void BlackboxWindow::changeBlackboxHints(const BlackboxHints
*net
) {
3588 if ((net
->flags
& AttribShaded
) &&
3589 ((blackbox_attrib
.attrib
& AttribShaded
) !=
3590 (net
->attrib
& AttribShaded
)))
3593 if (flags
.visible
&& // watch out for requests when we can not be seen
3594 (net
->flags
& (AttribMaxVert
| AttribMaxHoriz
)) &&
3595 ((blackbox_attrib
.attrib
& (AttribMaxVert
| AttribMaxHoriz
)) !=
3596 (net
->attrib
& (AttribMaxVert
| AttribMaxHoriz
)))) {
3597 if (flags
.maximized
) {
3602 if ((net
->flags
& AttribMaxHoriz
) && (net
->flags
& AttribMaxVert
))
3603 button
= ((net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0);
3604 else if (net
->flags
& AttribMaxVert
)
3605 button
= ((net
->attrib
& AttribMaxVert
) ? 2 : 0);
3606 else if (net
->flags
& AttribMaxHoriz
)
3607 button
= ((net
->attrib
& AttribMaxHoriz
) ? 3 : 0);
3613 if ((net
->flags
& AttribOmnipresent
) &&
3614 ((blackbox_attrib
.attrib
& AttribOmnipresent
) !=
3615 (net
->attrib
& AttribOmnipresent
)))
3618 if ((net
->flags
& AttribWorkspace
) &&
3619 (blackbox_attrib
.workspace
!= net
->workspace
)) {
3620 screen
->reassociateWindow(this, net
->workspace
, True
);
3622 if (screen
->getCurrentWorkspaceID() != net
->workspace
) {
3626 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3630 if (net
->flags
& AttribDecoration
) {
3631 switch (net
->decoration
) {
3639 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Iconify
;
3641 decorations
= ((functions
& Func_Resize
) && !isTransient() ?
3642 decorations
| Decor_Handle
:
3643 decorations
&= ~Decor_Handle
);
3644 decorations
= (functions
& Func_Maximize
?
3645 decorations
| Decor_Maximize
:
3646 decorations
&= ~Decor_Maximize
);
3651 decorations
|= Decor_Titlebar
| Decor_Iconify
;
3652 decorations
&= ~(Decor_Border
| Decor_Handle
);
3654 decorations
= (functions
& Func_Maximize
?
3655 decorations
| Decor_Maximize
:
3656 decorations
&= ~Decor_Maximize
);
3661 decorations
|= Decor_Titlebar
;
3662 decorations
&= ~(Decor_Iconify
| Decor_Border
);
3664 decorations
= ((functions
& Func_Resize
) && !isTransient() ?
3665 decorations
| Decor_Handle
:
3666 decorations
&= ~Decor_Handle
);
3667 decorations
= (functions
& Func_Maximize
?
3668 decorations
| Decor_Maximize
:
3669 decorations
&= ~Decor_Maximize
);
3674 // we can not be shaded if we lack a titlebar
3675 if (flags
.shaded
&& ! (decorations
& Decor_Titlebar
))
3678 if (flags
.visible
&& frame
.window
) {
3679 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
3680 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
3684 setState(current_state
);
3690 * Set the sizes of all components of the window frame
3691 * (the window decorations).
3692 * These values are based upon the current style settings and the client
3693 * window's dimensions.
3695 void BlackboxWindow::upsize(void) {
3696 frame
.bevel_w
= screen
->getBevelWidth();
3698 if (decorations
& Decor_Border
) {
3699 frame
.border_w
= screen
->getBorderWidth();
3700 if (! isTransient())
3701 frame
.mwm_border_w
= screen
->getFrameWidth();
3703 frame
.mwm_border_w
= 0;
3705 frame
.mwm_border_w
= frame
.border_w
= 0;
3708 if (decorations
& Decor_Titlebar
) {
3709 // the height of the titlebar is based upon the height of the font being
3710 // used to display the window's title
3711 WindowStyle
*style
= screen
->getWindowStyle();
3712 frame
.title_h
= style
->font
->height() + (frame
.bevel_w
* 2) + 2;
3714 frame
.label_h
= frame
.title_h
- (frame
.bevel_w
* 2);
3715 frame
.button_w
= (frame
.label_h
- 2);
3717 // set the top frame margin
3718 frame
.margin
.top
= frame
.border_w
+ frame
.title_h
+
3719 frame
.border_w
+ frame
.mwm_border_w
;
3725 // set the top frame margin
3726 frame
.margin
.top
= frame
.border_w
+ frame
.mwm_border_w
;
3729 // set the left/right frame margin
3730 frame
.margin
.left
= frame
.margin
.right
= frame
.border_w
+ frame
.mwm_border_w
;
3732 if (decorations
& Decor_Handle
) {
3733 frame
.grip_w
= frame
.button_w
* 2;
3734 frame
.handle_h
= screen
->getHandleWidth();
3736 // set the bottom frame margin
3737 frame
.margin
.bottom
= frame
.border_w
+ frame
.handle_h
+
3738 frame
.border_w
+ frame
.mwm_border_w
;
3743 // set the bottom frame margin
3744 frame
.margin
.bottom
= frame
.border_w
+ frame
.mwm_border_w
;
3748 We first get the normal dimensions and use this to define the inside_w/h
3749 then we modify the height if shading is in effect.
3750 If the shade state is not considered then frame.rect gets reset to the
3751 normal window size on a reconfigure() call resulting in improper
3752 dimensions appearing in move/resize and other events.
3755 height
= client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
,
3756 width
= client
.rect
.width() + frame
.margin
.left
+ frame
.margin
.right
;
3758 frame
.inside_w
= width
- (frame
.border_w
* 2);
3759 frame
.inside_h
= height
- (frame
.border_w
* 2);
3762 height
= frame
.title_h
+ (frame
.border_w
* 2);
3763 frame
.rect
.setSize(width
, height
);
3768 * Calculate the size of the client window and constrain it to the
3769 * size specified by the size hints of the client window.
3771 * The logical width and height are placed into pw and ph, if they
3772 * are non-zero. Logical size refers to the users perception of
3773 * the window size (for example an xterm resizes in cells, not in pixels).
3775 * The physical geometry is placed into frame.changing_{x,y,width,height}.
3776 * Physical geometry refers to the geometry of the window in pixels.
3778 void BlackboxWindow::constrain(Corner anchor
, int *pw
, int *ph
) {
3779 // frame.changing represents the requested frame size, we need to
3780 // strip the frame margin off and constrain the client size
3781 frame
.changing
.setCoords(frame
.changing
.left() + frame
.margin
.left
,
3782 frame
.changing
.top() + frame
.margin
.top
,
3783 frame
.changing
.right() - frame
.margin
.right
,
3784 frame
.changing
.bottom() - frame
.margin
.bottom
);
3786 int dw
= frame
.changing
.width(), dh
= frame
.changing
.height(),
3787 base_width
= (client
.base_width
) ? client
.base_width
: client
.min_width
,
3788 base_height
= (client
.base_height
) ? client
.base_height
:
3792 if (dw
< static_cast<signed>(client
.min_width
)) dw
= client
.min_width
;
3793 if (dh
< static_cast<signed>(client
.min_height
)) dh
= client
.min_height
;
3794 if (dw
> static_cast<signed>(client
.max_width
)) dw
= client
.max_width
;
3795 if (dh
> static_cast<signed>(client
.max_height
)) dh
= client
.max_height
;
3798 dw
/= client
.width_inc
;
3800 dh
/= client
.height_inc
;
3803 if (client
.width_inc
== 1)
3804 *pw
= dw
+ base_width
;
3809 if (client
.height_inc
== 1)
3810 *ph
= dh
+ base_height
;
3815 dw
*= client
.width_inc
;
3817 dh
*= client
.height_inc
;
3820 frame
.changing
.setSize(dw
, dh
);
3822 // add the frame margin back onto frame.changing
3823 frame
.changing
.setCoords(frame
.changing
.left() - frame
.margin
.left
,
3824 frame
.changing
.top() - frame
.margin
.top
,
3825 frame
.changing
.right() + frame
.margin
.right
,
3826 frame
.changing
.bottom() + frame
.margin
.bottom
);
3828 // move frame.changing to the specified anchor
3836 dx
= frame
.rect
.right() - frame
.changing
.right();
3840 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3844 dx
= frame
.rect
.right() - frame
.changing
.right();
3845 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3849 assert(false); // unhandled corner
3851 frame
.changing
.setPos(frame
.changing
.x() + dx
, frame
.changing
.y() + dy
);
3855 void WindowStyle::doJustify(const std::string
&text
, int &start_pos
,
3856 unsigned int max_length
,
3857 unsigned int modifier
) const {
3858 size_t text_len
= text
.size();
3859 unsigned int length
;
3862 length
= font
->measureString(string(text
, 0, text_len
)) + modifier
;
3863 } while (length
> max_length
&& text_len
-- > 0);
3867 start_pos
+= max_length
- length
;
3871 start_pos
+= (max_length
- length
) / 2;
3881 BWindowGroup::BWindowGroup(Blackbox
*b
, Window _group
)
3882 : blackbox(b
), group(_group
) {
3883 XWindowAttributes wattrib
;
3884 if (! XGetWindowAttributes(blackbox
->getXDisplay(), group
, &wattrib
)) {
3885 // group window doesn't seem to exist anymore
3890 XSelectInput(blackbox
->getXDisplay(), group
,
3891 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
3893 blackbox
->saveGroupSearch(group
, this);
3897 BWindowGroup::~BWindowGroup(void) {
3898 blackbox
->removeGroupSearch(group
);
3903 BWindowGroup::find(BScreen
*screen
, bool allow_transients
) const {
3904 BlackboxWindow
*ret
= blackbox
->getFocusedWindow();
3906 // does the focus window match (or any transient_fors)?
3908 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3909 if (ret
->isTransient() && allow_transients
) break;
3910 else if (! ret
->isTransient()) break;
3913 ret
= ret
->getTransientFor();
3916 if (ret
) return ret
;
3918 // the focus window didn't match, look in the group's window list
3919 BlackboxWindowList::const_iterator it
, end
= windowList
.end();
3920 for (it
= windowList
.begin(); it
!= end
; ++it
) {
3922 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3923 if (ret
->isTransient() && allow_transients
) break;
3924 else if (! ret
->isTransient()) break;