1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2 // Window.cc for Blackbox - an X11 Window manager
3 // Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry <shaleh at debian.org>
4 // Copyright (c) 1997 - 2000, 2002 Brad Hughes <bhughes at trolltech.com>
6 // Permission is hereby granted, free of charge, to any person obtaining a
7 // copy of this software and associated documentation files (the "Software"),
8 // to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 // and/or sell copies of the Software, and to permit persons to whom the
11 // Software is furnished to do so, subject to the following conditions:
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 // DEALINGS IN THE SOFTWARE.
25 # include "../config.h"
26 #endif // HAVE_CONFIG_H
29 #include <X11/Xatom.h>
30 #include <X11/keysym.h>
34 #endif // HAVE_STRING_H
39 # endif // HAVE_STDIO_H
46 #include "blackbox.hh"
47 #include "Clientmenu.hh"
50 #include "Iconmenu.hh"
56 #include "Windowmenu.hh"
57 #include "Workspace.hh"
62 // change this to change what modifier keys openbox uses for mouse bindings
63 // for example: Mod1Mask | ControlMask
64 // or: ControlMask| ShiftMask
65 const unsigned int ModMask
= Mod1Mask
;
68 * Initializes the class with default values/the window's set initial values.
70 BlackboxWindow::BlackboxWindow(Blackbox
*b
, Window w
, BScreen
*s
) {
71 // fprintf(stderr, "BlackboxWindow size: %d bytes\n",
72 // sizeof(BlackboxWindow));
75 fprintf(stderr
, "BlackboxWindow::BlackboxWindow(): creating 0x%lx\n", w
);
79 set timer to zero... it is initialized properly later, so we check
80 if timer is zero in the destructor, and assume that the window is not
81 fully constructed if timer is zero...
87 xatom
= blackbox
->getXAtom();
89 if (! validateClient()) {
94 // set the eventmask early in the game so that we make sure we get
95 // all the events we are interested in
96 XSetWindowAttributes attrib_set
;
97 attrib_set
.event_mask
= PropertyChangeMask
| FocusChangeMask
|
99 attrib_set
.do_not_propagate_mask
= ButtonPressMask
| ButtonReleaseMask
|
101 XChangeWindowAttributes(blackbox
->getXDisplay(), client
.window
,
102 CWEventMask
|CWDontPropagate
, &attrib_set
);
104 // fetch client size and placement
105 XWindowAttributes wattrib
;
106 if ((! XGetWindowAttributes(blackbox
->getXDisplay(),
107 client
.window
, &wattrib
)) ||
108 (! wattrib
.screen
) || wattrib
.override_redirect
) {
111 "BlackboxWindow::BlackboxWindow(): XGetWindowAttributes failed\n");
118 flags
.moving
= flags
.resizing
= flags
.shaded
= flags
.visible
=
119 flags
.iconic
= flags
.focused
= flags
.stuck
= flags
.modal
=
120 flags
.send_focus_message
= flags
.shaped
= flags
.skip_taskbar
=
121 flags
.skip_pager
= flags
.fullscreen
= False
;
124 blackbox_attrib
.workspace
= window_number
= BSENTINEL
;
126 blackbox_attrib
.flags
= blackbox_attrib
.attrib
= blackbox_attrib
.stack
127 = blackbox_attrib
.decoration
= 0l;
128 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
129 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
132 frame
.window
= frame
.plate
= frame
.title
= frame
.handle
= None
;
133 frame
.close_button
= frame
.iconify_button
= frame
.maximize_button
= None
;
134 frame
.right_grip
= frame
.left_grip
= None
;
136 frame
.ulabel_pixel
= frame
.flabel_pixel
= frame
.utitle_pixel
=
137 frame
.ftitle_pixel
= frame
.uhandle_pixel
= frame
.fhandle_pixel
=
138 frame
.ubutton_pixel
= frame
.fbutton_pixel
= frame
.pbutton_pixel
=
139 frame
.uborder_pixel
= frame
.fborder_pixel
= frame
.ugrip_pixel
=
140 frame
.fgrip_pixel
= 0;
141 frame
.utitle
= frame
.ftitle
= frame
.uhandle
= frame
.fhandle
= None
;
142 frame
.ulabel
= frame
.flabel
= frame
.ubutton
= frame
.fbutton
= None
;
143 frame
.pbutton
= frame
.ugrip
= frame
.fgrip
= None
;
145 decorations
= Decor_Titlebar
| Decor_Border
| Decor_Handle
|
146 Decor_Iconify
| Decor_Maximize
;
147 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
149 client
.wm_hint_flags
= client
.normal_hint_flags
= 0;
150 client
.window_group
= None
;
151 client
.transient_for
= 0;
154 get the initial size and location of client window (relative to the
155 _root window_). This position is the reference point used with the
156 window's gravity to find the window's initial position.
158 client
.rect
.setRect(wattrib
.x
, wattrib
.y
, wattrib
.width
, wattrib
.height
);
159 client
.old_bw
= wattrib
.border_width
;
162 lastButtonPressTime
= 0;
164 timer
= new BTimer(blackbox
, this);
165 timer
->setTimeout(blackbox
->getAutoRaiseDelay());
167 if (! getBlackboxHints()) {
172 // get size, aspect, minimum/maximum size and other hints set by the
178 if (client
.initial_state
== WithdrawnState
) {
179 screen
->getSlit()->addClient(client
.window
);
184 frame
.window
= createToplevelWindow();
185 frame
.plate
= createChildWindow(frame
.window
);
186 associateClientWindow();
188 blackbox
->saveWindowSearch(frame
.window
, this);
189 blackbox
->saveWindowSearch(frame
.plate
, this);
190 blackbox
->saveWindowSearch(client
.window
, this);
192 // determine if this is a transient window
195 // determine the window's type, so we can decide its decorations and
196 // functionality, or if we should not manage it at all
199 // adjust the window decorations/behavior based on the window type
200 switch (window_type
) {
207 // none of these windows are decorated or manipulated by the window manager
210 blackbox_attrib
.workspace
= 0; // we do need to belong to a workspace
211 flags
.stuck
= True
; // we show up on all workspaces
215 // dialogs cannot be maximized, and don't display a handle
216 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
217 functions
&= ~Func_Maximize
;
221 // normal windows retain all of the possible decorations and functionality
225 // further adjeust the window's decorations/behavior based on window sizes
226 if ((client
.normal_hint_flags
& PMinSize
) &&
227 (client
.normal_hint_flags
& PMaxSize
) &&
228 client
.max_width
<= client
.min_width
&&
229 client
.max_height
<= client
.min_height
) {
230 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
231 functions
&= ~(Func_Resize
| Func_Maximize
);
237 bool place_window
= True
;
238 if (blackbox
->isStartup() || isTransient() ||
239 client
.normal_hint_flags
& (PPosition
|USPosition
)) {
240 applyGravity(frame
.rect
);
242 if (blackbox
->isStartup() || client
.rect
.intersects(screen
->getRect()))
243 place_window
= False
;
246 // add the window's strut. note this is done *after* placing the window.
247 screen
->addStrut(&client
.strut
);
250 if (decorations
& Decor_Titlebar
)
253 if (decorations
& Decor_Handle
)
257 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
262 windowmenu
= new Windowmenu(this);
264 if (blackbox_attrib
.workspace
>= screen
->getWorkspaceCount())
265 screen
->getCurrentWorkspace()->addWindow(this, place_window
);
267 screen
->getWorkspace(blackbox_attrib
.workspace
)->
268 addWindow(this, place_window
);
270 if (! place_window
) {
271 // don't need to call configure if we are letting the workspace
273 configure(frame
.rect
.x(), frame
.rect
.y(),
274 frame
.rect
.width(), frame
.rect
.height());
277 // preserve the window's initial state on first map, and its current state
280 if (client
.wm_hint_flags
& StateHint
)
281 current_state
= client
.initial_state
;
283 current_state
= NormalState
;
286 // get sticky state from our parent window if we've got one
287 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
288 client
.transient_for
->isStuck() != flags
.stuck
)
292 flags
.shaded
= False
;
293 unsigned long orig_state
= current_state
;
297 At this point in the life of a window, current_state should only be set
298 to IconicState if the window was an *icon*, not if it was shaded.
300 if (orig_state
!= IconicState
)
301 current_state
= NormalState
;
309 if (flags
.maximized
&& (functions
& Func_Maximize
)) {
314 When the window is mapped (and also when its attributes are restored), the
315 current_state that was set here will be used.
316 It is set to Normal if the window is to be mapped or it is set to Iconic
317 if the window is to be iconified.
318 *Note* that for sticky windows, the same rules apply here, they are in
319 fact never set to Iconic since there is no way for us to tell if a sticky
320 window was iconified previously.
327 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
333 BlackboxWindow::~BlackboxWindow(void) {
335 fprintf(stderr
, "BlackboxWindow::~BlackboxWindow: destroying 0x%lx\n",
339 if (! timer
) // window not managed...
342 screen
->removeStrut(&client
.strut
);
343 screen
->updateAvailableArea();
345 // We don't need to worry about resizing because resizing always grabs the X
346 // server. This should only ever happen if using opaque moving.
350 if (client
.window_group
) {
351 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
352 if (group
) group
->removeWindow(this);
355 // remove ourselves from our transient_for
357 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
358 client
.transient_for
->client
.transientList
.remove(this);
360 // we save our transient_for though because the workspace will use it
361 // when determining the next window to get focus
364 if (blackbox_attrib
.workspace
!= BSENTINEL
&&
365 window_number
!= BSENTINEL
)
366 screen
->getWorkspace(blackbox_attrib
.workspace
)->removeWindow(this);
367 else if (flags
.iconic
)
368 screen
->removeIcon(this);
370 client
.transient_for
= (BlackboxWindow
*) 0;
372 if (client
.transientList
.size() > 0) {
373 // reset transient_for for all transients
374 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
375 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
376 (*it
)->client
.transient_for
= (BlackboxWindow
*) 0;
391 blackbox
->removeWindowSearch(frame
.plate
);
392 XDestroyWindow(blackbox
->getXDisplay(), frame
.plate
);
396 blackbox
->removeWindowSearch(frame
.window
);
397 XDestroyWindow(blackbox
->getXDisplay(), frame
.window
);
400 blackbox
->removeWindowSearch(client
.window
);
405 * Creates a new top level window, with a given location, size, and border
407 * Returns: the newly created window
409 Window
BlackboxWindow::createToplevelWindow(void) {
410 XSetWindowAttributes attrib_create
;
411 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
| CWColormap
|
412 CWOverrideRedirect
| CWEventMask
;
414 attrib_create
.background_pixmap
= None
;
415 attrib_create
.colormap
= screen
->getColormap();
416 attrib_create
.override_redirect
= True
;
417 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
418 ButtonMotionMask
| EnterWindowMask
;
420 return XCreateWindow(blackbox
->getXDisplay(), screen
->getRootWindow(),
421 0, 0, 1, 1, frame
.border_w
, screen
->getDepth(),
422 InputOutput
, screen
->getVisual(), create_mask
,
428 * Creates a child window, and optionally associates a given cursor with
431 Window
BlackboxWindow::createChildWindow(Window parent
, Cursor cursor
) {
432 XSetWindowAttributes attrib_create
;
433 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
|
436 attrib_create
.background_pixmap
= None
;
437 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
438 ButtonMotionMask
| ExposureMask
;
441 create_mask
|= CWCursor
;
442 attrib_create
.cursor
= cursor
;
445 return XCreateWindow(blackbox
->getXDisplay(), parent
, 0, 0, 1, 1, 0,
446 screen
->getDepth(), InputOutput
, screen
->getVisual(),
447 create_mask
, &attrib_create
);
451 void BlackboxWindow::associateClientWindow(void) {
452 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, 0);
456 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeInsert
);
458 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, SubstructureRedirectMask
);
460 XGrabServer(blackbox
->getXDisplay());
462 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
464 XSelectInput(blackbox
->getXDisplay(), client
.window
,
465 event_mask
& ~StructureNotifyMask
);
466 XReparentWindow(blackbox
->getXDisplay(), client
.window
, frame
.plate
, 0, 0);
467 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
469 XUngrabServer(blackbox
->getXDisplay());
471 XRaiseWindow(blackbox
->getXDisplay(), frame
.plate
);
472 XMapSubwindows(blackbox
->getXDisplay(), frame
.plate
);
476 if (blackbox
->hasShapeExtensions()) {
477 XShapeSelectInput(blackbox
->getXDisplay(), client
.window
,
484 XShapeQueryExtents(blackbox
->getXDisplay(), client
.window
, &shaped
,
485 &foo
, &foo
, &ufoo
, &ufoo
, &foo
, &foo
, &foo
,
487 flags
.shaped
= shaped
;
493 void BlackboxWindow::decorate(void) {
496 texture
= &(screen
->getWindowStyle()->b_focus
);
497 frame
.fbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
500 frame
.fbutton_pixel
= texture
->color().pixel();
502 texture
= &(screen
->getWindowStyle()->b_unfocus
);
503 frame
.ubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
506 frame
.ubutton_pixel
= texture
->color().pixel();
508 texture
= &(screen
->getWindowStyle()->b_pressed
);
509 frame
.pbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
512 frame
.pbutton_pixel
= texture
->color().pixel();
514 if (decorations
& Decor_Titlebar
) {
515 texture
= &(screen
->getWindowStyle()->t_focus
);
516 frame
.ftitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
519 frame
.ftitle_pixel
= texture
->color().pixel();
521 texture
= &(screen
->getWindowStyle()->t_unfocus
);
522 frame
.utitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
525 frame
.utitle_pixel
= texture
->color().pixel();
527 XSetWindowBorder(blackbox
->getXDisplay(), frame
.title
,
528 screen
->getBorderColor()->pixel());
533 if (decorations
& Decor_Border
) {
534 frame
.fborder_pixel
= screen
->getWindowStyle()->f_focus
.pixel();
535 frame
.uborder_pixel
= screen
->getWindowStyle()->f_unfocus
.pixel();
536 blackbox_attrib
.flags
|= AttribDecoration
;
537 blackbox_attrib
.decoration
= DecorNormal
;
539 blackbox_attrib
.flags
|= AttribDecoration
;
540 blackbox_attrib
.decoration
= DecorNone
;
543 if (decorations
& Decor_Handle
) {
544 texture
= &(screen
->getWindowStyle()->h_focus
);
545 frame
.fhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
548 frame
.fhandle_pixel
= texture
->color().pixel();
550 texture
= &(screen
->getWindowStyle()->h_unfocus
);
551 frame
.uhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
554 frame
.uhandle_pixel
= texture
->color().pixel();
556 texture
= &(screen
->getWindowStyle()->g_focus
);
557 frame
.fgrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.fgrip
);
559 frame
.fgrip_pixel
= texture
->color().pixel();
561 texture
= &(screen
->getWindowStyle()->g_unfocus
);
562 frame
.ugrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.ugrip
);
564 frame
.ugrip_pixel
= texture
->color().pixel();
566 XSetWindowBorder(blackbox
->getXDisplay(), frame
.handle
,
567 screen
->getBorderColor()->pixel());
568 XSetWindowBorder(blackbox
->getXDisplay(), frame
.left_grip
,
569 screen
->getBorderColor()->pixel());
570 XSetWindowBorder(blackbox
->getXDisplay(), frame
.right_grip
,
571 screen
->getBorderColor()->pixel());
574 XSetWindowBorder(blackbox
->getXDisplay(), frame
.window
,
575 screen
->getBorderColor()->pixel());
579 void BlackboxWindow::decorateLabel(void) {
582 texture
= &(screen
->getWindowStyle()->l_focus
);
583 frame
.flabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.flabel
);
585 frame
.flabel_pixel
= texture
->color().pixel();
587 texture
= &(screen
->getWindowStyle()->l_unfocus
);
588 frame
.ulabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.ulabel
);
590 frame
.ulabel_pixel
= texture
->color().pixel();
594 void BlackboxWindow::createHandle(void) {
595 frame
.handle
= createChildWindow(frame
.window
);
596 blackbox
->saveWindowSearch(frame
.handle
, this);
599 createChildWindow(frame
.handle
, blackbox
->getLowerLeftAngleCursor());
600 blackbox
->saveWindowSearch(frame
.left_grip
, this);
603 createChildWindow(frame
.handle
, blackbox
->getLowerRightAngleCursor());
604 blackbox
->saveWindowSearch(frame
.right_grip
, this);
608 void BlackboxWindow::destroyHandle(void) {
610 screen
->getImageControl()->removeImage(frame
.fhandle
);
613 screen
->getImageControl()->removeImage(frame
.uhandle
);
616 screen
->getImageControl()->removeImage(frame
.fgrip
);
619 screen
->getImageControl()->removeImage(frame
.ugrip
);
621 blackbox
->removeWindowSearch(frame
.left_grip
);
622 blackbox
->removeWindowSearch(frame
.right_grip
);
624 XDestroyWindow(blackbox
->getXDisplay(), frame
.left_grip
);
625 XDestroyWindow(blackbox
->getXDisplay(), frame
.right_grip
);
626 frame
.left_grip
= frame
.right_grip
= None
;
628 blackbox
->removeWindowSearch(frame
.handle
);
629 XDestroyWindow(blackbox
->getXDisplay(), frame
.handle
);
634 void BlackboxWindow::createTitlebar(void) {
635 frame
.title
= createChildWindow(frame
.window
);
636 frame
.label
= createChildWindow(frame
.title
);
637 blackbox
->saveWindowSearch(frame
.title
, this);
638 blackbox
->saveWindowSearch(frame
.label
, this);
640 if (decorations
& Decor_Iconify
) createIconifyButton();
641 if (decorations
& Decor_Maximize
) createMaximizeButton();
642 if (decorations
& Decor_Close
) createCloseButton();
646 void BlackboxWindow::destroyTitlebar(void) {
647 if (frame
.close_button
)
648 destroyCloseButton();
650 if (frame
.iconify_button
)
651 destroyIconifyButton();
653 if (frame
.maximize_button
)
654 destroyMaximizeButton();
657 screen
->getImageControl()->removeImage(frame
.ftitle
);
660 screen
->getImageControl()->removeImage(frame
.utitle
);
663 screen
->getImageControl()->removeImage(frame
.flabel
);
666 screen
->getImageControl()->removeImage(frame
.ulabel
);
669 screen
->getImageControl()->removeImage(frame
.fbutton
);
672 screen
->getImageControl()->removeImage(frame
.ubutton
);
675 screen
->getImageControl()->removeImage(frame
.pbutton
);
677 blackbox
->removeWindowSearch(frame
.title
);
678 blackbox
->removeWindowSearch(frame
.label
);
680 XDestroyWindow(blackbox
->getXDisplay(), frame
.label
);
681 XDestroyWindow(blackbox
->getXDisplay(), frame
.title
);
682 frame
.title
= frame
.label
= None
;
686 void BlackboxWindow::createCloseButton(void) {
687 if (frame
.title
!= None
) {
688 frame
.close_button
= createChildWindow(frame
.title
);
689 blackbox
->saveWindowSearch(frame
.close_button
, this);
694 void BlackboxWindow::destroyCloseButton(void) {
695 blackbox
->removeWindowSearch(frame
.close_button
);
696 XDestroyWindow(blackbox
->getXDisplay(), frame
.close_button
);
697 frame
.close_button
= None
;
701 void BlackboxWindow::createIconifyButton(void) {
702 if (frame
.title
!= None
) {
703 frame
.iconify_button
= createChildWindow(frame
.title
);
704 blackbox
->saveWindowSearch(frame
.iconify_button
, this);
709 void BlackboxWindow::destroyIconifyButton(void) {
710 blackbox
->removeWindowSearch(frame
.iconify_button
);
711 XDestroyWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
712 frame
.iconify_button
= None
;
716 void BlackboxWindow::createMaximizeButton(void) {
717 if (frame
.title
!= None
) {
718 frame
.maximize_button
= createChildWindow(frame
.title
);
719 blackbox
->saveWindowSearch(frame
.maximize_button
, this);
724 void BlackboxWindow::destroyMaximizeButton(void) {
725 blackbox
->removeWindowSearch(frame
.maximize_button
);
726 XDestroyWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
727 frame
.maximize_button
= None
;
731 void BlackboxWindow::positionButtons(bool redecorate_label
) {
732 string layout
= blackbox
->getTitlebarLayout();
735 bool hasclose
, hasiconify
, hasmaximize
, haslabel
;
736 hasclose
= hasiconify
= hasmaximize
= haslabel
= false;
738 string::const_iterator it
, end
;
739 for (it
= layout
.begin(), end
= layout
.end(); it
!= end
; ++it
) {
742 if (! hasclose
&& (decorations
& Decor_Close
)) {
748 if (! hasiconify
&& (decorations
& Decor_Iconify
)) {
754 if (! hasmaximize
&& (decorations
& Decor_Maximize
)) {
766 if (! hasclose
&& frame
.close_button
)
767 destroyCloseButton();
768 if (! hasiconify
&& frame
.iconify_button
)
769 destroyIconifyButton();
770 if (! hasmaximize
&& frame
.maximize_button
)
771 destroyMaximizeButton();
773 parsed
+= 'L'; // require that the label be in the layout
775 const unsigned int bsep
= frame
.bevel_w
+ 1; // separation between elements
776 const unsigned int by
= frame
.bevel_w
+ 1;
777 const unsigned int ty
= frame
.bevel_w
;
779 frame
.label_w
= frame
.inside_w
- bsep
* 2 -
780 (frame
.button_w
+ bsep
) * (parsed
.size() - 1);
782 unsigned int x
= bsep
;
783 for (it
= parsed
.begin(), end
= parsed
.end(); it
!= end
; ++it
) {
786 if (! frame
.close_button
) createCloseButton();
787 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.close_button
, x
, by
,
788 frame
.button_w
, frame
.button_w
);
789 x
+= frame
.button_w
+ bsep
;
792 if (! frame
.iconify_button
) createIconifyButton();
793 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.iconify_button
, x
, by
,
794 frame
.button_w
, frame
.button_w
);
795 x
+= frame
.button_w
+ bsep
;
798 if (! frame
.maximize_button
) createMaximizeButton();
799 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.maximize_button
, x
, by
,
800 frame
.button_w
, frame
.button_w
);
801 x
+= frame
.button_w
+ bsep
;
804 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.label
, x
, ty
,
805 frame
.label_w
, frame
.label_h
);
806 x
+= frame
.label_w
+ bsep
;
811 if (redecorate_label
) decorateLabel();
817 void BlackboxWindow::reconfigure(void) {
818 restoreGravity(client
.rect
);
820 applyGravity(frame
.rect
);
829 windowmenu
->move(windowmenu
->getX(), frame
.rect
.y() + frame
.title_h
);
830 windowmenu
->reconfigure();
835 void BlackboxWindow::grabButtons(void) {
836 if (! screen
->isSloppyFocus() || screen
->doClickRaise())
837 // grab button 1 for changing focus/raising
838 blackbox
->grabButton(Button1
, 0, frame
.plate
, True
, ButtonPressMask
,
839 GrabModeSync
, GrabModeSync
, frame
.plate
, None
,
840 screen
->allowScrollLock());
842 if (functions
& Func_Move
)
843 blackbox
->grabButton(Button1
, ModMask
, frame
.window
, True
,
844 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
845 GrabModeAsync
, frame
.window
, None
,
846 screen
->allowScrollLock());
847 if (functions
& Func_Resize
)
848 blackbox
->grabButton(Button3
, ModMask
, frame
.window
, True
,
849 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
850 GrabModeAsync
, frame
.window
, None
,
851 screen
->allowScrollLock());
852 // alt+middle lowers the window
853 blackbox
->grabButton(Button2
, ModMask
, frame
.window
, True
,
854 ButtonReleaseMask
, GrabModeAsync
, GrabModeAsync
,
856 screen
->allowScrollLock());
860 void BlackboxWindow::ungrabButtons(void) {
861 if ((! screen
->isSloppyFocus()) || screen
->doClickRaise())
862 blackbox
->ungrabButton(Button1
, 0, frame
.plate
);
864 blackbox
->ungrabButton(Button1
, ModMask
, frame
.window
);
865 blackbox
->ungrabButton(Button2
, ModMask
, frame
.window
);
866 blackbox
->ungrabButton(Button3
, ModMask
, frame
.window
);
870 void BlackboxWindow::positionWindows(void) {
871 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.window
,
872 frame
.rect
.x(), frame
.rect
.y(), frame
.inside_w
,
873 (flags
.shaded
) ? frame
.title_h
: frame
.inside_h
);
874 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.window
,
876 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.plate
,
878 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.plate
,
879 frame
.margin
.left
- frame
.mwm_border_w
- frame
.border_w
,
880 frame
.margin
.top
- frame
.mwm_border_w
- frame
.border_w
,
881 client
.rect
.width(), client
.rect
.height());
882 XMoveResizeWindow(blackbox
->getXDisplay(), client
.window
,
883 0, 0, client
.rect
.width(), client
.rect
.height());
884 // ensure client.rect contains the real location
885 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
886 frame
.rect
.top() + frame
.margin
.top
);
888 if (decorations
& Decor_Titlebar
) {
889 if (frame
.title
== None
) createTitlebar();
891 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.title
,
893 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.title
, -frame
.border_w
,
894 -frame
.border_w
, frame
.inside_w
, frame
.title_h
);
897 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
898 XMapWindow(blackbox
->getXDisplay(), frame
.title
);
899 } else if (frame
.title
) {
902 if (decorations
& Decor_Handle
) {
903 if (frame
.handle
== None
) createHandle();
904 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.handle
,
906 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.left_grip
,
908 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.right_grip
,
911 // use client.rect here so the value is correct even if shaded
912 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.handle
,
914 client
.rect
.height() + frame
.margin
.top
+
915 frame
.mwm_border_w
- frame
.border_w
,
916 frame
.inside_w
, frame
.handle_h
);
917 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.left_grip
,
918 -frame
.border_w
, -frame
.border_w
,
919 frame
.grip_w
, frame
.handle_h
);
920 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.right_grip
,
921 frame
.inside_w
- frame
.grip_w
- frame
.border_w
,
922 -frame
.border_w
, frame
.grip_w
, frame
.handle_h
);
924 XMapSubwindows(blackbox
->getXDisplay(), frame
.handle
);
925 XMapWindow(blackbox
->getXDisplay(), frame
.handle
);
926 } else if (frame
.handle
) {
929 XSync(blackbox
->getXDisplay(), False
);
933 void BlackboxWindow::updateStrut(void) {
934 unsigned long num
= 4;
936 if (! xatom
->getValue(client
.window
, XAtom::net_wm_strut
, XAtom::cardinal
,
941 client
.strut
.left
= data
[0];
942 client
.strut
.right
= data
[1];
943 client
.strut
.top
= data
[2];
944 client
.strut
.bottom
= data
[3];
946 screen
->updateAvailableArea();
953 void BlackboxWindow::getWindowType(void) {
955 if (xatom
->getValue(client
.window
, XAtom::net_wm_window_type
, XAtom::atom
,
957 if (val
== xatom
->getAtom(XAtom::net_wm_window_type_desktop
))
958 window_type
= Type_Desktop
;
959 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_dock
))
960 window_type
= Type_Dock
;
961 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_toolbar
))
962 window_type
= Type_Toolbar
;
963 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_menu
))
964 window_type
= Type_Menu
;
965 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_utility
))
966 window_type
= Type_Utility
;
967 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_splash
))
968 window_type
= Type_Splash
;
969 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_dialog
))
970 window_type
= Type_Dialog
;
971 else //if (val[0] == xatom->getAtom(XAtom::net_wm_window_type_normal))
972 window_type
= Type_Normal
;
977 * the window type hint was not set, which means we either classify ourself
978 * as a normal window or a dialog, depending on if we are a transient.
981 window_type
= Type_Dialog
;
983 window_type
= Type_Normal
;
987 void BlackboxWindow::getWMName(void) {
988 if (xatom
->getValue(client
.window
, XAtom::net_wm_name
,
989 XAtom::utf8
, client
.title
) &&
990 !client
.title
.empty()) {
991 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
994 //fall through to using WM_NAME
995 if (xatom
->getValue(client
.window
, XAtom::wm_name
, XAtom::ansi
, client
.title
)
996 && !client
.title
.empty()) {
997 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
1000 // fall back to an internal default
1001 client
.title
= i18n(WindowSet
, WindowUnnamed
, "Unnamed");
1002 xatom
->setValue(client
.window
, XAtom::net_wm_visible_name
, XAtom::utf8
,
1007 void BlackboxWindow::getWMIconName(void) {
1008 if (xatom
->getValue(client
.window
, XAtom::net_wm_icon_name
,
1009 XAtom::utf8
, client
.icon_title
) &&
1010 !client
.icon_title
.empty()) {
1011 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1014 //fall through to using WM_ICON_NAME
1015 if (xatom
->getValue(client
.window
, XAtom::wm_icon_name
, XAtom::ansi
,
1016 client
.icon_title
) &&
1017 !client
.icon_title
.empty()) {
1018 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1021 // fall back to using the main name
1022 client
.icon_title
= client
.title
;
1023 xatom
->setValue(client
.window
, XAtom::net_wm_visible_icon_name
, XAtom::utf8
,
1029 * Retrieve which WM Protocols are supported by the client window.
1030 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
1031 * window's decorations and allow the close behavior.
1032 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
1035 void BlackboxWindow::getWMProtocols(void) {
1039 if (XGetWMProtocols(blackbox
->getXDisplay(), client
.window
,
1040 &proto
, &num_return
)) {
1041 for (int i
= 0; i
< num_return
; ++i
) {
1042 if (proto
[i
] == xatom
->getAtom(XAtom::wm_delete_window
)) {
1043 decorations
|= Decor_Close
;
1044 functions
|= Func_Close
;
1045 } else if (proto
[i
] == xatom
->getAtom(XAtom::wm_take_focus
))
1046 flags
.send_focus_message
= True
;
1047 else if (proto
[i
] == xatom
->getAtom(XAtom::blackbox_structure_messages
))
1048 screen
->addNetizen(new Netizen(screen
, client
.window
));
1057 * Gets the value of the WM_HINTS property.
1058 * If the property is not set, then use a set of default values.
1060 void BlackboxWindow::getWMHints(void) {
1061 focus_mode
= F_Passive
;
1062 client
.initial_state
= NormalState
;
1064 // remove from current window group
1065 if (client
.window_group
) {
1066 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1067 if (group
) group
->removeWindow(this);
1069 client
.window_group
= None
;
1071 XWMHints
*wmhint
= XGetWMHints(blackbox
->getXDisplay(), client
.window
);
1076 if (wmhint
->flags
& InputHint
) {
1077 if (wmhint
->input
== True
) {
1078 if (flags
.send_focus_message
)
1079 focus_mode
= F_LocallyActive
;
1081 if (flags
.send_focus_message
)
1082 focus_mode
= F_GloballyActive
;
1084 focus_mode
= F_NoInput
;
1088 if (wmhint
->flags
& StateHint
)
1089 client
.initial_state
= wmhint
->initial_state
;
1091 if (wmhint
->flags
& WindowGroupHint
) {
1092 client
.window_group
= wmhint
->window_group
;
1094 // add window to the appropriate group
1095 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1096 if (! group
) { // no group found, create it!
1097 new BWindowGroup(blackbox
, client
.window_group
);
1098 group
= blackbox
->searchGroup(client
.window_group
);
1101 group
->addWindow(this);
1104 client
.wm_hint_flags
= wmhint
->flags
;
1110 * Gets the value of the WM_NORMAL_HINTS property.
1111 * If the property is not set, then use a set of default values.
1113 void BlackboxWindow::getWMNormalHints(void) {
1115 XSizeHints sizehint
;
1117 client
.min_width
= client
.min_height
=
1118 client
.width_inc
= client
.height_inc
= 1;
1119 client
.base_width
= client
.base_height
= 0;
1120 client
.win_gravity
= NorthWestGravity
;
1122 client
.min_aspect_x
= client
.min_aspect_y
=
1123 client
.max_aspect_x
= client
.max_aspect_y
= 1;
1127 use the full screen, not the strut modified size. otherwise when the
1128 availableArea changes max_width/height will be incorrect and lead to odd
1131 const Rect
& screen_area
= screen
->getRect();
1132 client
.max_width
= screen_area
.width();
1133 client
.max_height
= screen_area
.height();
1135 if (! XGetWMNormalHints(blackbox
->getXDisplay(), client
.window
,
1136 &sizehint
, &icccm_mask
))
1139 client
.normal_hint_flags
= sizehint
.flags
;
1141 if (sizehint
.flags
& PMinSize
) {
1142 if (sizehint
.min_width
>= 0)
1143 client
.min_width
= sizehint
.min_width
;
1144 if (sizehint
.min_height
>= 0)
1145 client
.min_height
= sizehint
.min_height
;
1148 if (sizehint
.flags
& PMaxSize
) {
1149 if (sizehint
.max_width
> static_cast<signed>(client
.min_width
))
1150 client
.max_width
= sizehint
.max_width
;
1152 client
.max_width
= client
.min_width
;
1154 if (sizehint
.max_height
> static_cast<signed>(client
.min_height
))
1155 client
.max_height
= sizehint
.max_height
;
1157 client
.max_height
= client
.min_height
;
1160 if (sizehint
.flags
& PResizeInc
) {
1161 client
.width_inc
= sizehint
.width_inc
;
1162 client
.height_inc
= sizehint
.height_inc
;
1165 #if 0 // we do not support this at the moment
1166 if (sizehint
.flags
& PAspect
) {
1167 client
.min_aspect_x
= sizehint
.min_aspect
.x
;
1168 client
.min_aspect_y
= sizehint
.min_aspect
.y
;
1169 client
.max_aspect_x
= sizehint
.max_aspect
.x
;
1170 client
.max_aspect_y
= sizehint
.max_aspect
.y
;
1174 if (sizehint
.flags
& PBaseSize
) {
1175 client
.base_width
= sizehint
.base_width
;
1176 client
.base_height
= sizehint
.base_height
;
1179 if (sizehint
.flags
& PWinGravity
)
1180 client
.win_gravity
= sizehint
.win_gravity
;
1185 * Gets the NETWM hints for the class' contained window.
1187 void BlackboxWindow::getNetWMHints(void) {
1188 unsigned long workspace
;
1190 if (xatom
->getValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1192 if (workspace
== 0xffffffff)
1195 blackbox_attrib
.workspace
= workspace
;
1198 unsigned long *state
;
1199 unsigned long num
= (unsigned) -1;
1200 if (xatom
->getValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
1204 for (unsigned long i
= 0; i
< num
; ++i
) {
1205 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
))
1207 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_shaded
))
1208 flags
.shaded
= True
;
1209 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
))
1210 flags
.skip_taskbar
= True
;
1211 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_pager
))
1212 flags
.skip_pager
= True
;
1213 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_fullscreen
))
1214 flags
.fullscreen
= True
;
1215 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_hidden
))
1216 setState(IconicState
);
1217 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_vert
))
1219 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_horz
))
1223 flags
.maximized
= 1;
1225 flags
.maximized
= 2;
1227 flags
.maximized
= 3;
1235 * Gets the MWM hints for the class' contained window.
1236 * This is used while initializing the window to its first state, and not
1238 * Returns: true if the MWM hints are successfully retreived and applied;
1239 * false if they are not.
1241 void BlackboxWindow::getMWMHints(void) {
1245 num
= PropMwmHintsElements
;
1246 if (! xatom
->getValue(client
.window
, XAtom::motif_wm_hints
,
1247 XAtom::motif_wm_hints
, num
,
1248 (unsigned long **)&mwm_hint
))
1250 if (num
< PropMwmHintsElements
) {
1255 if (mwm_hint
->flags
& MwmHintsDecorations
) {
1256 if (mwm_hint
->decorations
& MwmDecorAll
) {
1257 decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
1258 Decor_Iconify
| Decor_Maximize
| Decor_Close
;
1262 if (mwm_hint
->decorations
& MwmDecorBorder
)
1263 decorations
|= Decor_Border
;
1264 if (mwm_hint
->decorations
& MwmDecorHandle
)
1265 decorations
|= Decor_Handle
;
1266 if (mwm_hint
->decorations
& MwmDecorTitle
)
1267 decorations
|= Decor_Titlebar
;
1268 if (mwm_hint
->decorations
& MwmDecorIconify
)
1269 decorations
|= Decor_Iconify
;
1270 if (mwm_hint
->decorations
& MwmDecorMaximize
)
1271 decorations
|= Decor_Maximize
;
1275 if (mwm_hint
->flags
& MwmHintsFunctions
) {
1276 if (mwm_hint
->functions
& MwmFuncAll
) {
1277 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
|
1282 if (mwm_hint
->functions
& MwmFuncResize
)
1283 functions
|= Func_Resize
;
1284 if (mwm_hint
->functions
& MwmFuncMove
)
1285 functions
|= Func_Move
;
1286 if (mwm_hint
->functions
& MwmFuncIconify
)
1287 functions
|= Func_Iconify
;
1288 if (mwm_hint
->functions
& MwmFuncMaximize
)
1289 functions
|= Func_Maximize
;
1290 if (mwm_hint
->functions
& MwmFuncClose
)
1291 functions
|= Func_Close
;
1299 * Gets the blackbox hints from the class' contained window.
1300 * This is used while initializing the window to its first state, and not
1302 * Returns: true if the hints are successfully retreived and applied; false if
1305 bool BlackboxWindow::getBlackboxHints(void) {
1307 BlackboxHints
*blackbox_hint
;
1309 num
= PropBlackboxHintsElements
;
1310 if (! xatom
->getValue(client
.window
, XAtom::blackbox_hints
,
1311 XAtom::blackbox_hints
, num
,
1312 (unsigned long **)&blackbox_hint
))
1314 if (num
< PropBlackboxHintsElements
) {
1315 delete [] blackbox_hint
;
1319 if (blackbox_hint
->flags
& AttribShaded
)
1320 flags
.shaded
= (blackbox_hint
->attrib
& AttribShaded
);
1322 if ((blackbox_hint
->flags
& AttribMaxHoriz
) &&
1323 (blackbox_hint
->flags
& AttribMaxVert
))
1324 flags
.maximized
= (blackbox_hint
->attrib
&
1325 (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1326 else if (blackbox_hint
->flags
& AttribMaxVert
)
1327 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxVert
) ? 2 : 0;
1328 else if (blackbox_hint
->flags
& AttribMaxHoriz
)
1329 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1331 if (blackbox_hint
->flags
& AttribOmnipresent
)
1332 flags
.stuck
= (blackbox_hint
->attrib
& AttribOmnipresent
);
1334 if (blackbox_hint
->flags
& AttribWorkspace
)
1335 blackbox_attrib
.workspace
= blackbox_hint
->workspace
;
1337 // if (blackbox_hint->flags & AttribStack)
1338 // don't yet have always on top/bottom for blackbox yet... working
1341 if (blackbox_hint
->flags
& AttribDecoration
) {
1342 switch (blackbox_hint
->decoration
) {
1344 // clear all decorations except close
1345 decorations
&= Decor_Close
;
1346 // clear all functions except close
1347 functions
&= Func_Close
;
1352 decorations
|= Decor_Titlebar
| Decor_Iconify
;
1353 decorations
&= ~(Decor_Border
| Decor_Handle
| Decor_Maximize
);
1354 functions
|= Func_Move
| Func_Iconify
;
1355 functions
&= ~(Func_Resize
| Func_Maximize
);
1360 decorations
|= Decor_Titlebar
;
1361 decorations
&= ~(Decor_Iconify
| Decor_Border
| Decor_Handle
);
1362 functions
|= Func_Move
;
1363 functions
&= ~(Func_Resize
| Func_Maximize
| Func_Iconify
);
1369 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Handle
|
1370 Decor_Iconify
| Decor_Maximize
;
1371 functions
|= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
1379 delete [] blackbox_hint
;
1385 void BlackboxWindow::getTransientInfo(void) {
1386 if (client
.transient_for
&&
1387 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1388 // the transient for hint was removed, so we need to tell our
1389 // previous transient_for that we are going away
1390 client
.transient_for
->client
.transientList
.remove(this);
1393 // we have no transient_for until we find a new one
1394 client
.transient_for
= 0;
1397 if (! XGetTransientForHint(blackbox
->getXDisplay(), client
.window
,
1399 // transient_for hint not set
1403 if (trans_for
== client
.window
) {
1404 // wierd client... treat this window as a normal window
1408 if (trans_for
== None
|| trans_for
== screen
->getRootWindow()) {
1409 // this is an undocumented interpretation of the ICCCM. a transient
1410 // associated with None/Root/itself is assumed to be a modal root
1411 // transient. we don't support the concept of a global transient,
1412 // so we just associate this transient with nothing, and perhaps
1413 // we will add support later for global modality.
1414 client
.transient_for
= (BlackboxWindow
*) ~0ul;
1419 client
.transient_for
= blackbox
->searchWindow(trans_for
);
1420 if (! client
.transient_for
&&
1421 client
.window_group
&& trans_for
== client
.window_group
) {
1422 // no direct transient_for, perhaps this is a group transient?
1423 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1424 if (group
) client
.transient_for
= group
->find(screen
);
1427 if (! client
.transient_for
|| client
.transient_for
== this) {
1428 // no transient_for found, or we have a wierd client that wants to be
1429 // a transient for itself, so we treat this window as a normal window
1430 client
.transient_for
= (BlackboxWindow
*) 0;
1434 // register ourselves with our new transient_for
1435 client
.transient_for
->client
.transientList
.push_back(this);
1436 flags
.stuck
= client
.transient_for
->flags
.stuck
;
1440 BlackboxWindow
*BlackboxWindow::getTransientFor(void) const {
1441 if (client
.transient_for
&&
1442 client
.transient_for
!= (BlackboxWindow
*) ~0ul)
1443 return client
.transient_for
;
1449 * This function is responsible for updating both the client and the frame
1451 * According to the ICCCM a client message is not sent for a resize, only a
1454 void BlackboxWindow::configure(int dx
, int dy
,
1455 unsigned int dw
, unsigned int dh
) {
1456 bool send_event
= ((frame
.rect
.x() != dx
|| frame
.rect
.y() != dy
) &&
1459 if (dw
!= frame
.rect
.width() || dh
!= frame
.rect
.height()) {
1460 frame
.rect
.setRect(dx
, dy
, dw
, dh
);
1461 frame
.inside_w
= frame
.rect
.width() - (frame
.border_w
* 2);
1462 frame
.inside_h
= frame
.rect
.height() - (frame
.border_w
* 2);
1464 if (frame
.rect
.right() <= 0 || frame
.rect
.bottom() <= 0)
1465 frame
.rect
.setPos(0, 0);
1467 client
.rect
.setCoords(frame
.rect
.left() + frame
.margin
.left
,
1468 frame
.rect
.top() + frame
.margin
.top
,
1469 frame
.rect
.right() - frame
.margin
.right
,
1470 frame
.rect
.bottom() - frame
.margin
.bottom
);
1473 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
1480 redrawWindowFrame();
1482 frame
.rect
.setPos(dx
, dy
);
1484 XMoveWindow(blackbox
->getXDisplay(), frame
.window
,
1485 frame
.rect
.x(), frame
.rect
.y());
1487 we may have been called just after an opaque window move, so even though
1488 the old coords match the new ones no ConfigureNotify has been sent yet.
1489 There are likely other times when this will be relevant as well.
1491 if (! flags
.moving
) send_event
= True
;
1495 // if moving, the update and event will occur when the move finishes
1496 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1497 frame
.rect
.top() + frame
.margin
.top
);
1500 event
.type
= ConfigureNotify
;
1502 event
.xconfigure
.display
= blackbox
->getXDisplay();
1503 event
.xconfigure
.event
= client
.window
;
1504 event
.xconfigure
.window
= client
.window
;
1505 event
.xconfigure
.x
= client
.rect
.x();
1506 event
.xconfigure
.y
= client
.rect
.y();
1507 event
.xconfigure
.width
= client
.rect
.width();
1508 event
.xconfigure
.height
= client
.rect
.height();
1509 event
.xconfigure
.border_width
= client
.old_bw
;
1510 event
.xconfigure
.above
= frame
.window
;
1511 event
.xconfigure
.override_redirect
= False
;
1513 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1514 StructureNotifyMask
, &event
);
1515 screen
->updateNetizenConfigNotify(&event
);
1516 XFlush(blackbox
->getXDisplay());
1522 void BlackboxWindow::configureShape(void) {
1523 XShapeCombineShape(blackbox
->getXDisplay(), frame
.window
, ShapeBounding
,
1524 frame
.margin
.left
- frame
.border_w
,
1525 frame
.margin
.top
- frame
.border_w
,
1526 client
.window
, ShapeBounding
, ShapeSet
);
1529 XRectangle xrect
[2];
1531 if (decorations
& Decor_Titlebar
) {
1532 xrect
[0].x
= xrect
[0].y
= -frame
.border_w
;
1533 xrect
[0].width
= frame
.rect
.width();
1534 xrect
[0].height
= frame
.title_h
+ (frame
.border_w
* 2);
1538 if (decorations
& Decor_Handle
) {
1539 xrect
[1].x
= -frame
.border_w
;
1540 xrect
[1].y
= frame
.rect
.height() - frame
.margin
.bottom
+
1541 frame
.mwm_border_w
- frame
.border_w
;
1542 xrect
[1].width
= frame
.rect
.width();
1543 xrect
[1].height
= frame
.handle_h
+ (frame
.border_w
* 2);
1547 XShapeCombineRectangles(blackbox
->getXDisplay(), frame
.window
,
1548 ShapeBounding
, 0, 0, xrect
, num
,
1549 ShapeUnion
, Unsorted
);
1554 bool BlackboxWindow::setInputFocus(void) {
1555 if (flags
.focused
) return True
;
1557 assert(! flags
.iconic
&&
1558 (flags
.stuck
|| // window must be on the current workspace or sticky
1559 blackbox_attrib
.workspace
== screen
->getCurrentWorkspaceID()));
1561 // if the window is not visible, mark the window as wanting focus rather
1562 // than give it focus.
1563 if (! flags
.visible
) {
1564 Workspace
*wkspc
= screen
->getWorkspace(blackbox_attrib
.workspace
);
1565 wkspc
->setLastFocusedWindow(this);
1570 We only do this check for normal windows and dialogs because other windows
1571 do this on purpose, such as kde's kicker, and we don't want to go moving
1574 if (window_type
== Type_Normal
|| window_type
== Type_Dialog
)
1575 if (! frame
.rect
.intersects(screen
->getRect())) {
1576 // client is outside the screen, move it to the center
1577 configure((screen
->getWidth() - frame
.rect
.width()) / 2,
1578 (screen
->getHeight() - frame
.rect
.height()) / 2,
1579 frame
.rect
.width(), frame
.rect
.height());
1582 if (client
.transientList
.size() > 0) {
1583 // transfer focus to any modal transients
1584 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1585 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1586 if ((*it
)->flags
.modal
) return (*it
)->setInputFocus();
1591 if (focus_mode
== F_LocallyActive
|| focus_mode
== F_Passive
) {
1592 XSetInputFocus(blackbox
->getXDisplay(), client
.window
,
1593 RevertToPointerRoot
, CurrentTime
);
1595 blackbox
->setFocusedWindow(this);
1597 /* we could set the focus to none, since the window doesn't accept focus,
1598 * but we shouldn't set focus to nothing since this would surely make
1604 if (flags
.send_focus_message
) {
1606 ce
.xclient
.type
= ClientMessage
;
1607 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1608 ce
.xclient
.display
= blackbox
->getXDisplay();
1609 ce
.xclient
.window
= client
.window
;
1610 ce
.xclient
.format
= 32;
1611 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_take_focus
);
1612 ce
.xclient
.data
.l
[1] = blackbox
->getLastTime();
1613 ce
.xclient
.data
.l
[2] = 0l;
1614 ce
.xclient
.data
.l
[3] = 0l;
1615 ce
.xclient
.data
.l
[4] = 0l;
1616 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1618 XFlush(blackbox
->getXDisplay());
1625 void BlackboxWindow::iconify(void) {
1626 if (flags
.iconic
) return;
1628 // We don't need to worry about resizing because resizing always grabs the X
1629 // server. This should only ever happen if using opaque moving.
1633 if (windowmenu
) windowmenu
->hide();
1636 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1637 * we need to clear the event mask on client.window for a split second.
1638 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1639 * split second, leaving us with a ghost window... so, we need to do this
1640 * while the X server is grabbed
1642 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1643 StructureNotifyMask
;
1644 XGrabServer(blackbox
->getXDisplay());
1645 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1646 event_mask
& ~StructureNotifyMask
);
1647 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1648 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1649 XUngrabServer(blackbox
->getXDisplay());
1651 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1652 flags
.visible
= False
;
1653 flags
.iconic
= True
;
1655 setState(IconicState
);
1657 screen
->getWorkspace(blackbox_attrib
.workspace
)->removeWindow(this);
1659 if (isTransient()) {
1660 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1661 ! client
.transient_for
->flags
.iconic
) {
1662 // iconify our transient_for
1663 client
.transient_for
->iconify();
1667 screen
->addIcon(this);
1669 if (client
.transientList
.size() > 0) {
1670 // iconify all transients
1671 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1672 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1673 if (! (*it
)->flags
.iconic
) (*it
)->iconify();
1676 screen
->updateStackingList();
1680 void BlackboxWindow::show(void) {
1681 flags
.visible
= True
;
1682 flags
.iconic
= False
;
1684 current_state
= (flags
.shaded
) ? IconicState
: NormalState
;
1685 setState(current_state
);
1687 XMapWindow(blackbox
->getXDisplay(), client
.window
);
1688 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
1689 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
1694 XTranslateCoordinates(blackbox
->getXDisplay(), client
.window
,
1695 screen
->getRootWindow(),
1696 0, 0, &real_x
, &real_y
, &child
);
1697 fprintf(stderr
, "%s -- assumed: (%d, %d), real: (%d, %d)\n", getTitle(),
1698 client
.rect
.left(), client
.rect
.top(), real_x
, real_y
);
1699 assert(client
.rect
.left() == real_x
&& client
.rect
.top() == real_y
);
1704 void BlackboxWindow::deiconify(bool reassoc
, bool raise
) {
1705 if (flags
.iconic
|| reassoc
)
1706 screen
->reassociateWindow(this, BSENTINEL
, False
);
1707 else if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID())
1712 // reassociate and deiconify all transients
1713 if (reassoc
&& client
.transientList
.size() > 0) {
1714 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1715 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1716 (*it
)->deiconify(True
, False
);
1721 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1725 void BlackboxWindow::close(void) {
1727 ce
.xclient
.type
= ClientMessage
;
1728 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1729 ce
.xclient
.display
= blackbox
->getXDisplay();
1730 ce
.xclient
.window
= client
.window
;
1731 ce
.xclient
.format
= 32;
1732 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_delete_window
);
1733 ce
.xclient
.data
.l
[1] = CurrentTime
;
1734 ce
.xclient
.data
.l
[2] = 0l;
1735 ce
.xclient
.data
.l
[3] = 0l;
1736 ce
.xclient
.data
.l
[4] = 0l;
1737 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
, NoEventMask
, &ce
);
1738 XFlush(blackbox
->getXDisplay());
1742 void BlackboxWindow::withdraw(void) {
1743 // We don't need to worry about resizing because resizing always grabs the X
1744 // server. This should only ever happen if using opaque moving.
1748 flags
.visible
= False
;
1749 flags
.iconic
= False
;
1751 setState(current_state
);
1753 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1755 XGrabServer(blackbox
->getXDisplay());
1757 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1758 StructureNotifyMask
;
1759 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1760 event_mask
& ~StructureNotifyMask
);
1761 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1762 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1764 XUngrabServer(blackbox
->getXDisplay());
1766 if (windowmenu
) windowmenu
->hide();
1770 void BlackboxWindow::maximize(unsigned int button
) {
1771 // We don't need to worry about resizing because resizing always grabs the X
1772 // server. This should only ever happen if using opaque moving.
1776 // handle case where menu is open then the max button is used instead
1777 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
1779 if (flags
.maximized
) {
1780 flags
.maximized
= 0;
1782 blackbox_attrib
.flags
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1783 blackbox_attrib
.attrib
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1786 when a resize finishes, maximize(0) is called to clear any maximization
1787 flags currently set. Otherwise it still thinks it is maximized.
1788 so we do not need to call configure() because resizing will handle it
1790 if (! flags
.resizing
)
1791 configure(blackbox_attrib
.premax_x
, blackbox_attrib
.premax_y
,
1792 blackbox_attrib
.premax_w
, blackbox_attrib
.premax_h
);
1794 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
1795 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
1797 redrawAllButtons(); // in case it is not called in configure()
1798 setState(current_state
);
1802 blackbox_attrib
.premax_x
= frame
.rect
.x();
1803 blackbox_attrib
.premax_y
= frame
.rect
.y();
1804 blackbox_attrib
.premax_w
= frame
.rect
.width();
1805 // use client.rect so that clients can be restored even if shaded
1806 blackbox_attrib
.premax_h
=
1807 client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
;
1810 if (screen
->isXineramaActive() && blackbox
->doXineramaMaximizing()) {
1811 // find the area to use
1812 RectList availableAreas
= screen
->allAvailableAreas();
1813 RectList::iterator it
, end
= availableAreas
.end();
1815 for (it
= availableAreas
.begin(); it
!= end
; ++it
)
1816 if (it
->intersects(frame
.rect
)) break;
1817 if (it
== end
) // the window isn't inside an area
1818 it
= availableAreas
.begin(); // so just default to the first one
1820 frame
.changing
= *it
;
1823 frame
.changing
= screen
->availableArea();
1827 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1828 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1832 blackbox_attrib
.flags
|= AttribMaxVert
;
1833 blackbox_attrib
.attrib
|= AttribMaxVert
;
1835 frame
.changing
.setX(frame
.rect
.x());
1836 frame
.changing
.setWidth(frame
.rect
.width());
1840 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1841 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1843 frame
.changing
.setY(frame
.rect
.y());
1844 frame
.changing
.setHeight(frame
.rect
.height());
1851 blackbox_attrib
.flags
^= AttribShaded
;
1852 blackbox_attrib
.attrib
^= AttribShaded
;
1853 flags
.shaded
= False
;
1856 flags
.maximized
= button
;
1858 configure(frame
.changing
.x(), frame
.changing
.y(),
1859 frame
.changing
.width(), frame
.changing
.height());
1861 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1862 redrawAllButtons(); // in case it is not called in configure()
1863 setState(current_state
);
1867 // re-maximizes the window to take into account availableArea changes
1868 void BlackboxWindow::remaximize(void) {
1869 // save the original dimensions because maximize will wipe them out
1870 int premax_x
= blackbox_attrib
.premax_x
,
1871 premax_y
= blackbox_attrib
.premax_y
,
1872 premax_w
= blackbox_attrib
.premax_w
,
1873 premax_h
= blackbox_attrib
.premax_h
;
1875 unsigned int button
= flags
.maximized
;
1876 flags
.maximized
= 0; // trick maximize() into working
1879 // restore saved values
1880 blackbox_attrib
.premax_x
= premax_x
;
1881 blackbox_attrib
.premax_y
= premax_y
;
1882 blackbox_attrib
.premax_w
= premax_w
;
1883 blackbox_attrib
.premax_h
= premax_h
;
1887 void BlackboxWindow::setWorkspace(unsigned int n
) {
1888 blackbox_attrib
.flags
|= AttribWorkspace
;
1889 blackbox_attrib
.workspace
= n
;
1890 if (n
== BSENTINEL
) { // iconified window
1892 we set the workspace to 'all workspaces' so that taskbars will show the
1893 window. otherwise, it made uniconifying a window imposible without the
1894 blackbox workspace menu
1898 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
, n
);
1902 void BlackboxWindow::shade(void) {
1904 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1905 frame
.inside_w
, frame
.inside_h
);
1906 flags
.shaded
= False
;
1907 blackbox_attrib
.flags
^= AttribShaded
;
1908 blackbox_attrib
.attrib
^= AttribShaded
;
1910 setState(NormalState
);
1912 // set the frame rect to the normal size
1913 frame
.rect
.setHeight(client
.rect
.height() + frame
.margin
.top
+
1914 frame
.margin
.bottom
);
1916 if (! (decorations
& Decor_Titlebar
))
1917 return; // can't shade it without a titlebar!
1919 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1920 frame
.inside_w
, frame
.title_h
);
1921 flags
.shaded
= True
;
1922 blackbox_attrib
.flags
|= AttribShaded
;
1923 blackbox_attrib
.attrib
|= AttribShaded
;
1925 setState(IconicState
);
1927 // set the frame rect to the shaded size
1928 frame
.rect
.setHeight(frame
.title_h
+ (frame
.border_w
* 2));
1934 * (Un)Sticks a window and its relatives.
1936 void BlackboxWindow::stick(void) {
1938 blackbox_attrib
.flags
^= AttribOmnipresent
;
1939 blackbox_attrib
.attrib
^= AttribOmnipresent
;
1941 flags
.stuck
= False
;
1944 screen
->reassociateWindow(this, BSENTINEL
, True
);
1945 // temporary fix since sticky windows suck. set the hint to what we
1946 // actually hold in our data.
1947 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1948 blackbox_attrib
.workspace
);
1950 setState(current_state
);
1954 blackbox_attrib
.flags
|= AttribOmnipresent
;
1955 blackbox_attrib
.attrib
|= AttribOmnipresent
;
1957 // temporary fix since sticky windows suck. set the hint to a different
1958 // value than that contained in the class' data.
1959 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1962 setState(current_state
);
1965 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1966 client
.transient_for
->isStuck() != flags
.stuck
)
1967 client
.transient_for
->stick();
1968 // go down the chain
1969 BlackboxWindowList::iterator it
;
1970 const BlackboxWindowList::iterator end
= client
.transientList
.end();
1971 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1972 if ((*it
)->isStuck() != flags
.stuck
)
1977 void BlackboxWindow::redrawWindowFrame(void) const {
1978 if (decorations
& Decor_Titlebar
) {
1979 if (flags
.focused
) {
1981 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1982 frame
.title
, frame
.ftitle
);
1984 XSetWindowBackground(blackbox
->getXDisplay(),
1985 frame
.title
, frame
.ftitle_pixel
);
1988 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1989 frame
.title
, frame
.utitle
);
1991 XSetWindowBackground(blackbox
->getXDisplay(),
1992 frame
.title
, frame
.utitle_pixel
);
1994 XClearWindow(blackbox
->getXDisplay(), frame
.title
);
2000 if (decorations
& Decor_Handle
) {
2001 if (flags
.focused
) {
2003 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2004 frame
.handle
, frame
.fhandle
);
2006 XSetWindowBackground(blackbox
->getXDisplay(),
2007 frame
.handle
, frame
.fhandle_pixel
);
2010 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2011 frame
.left_grip
, frame
.fgrip
);
2012 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2013 frame
.right_grip
, frame
.fgrip
);
2015 XSetWindowBackground(blackbox
->getXDisplay(),
2016 frame
.left_grip
, frame
.fgrip_pixel
);
2017 XSetWindowBackground(blackbox
->getXDisplay(),
2018 frame
.right_grip
, frame
.fgrip_pixel
);
2022 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2023 frame
.handle
, frame
.uhandle
);
2025 XSetWindowBackground(blackbox
->getXDisplay(),
2026 frame
.handle
, frame
.uhandle_pixel
);
2029 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2030 frame
.left_grip
, frame
.ugrip
);
2031 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2032 frame
.right_grip
, frame
.ugrip
);
2034 XSetWindowBackground(blackbox
->getXDisplay(),
2035 frame
.left_grip
, frame
.ugrip_pixel
);
2036 XSetWindowBackground(blackbox
->getXDisplay(),
2037 frame
.right_grip
, frame
.ugrip_pixel
);
2040 XClearWindow(blackbox
->getXDisplay(), frame
.handle
);
2041 XClearWindow(blackbox
->getXDisplay(), frame
.left_grip
);
2042 XClearWindow(blackbox
->getXDisplay(), frame
.right_grip
);
2045 if (decorations
& Decor_Border
) {
2047 XSetWindowBorder(blackbox
->getXDisplay(),
2048 frame
.plate
, frame
.fborder_pixel
);
2050 XSetWindowBorder(blackbox
->getXDisplay(),
2051 frame
.plate
, frame
.uborder_pixel
);
2056 void BlackboxWindow::setFocusFlag(bool focus
) {
2057 // only focus a window if it is visible
2058 if (focus
&& !flags
.visible
)
2061 flags
.focused
= focus
;
2063 redrawWindowFrame();
2065 if (screen
->isSloppyFocus() && screen
->doAutoRaise()) {
2066 if (isFocused()) timer
->start();
2071 blackbox
->setFocusedWindow(this);
2073 Clientmenu
*menu
= screen
->getWorkspace(blackbox_attrib
.workspace
)->getMenu();
2074 menu
->setItemSelected(window_number
, isFocused());
2078 void BlackboxWindow::installColormap(bool install
) {
2079 int i
= 0, ncmap
= 0;
2080 Colormap
*cmaps
= XListInstalledColormaps(blackbox
->getXDisplay(),
2081 client
.window
, &ncmap
);
2083 XWindowAttributes wattrib
;
2084 if (XGetWindowAttributes(blackbox
->getXDisplay(),
2085 client
.window
, &wattrib
)) {
2087 // install the window's colormap
2088 for (i
= 0; i
< ncmap
; i
++) {
2089 if (*(cmaps
+ i
) == wattrib
.colormap
)
2090 // this window is using an installed color map... do not install
2093 // otherwise, install the window's colormap
2095 XInstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2097 // uninstall the window's colormap
2098 for (i
= 0; i
< ncmap
; i
++) {
2099 if (*(cmaps
+ i
) == wattrib
.colormap
)
2100 // we found the colormap to uninstall
2101 XUninstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2111 void BlackboxWindow::setAllowedActions(void) {
2115 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_shade
);
2116 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_change_desktop
);
2117 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_close
);
2119 if (functions
& Func_Move
)
2120 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_move
);
2121 if (functions
& Func_Resize
)
2122 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_resize
);
2123 if (functions
& Func_Maximize
) {
2124 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_horz
);
2125 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_vert
);
2128 xatom
->setValue(client
.window
, XAtom::net_wm_allowed_actions
, XAtom::atom
,
2133 void BlackboxWindow::setState(unsigned long new_state
) {
2134 current_state
= new_state
;
2136 unsigned long state
[2];
2137 state
[0] = current_state
;
2139 xatom
->setValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
, state
, 2);
2141 xatom
->setValue(client
.window
, XAtom::blackbox_attributes
,
2142 XAtom::blackbox_attributes
, (unsigned long *)&blackbox_attrib
,
2143 PropBlackboxAttributesElements
);
2148 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_modal
);
2150 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_shaded
);
2152 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_hidden
);
2153 if (flags
.skip_taskbar
)
2154 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
);
2155 if (flags
.skip_pager
)
2156 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_pager
);
2157 if (flags
.fullscreen
)
2158 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_fullscreen
);
2159 if (flags
.maximized
== 1 || flags
.maximized
== 2)
2160 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_vert
);
2161 if (flags
.maximized
== 1 || flags
.maximized
== 3)
2162 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_horz
);
2163 xatom
->setValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
2168 bool BlackboxWindow::getState(void) {
2169 bool ret
= xatom
->getValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
,
2171 if (! ret
) current_state
= 0;
2176 void BlackboxWindow::restoreAttributes(void) {
2177 unsigned long num
= PropBlackboxAttributesElements
;
2178 BlackboxAttributes
*net
;
2179 if (! xatom
->getValue(client
.window
, XAtom::blackbox_attributes
,
2180 XAtom::blackbox_attributes
, num
,
2181 (unsigned long **)&net
))
2183 if (num
< PropBlackboxAttributesElements
) {
2188 if (net
->flags
& AttribShaded
&& net
->attrib
& AttribShaded
) {
2189 flags
.shaded
= False
;
2190 unsigned long orig_state
= current_state
;
2194 At this point in the life of a window, current_state should only be set
2195 to IconicState if the window was an *icon*, not if it was shaded.
2197 if (orig_state
!= IconicState
)
2198 current_state
= WithdrawnState
;
2201 if (net
->workspace
!= screen
->getCurrentWorkspaceID() &&
2202 net
->workspace
< screen
->getWorkspaceCount())
2203 screen
->reassociateWindow(this, net
->workspace
, True
);
2205 if ((blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID()) &&
2206 (blackbox_attrib
.workspace
< screen
->getWorkspaceCount())) {
2207 // set to WithdrawnState so it will be mapped on the new workspace
2208 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2209 } else if (current_state
== WithdrawnState
) {
2210 // the window is on this workspace and is Withdrawn, so it is waiting to
2212 current_state
= NormalState
;
2215 if (net
->flags
& AttribOmnipresent
&& net
->attrib
& AttribOmnipresent
) {
2216 flags
.stuck
= False
;
2219 // if the window was on another workspace, it was going to be hidden. this
2220 // specifies that the window should be mapped since it is sticky.
2221 if (current_state
== WithdrawnState
) current_state
= NormalState
;
2224 if (net
->flags
& AttribMaxHoriz
|| net
->flags
& AttribMaxVert
) {
2225 int x
= net
->premax_x
, y
= net
->premax_y
;
2226 unsigned int w
= net
->premax_w
, h
= net
->premax_h
;
2227 flags
.maximized
= 0;
2230 if ((net
->flags
& AttribMaxHoriz
) &&
2231 (net
->flags
& AttribMaxVert
))
2232 m
= (net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
2233 else if (net
->flags
& AttribMaxVert
)
2234 m
= (net
->attrib
& AttribMaxVert
) ? 2 : 0;
2235 else if (net
->flags
& AttribMaxHoriz
)
2236 m
= (net
->attrib
& AttribMaxHoriz
) ? 3 : 0;
2240 blackbox_attrib
.premax_x
= x
;
2241 blackbox_attrib
.premax_y
= y
;
2242 blackbox_attrib
.premax_w
= w
;
2243 blackbox_attrib
.premax_h
= h
;
2246 // with the state set it will then be the map event's job to read the
2247 // window's state and behave accordingly
2254 * Positions the Rect r according the the client window position and
2257 void BlackboxWindow::applyGravity(Rect
&r
) {
2258 // apply horizontal window gravity
2259 switch (client
.win_gravity
) {
2261 case NorthWestGravity
:
2262 case SouthWestGravity
:
2264 r
.setX(client
.rect
.x());
2270 r
.setX(client
.rect
.x() - (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2273 case NorthEastGravity
:
2274 case SouthEastGravity
:
2276 r
.setX(client
.rect
.x() - frame
.margin
.left
- frame
.margin
.right
+ 2);
2281 r
.setX(client
.rect
.x() - frame
.margin
.left
);
2285 // apply vertical window gravity
2286 switch (client
.win_gravity
) {
2288 case NorthWestGravity
:
2289 case NorthEastGravity
:
2291 r
.setY(client
.rect
.y());
2297 r
.setY(client
.rect
.y() - (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2300 case SouthWestGravity
:
2301 case SouthEastGravity
:
2303 r
.setY(client
.rect
.y() - frame
.margin
.top
- frame
.margin
.bottom
+ 2);
2308 r
.setY(client
.rect
.y() - frame
.margin
.top
);
2315 * The reverse of the applyGravity function.
2317 * Positions the Rect r according to the frame window position and
2320 void BlackboxWindow::restoreGravity(Rect
&r
) {
2321 // restore horizontal window gravity
2322 switch (client
.win_gravity
) {
2324 case NorthWestGravity
:
2325 case SouthWestGravity
:
2327 r
.setX(frame
.rect
.x());
2333 r
.setX(frame
.rect
.x() + (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2336 case NorthEastGravity
:
2337 case SouthEastGravity
:
2339 r
.setX(frame
.rect
.x() + frame
.margin
.left
+ frame
.margin
.right
- 2);
2344 r
.setX(frame
.rect
.x() + frame
.margin
.left
);
2348 // restore vertical window gravity
2349 switch (client
.win_gravity
) {
2351 case NorthWestGravity
:
2352 case NorthEastGravity
:
2354 r
.setY(frame
.rect
.y());
2360 r
.setY(frame
.rect
.y() + (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2363 case SouthWestGravity
:
2364 case SouthEastGravity
:
2366 r
.setY(frame
.rect
.y() + frame
.margin
.top
+ frame
.margin
.bottom
- 2);
2371 r
.setY(frame
.rect
.y() + frame
.margin
.top
);
2377 void BlackboxWindow::redrawLabel(void) const {
2378 if (flags
.focused
) {
2380 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2381 frame
.label
, frame
.flabel
);
2383 XSetWindowBackground(blackbox
->getXDisplay(),
2384 frame
.label
, frame
.flabel_pixel
);
2387 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2388 frame
.label
, frame
.ulabel
);
2390 XSetWindowBackground(blackbox
->getXDisplay(),
2391 frame
.label
, frame
.ulabel_pixel
);
2393 XClearWindow(blackbox
->getXDisplay(), frame
.label
);
2395 WindowStyle
*style
= screen
->getWindowStyle();
2397 int pos
= frame
.bevel_w
* 2;
2398 style
->doJustify(client
.title
.c_str(), pos
, frame
.label_w
, frame
.bevel_w
* 4);
2399 style
->font
->drawString(frame
.label
, pos
, 1,
2400 (flags
.focused
? style
->l_text_focus
:
2401 style
->l_text_unfocus
),
2406 void BlackboxWindow::redrawAllButtons(void) const {
2407 if (frame
.iconify_button
) redrawIconifyButton(False
);
2408 if (frame
.maximize_button
) redrawMaximizeButton(flags
.maximized
);
2409 if (frame
.close_button
) redrawCloseButton(False
);
2413 void BlackboxWindow::redrawIconifyButton(bool pressed
) const {
2415 if (flags
.focused
) {
2417 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2418 frame
.iconify_button
, frame
.fbutton
);
2420 XSetWindowBackground(blackbox
->getXDisplay(),
2421 frame
.iconify_button
, frame
.fbutton_pixel
);
2424 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2425 frame
.iconify_button
, frame
.ubutton
);
2427 XSetWindowBackground(blackbox
->getXDisplay(), frame
.iconify_button
,
2428 frame
.ubutton_pixel
);
2432 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2433 frame
.iconify_button
, frame
.pbutton
);
2435 XSetWindowBackground(blackbox
->getXDisplay(),
2436 frame
.iconify_button
, frame
.pbutton_pixel
);
2438 XClearWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
2440 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2441 screen
->getWindowStyle()->b_pic_unfocus
);
2442 XDrawRectangle(blackbox
->getXDisplay(), frame
.iconify_button
, pen
.gc(),
2443 2, (frame
.button_w
- 5), (frame
.button_w
- 5), 2);
2447 void BlackboxWindow::redrawMaximizeButton(bool pressed
) const {
2449 if (flags
.focused
) {
2451 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2452 frame
.maximize_button
, frame
.fbutton
);
2454 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2455 frame
.fbutton_pixel
);
2458 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2459 frame
.maximize_button
, frame
.ubutton
);
2461 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2462 frame
.ubutton_pixel
);
2466 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2467 frame
.maximize_button
, frame
.pbutton
);
2469 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2470 frame
.pbutton_pixel
);
2472 XClearWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
2474 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2475 screen
->getWindowStyle()->b_pic_unfocus
);
2476 XDrawRectangle(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2477 2, 2, (frame
.button_w
- 5), (frame
.button_w
- 5));
2478 XDrawLine(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2479 2, 3, (frame
.button_w
- 3), 3);
2483 void BlackboxWindow::redrawCloseButton(bool pressed
) const {
2485 if (flags
.focused
) {
2487 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2490 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2491 frame
.fbutton_pixel
);
2494 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2497 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2498 frame
.ubutton_pixel
);
2502 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2503 frame
.close_button
, frame
.pbutton
);
2505 XSetWindowBackground(blackbox
->getXDisplay(),
2506 frame
.close_button
, frame
.pbutton_pixel
);
2508 XClearWindow(blackbox
->getXDisplay(), frame
.close_button
);
2510 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2511 screen
->getWindowStyle()->b_pic_unfocus
);
2512 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2513 2, 2, (frame
.button_w
- 3), (frame
.button_w
- 3));
2514 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2515 2, (frame
.button_w
- 3), (frame
.button_w
- 3), 2);
2519 void BlackboxWindow::mapRequestEvent(const XMapRequestEvent
*re
) {
2520 if (re
->window
!= client
.window
)
2524 fprintf(stderr
, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2528 switch (current_state
) {
2533 case WithdrawnState
:
2542 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2544 if (! blackbox
->isStartup()) {
2545 XSync(blackbox
->getXDisplay(), False
); // make sure the frame is mapped
2546 if (screen
->doFocusNew()|| (isTransient() && getTransientFor() &&
2547 getTransientFor()->isFocused())) {
2550 if (screen
->getPlacementPolicy() == BScreen::ClickMousePlacement
) {
2554 XQueryPointer(blackbox
->getXDisplay(), screen
->getRootWindow(),
2555 &r
, &c
, &rx
, &ry
, &x
, &y
, &m
);
2565 void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent
*ue
) {
2566 if (ue
->window
!= client
.window
)
2570 fprintf(stderr
, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2574 screen
->unmanageWindow(this, False
);
2578 void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent
*de
) {
2579 if (de
->window
!= client
.window
)
2583 fprintf(stderr
, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2587 screen
->unmanageWindow(this, False
);
2591 void BlackboxWindow::reparentNotifyEvent(const XReparentEvent
*re
) {
2592 if (re
->window
!= client
.window
|| re
->parent
== frame
.plate
)
2596 fprintf(stderr
, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2597 "0x%lx.\n", client
.window
, re
->parent
);
2602 XPutBackEvent(blackbox
->getXDisplay(), &ev
);
2603 screen
->unmanageWindow(this, True
);
2607 void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent
*pe
) {
2608 if (pe
->state
== PropertyDelete
)
2612 fprintf(stderr
, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n",
2618 case XA_WM_CLIENT_MACHINE
:
2622 case XA_WM_TRANSIENT_FOR
: {
2623 // determine if this is a transient window
2626 // adjust the window decorations based on transience
2627 if (isTransient()) {
2628 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2629 functions
&= ~Func_Maximize
;
2630 setAllowedActions();
2641 case XA_WM_ICON_NAME
:
2643 if (flags
.iconic
) screen
->propagateWindowName(this);
2646 case XAtom::net_wm_name
:
2650 if (decorations
& Decor_Titlebar
)
2653 screen
->propagateWindowName(this);
2656 case XA_WM_NORMAL_HINTS
: {
2659 if ((client
.normal_hint_flags
& PMinSize
) &&
2660 (client
.normal_hint_flags
& PMaxSize
)) {
2661 // the window now can/can't resize itself, so the buttons need to be
2664 if (client
.max_width
<= client
.min_width
&&
2665 client
.max_height
<= client
.min_height
) {
2666 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2667 functions
&= ~(Func_Resize
| Func_Maximize
);
2669 if (! isTransient()) {
2670 decorations
|= Decor_Maximize
| Decor_Handle
;
2671 functions
|= Func_Maximize
;
2673 functions
|= Func_Resize
;
2676 setAllowedActions();
2679 Rect old_rect
= frame
.rect
;
2683 if (old_rect
!= frame
.rect
)
2690 if (pe
->atom
== xatom
->getAtom(XAtom::wm_protocols
)) {
2693 if ((decorations
& Decor_Close
) && (! frame
.close_button
)) {
2694 createCloseButton();
2695 if (decorations
& Decor_Titlebar
) {
2696 positionButtons(True
);
2697 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
2699 if (windowmenu
) windowmenu
->reconfigure();
2701 } else if (pe
->atom
== xatom
->getAtom(XAtom::net_wm_strut
)) {
2710 void BlackboxWindow::exposeEvent(const XExposeEvent
*ee
) {
2712 fprintf(stderr
, "BlackboxWindow::exposeEvent() for 0x%lx\n", client
.window
);
2715 if (frame
.label
== ee
->window
&& (decorations
& Decor_Titlebar
))
2717 else if (frame
.close_button
== ee
->window
)
2718 redrawCloseButton(False
);
2719 else if (frame
.maximize_button
== ee
->window
)
2720 redrawMaximizeButton(flags
.maximized
);
2721 else if (frame
.iconify_button
== ee
->window
)
2722 redrawIconifyButton(False
);
2726 void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent
*cr
) {
2727 if (cr
->window
!= client
.window
|| flags
.iconic
)
2730 if (cr
->value_mask
& CWBorderWidth
)
2731 client
.old_bw
= cr
->border_width
;
2733 if (cr
->value_mask
& (CWX
| CWY
| CWWidth
| CWHeight
)) {
2734 Rect req
= frame
.rect
;
2736 if (cr
->value_mask
& (CWX
| CWY
)) {
2737 if (cr
->value_mask
& CWX
)
2738 client
.rect
.setX(cr
->x
);
2739 if (cr
->value_mask
& CWY
)
2740 client
.rect
.setY(cr
->y
);
2745 if (cr
->value_mask
& CWWidth
)
2746 req
.setWidth(cr
->width
+ frame
.margin
.left
+ frame
.margin
.right
);
2748 if (cr
->value_mask
& CWHeight
)
2749 req
.setHeight(cr
->height
+ frame
.margin
.top
+ frame
.margin
.bottom
);
2751 configure(req
.x(), req
.y(), req
.width(), req
.height());
2754 if (cr
->value_mask
& CWStackMode
&& !isDesktop()) {
2755 switch (cr
->detail
) {
2758 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2764 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2771 void BlackboxWindow::buttonPressEvent(const XButtonEvent
*be
) {
2773 fprintf(stderr
, "BlackboxWindow::buttonPressEvent() for 0x%lx\n",
2777 if (frame
.maximize_button
== be
->window
&& be
->button
<= 3) {
2778 redrawMaximizeButton(True
);
2779 } else if (be
->button
== 1 || (be
->button
== 3 && be
->state
== ModMask
)) {
2780 if (! flags
.focused
)
2783 if (frame
.iconify_button
== be
->window
) {
2784 redrawIconifyButton(True
);
2785 } else if (frame
.close_button
== be
->window
) {
2786 redrawCloseButton(True
);
2787 } else if (frame
.plate
== be
->window
) {
2788 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2790 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2792 XAllowEvents(blackbox
->getXDisplay(), ReplayPointer
, be
->time
);
2794 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
2795 if (((be
->time
- lastButtonPressTime
) <=
2796 blackbox
->getDoubleClickInterval()) ||
2797 (be
->state
== ControlMask
)) {
2798 lastButtonPressTime
= 0;
2801 lastButtonPressTime
= be
->time
;
2805 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2807 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2809 } else if (be
->button
== 2 && (be
->window
!= frame
.iconify_button
) &&
2810 (be
->window
!= frame
.close_button
)) {
2811 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2812 } else if (windowmenu
&& be
->button
== 3 &&
2813 (frame
.title
== be
->window
|| frame
.label
== be
->window
||
2814 frame
.handle
== be
->window
|| frame
.window
== be
->window
)) {
2815 if (windowmenu
->isVisible()) {
2818 int mx
= be
->x_root
- windowmenu
->getWidth() / 2,
2819 my
= be
->y_root
- windowmenu
->getHeight() / 2;
2821 // snap the window menu into a corner/side if necessary
2822 int left_edge
, right_edge
, top_edge
, bottom_edge
;
2825 the " + (frame.border_w * 2) - 1" bits are to get the proper width
2826 and height of the menu, as the sizes returned by it do not include
2829 left_edge
= frame
.rect
.x();
2830 right_edge
= frame
.rect
.right() -
2831 (windowmenu
->getWidth() + (frame
.border_w
* 2) - 1);
2832 top_edge
= client
.rect
.top() - (frame
.border_w
+ frame
.mwm_border_w
);
2833 bottom_edge
= client
.rect
.bottom() -
2834 (windowmenu
->getHeight() + (frame
.border_w
* 2) - 1) +
2835 (frame
.border_w
+ frame
.mwm_border_w
);
2839 if (mx
> right_edge
)
2843 if (my
> bottom_edge
)
2846 windowmenu
->move(mx
, my
);
2848 XRaiseWindow(blackbox
->getXDisplay(), windowmenu
->getWindowID());
2849 XRaiseWindow(blackbox
->getXDisplay(),
2850 windowmenu
->getSendToMenu()->getWindowID());
2853 } else if (be
->button
== 4) {
2854 if ((be
->window
== frame
.label
||
2855 be
->window
== frame
.title
||
2856 be
->window
== frame
.maximize_button
||
2857 be
->window
== frame
.iconify_button
||
2858 be
->window
== frame
.close_button
) &&
2862 } else if (be
->button
== 5) {
2863 if ((be
->window
== frame
.label
||
2864 be
->window
== frame
.title
||
2865 be
->window
== frame
.maximize_button
||
2866 be
->window
== frame
.iconify_button
||
2867 be
->window
== frame
.close_button
) &&
2874 void BlackboxWindow::buttonReleaseEvent(const XButtonEvent
*re
) {
2876 fprintf(stderr
, "BlackboxWindow::buttonReleaseEvent() for 0x%lx\n",
2880 if (re
->window
== frame
.maximize_button
&&
2881 re
->button
>= 1 && re
->button
<= 3) {
2882 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2883 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2884 maximize(re
->button
);
2886 redrawMaximizeButton(flags
.maximized
);
2888 } else if (re
->window
== frame
.iconify_button
&& re
->button
== 1) {
2889 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2890 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2893 redrawIconifyButton(False
);
2895 } else if (re
->window
== frame
.close_button
& re
->button
== 1) {
2896 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2897 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
)))
2899 redrawCloseButton(False
);
2900 } else if (flags
.moving
) {
2902 } else if (flags
.resizing
) {
2904 } else if (re
->window
== frame
.window
) {
2905 if (re
->button
== 2 && re
->state
== ModMask
)
2906 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
2912 void BlackboxWindow::beginMove(int x_root
, int y_root
) {
2913 assert(! (flags
.resizing
|| flags
.moving
));
2916 Only one window can be moved/resized at a time. If another window is already
2917 being moved or resized, then stop it before whating to work with this one.
2919 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
2920 if (changing
&& changing
!= this) {
2921 if (changing
->flags
.moving
)
2922 changing
->endMove();
2923 else // if (changing->flags.resizing)
2924 changing
->endResize();
2927 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
2928 PointerMotionMask
| ButtonReleaseMask
,
2929 GrabModeAsync
, GrabModeAsync
,
2930 None
, blackbox
->getMoveCursor(), CurrentTime
);
2932 if (windowmenu
&& windowmenu
->isVisible())
2935 flags
.moving
= True
;
2936 blackbox
->setChangingWindow(this);
2938 if (! screen
->doOpaqueMove()) {
2939 XGrabServer(blackbox
->getXDisplay());
2941 frame
.changing
= frame
.rect
;
2942 screen
->showPosition(frame
.changing
.x(), frame
.changing
.y());
2944 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2948 frame
.changing
.width() - 1,
2949 frame
.changing
.height() - 1);
2952 frame
.grab_x
= x_root
- frame
.rect
.x() - frame
.border_w
;
2953 frame
.grab_y
= y_root
- frame
.rect
.y() - frame
.border_w
;
2957 void BlackboxWindow::doMove(int x_root
, int y_root
) {
2958 assert(flags
.moving
);
2959 assert(blackbox
->getChangingWindow() == this);
2961 int dx
= x_root
- frame
.grab_x
, dy
= y_root
- frame
.grab_y
;
2962 dx
-= frame
.border_w
;
2963 dy
-= frame
.border_w
;
2965 if (screen
->doWorkspaceWarping()) {
2966 // workspace warping
2968 unsigned int dest
= screen
->getCurrentWorkspaceID();
2972 if (dest
> 0) dest
--;
2973 else dest
= screen
->getNumberOfWorkspaces() - 1;
2975 } else if (x_root
>= screen
->getRect().right()) {
2978 if (dest
< screen
->getNumberOfWorkspaces() - 1) dest
++;
2983 bool focus
= flags
.focused
; // had focus while moving?
2985 screen
->reassociateWindow(this, dest
, False
);
2986 screen
->changeWorkspaceID(dest
);
2991 If the XWarpPointer is done after the configure, we can end up
2992 grabbing another window, so made sure you do it first.
2996 dest_x
= screen
->getRect().right() - 1;
2997 XWarpPointer(blackbox
->getXDisplay(), None
,
2998 screen
->getRootWindow(), 0, 0, 0, 0,
3001 configure(dx
+ (screen
->getRect().width() - 1), dy
,
3002 frame
.rect
.width(), frame
.rect
.height());
3005 XWarpPointer(blackbox
->getXDisplay(), None
,
3006 screen
->getRootWindow(), 0, 0, 0, 0,
3009 configure(dx
- (screen
->getRect().width() - 1), dy
,
3010 frame
.rect
.width(), frame
.rect
.height());
3013 beginMove(dest_x
, y_root
);
3018 const int snap_distance
= screen
->getEdgeSnapThreshold();
3020 if (snap_distance
) {
3022 const int wleft
= dx
,
3023 wright
= dx
+ frame
.rect
.width() - 1,
3025 wbottom
= dy
+ frame
.rect
.height() - 1;
3027 if (screen
->getWindowToWindowSnap()) {
3028 Workspace
*w
= screen
->getWorkspace(getWorkspaceNumber());
3031 // try snap to another window
3032 for (unsigned int i
= 0, c
= w
->getCount(); i
< c
; ++i
) {
3033 BlackboxWindow
*snapwin
= w
->getWindow(i
);
3034 if (snapwin
== this)
3035 continue; // don't snap to self
3037 bool snapped
= False
;
3039 const Rect
&winrect
= snapwin
->frameRect();
3040 int dleft
= std::abs(wright
- winrect
.left()),
3041 dright
= std::abs(wleft
- winrect
.right()),
3042 dtop
= std::abs(wbottom
- winrect
.top()),
3043 dbottom
= std::abs(wtop
- winrect
.bottom());
3045 if (wtop
>= (signed)(winrect
.y() - frame
.rect
.height() + 1) &&
3046 wtop
< (signed)(winrect
.y() + winrect
.height() - 1)) {
3048 // snap left of other window?
3049 if (dleft
< snap_distance
&& dleft
<= dright
) {
3050 dx
= winrect
.left() - frame
.rect
.width();
3053 // snap right of other window?
3054 else if (dright
< snap_distance
) {
3055 dx
= winrect
.right() + 1;
3060 if (screen
->getWindowCornerSnap()) {
3061 // try corner-snap to its other sides
3062 dtop
= std::abs(wtop
- winrect
.top());
3063 dbottom
= std::abs(wbottom
- winrect
.bottom());
3064 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3066 else if (dbottom
< snap_distance
)
3067 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
3074 if (wleft
>= (signed)(winrect
.x() - frame
.rect
.width() + 1) &&
3075 wleft
< (signed)(winrect
.x() + winrect
.width() - 1)) {
3077 // snap top of other window?
3078 if (dtop
< snap_distance
&& dtop
<= dbottom
) {
3079 dy
= winrect
.top() - frame
.rect
.height();
3082 // snap bottom of other window?
3083 else if (dbottom
< snap_distance
) {
3084 dy
= winrect
.bottom() + 1;
3089 if (screen
->getWindowCornerSnap()) {
3090 // try corner-snap to its other sides
3091 dleft
= std::abs(wleft
- winrect
.left());
3092 dright
= std::abs(wright
- winrect
.right());
3093 if (dleft
< snap_distance
&& dleft
<= dright
)
3094 dx
= winrect
.left();
3095 else if (dright
< snap_distance
)
3096 dx
= winrect
.right() - frame
.rect
.width() + 1;
3105 RectList snaplist
; // the list of rects we will try to snap to
3107 // snap to the strut (and screen boundaries for xinerama)
3109 if (screen
->isXineramaActive() && blackbox
->doXineramaSnapping()) {
3110 if (! screen
->doFullMax())
3111 snaplist
.insert(snaplist
.begin(),
3112 screen
->allAvailableAreas().begin(),
3113 screen
->allAvailableAreas().end());
3115 // always snap to the screen edges
3116 snaplist
.insert(snaplist
.begin(),
3117 screen
->getXineramaAreas().begin(),
3118 screen
->getXineramaAreas().end());
3122 if (! screen
->doFullMax())
3123 snaplist
.push_back(screen
->availableArea());
3125 // always snap to the screen edges
3126 snaplist
.push_back(screen
->getRect());
3129 RectList::const_iterator it
, end
= snaplist
.end();
3130 for (it
= snaplist
.begin(); it
!= end
; ++it
) {
3131 const Rect
&srect
= *it
;
3133 // if we're not in the rectangle then don't snap to it.
3134 if (! srect
.intersects(Rect(wleft
, wtop
, frame
.rect
.width(),
3135 frame
.rect
.height())))
3138 int dleft
= std::abs(wleft
- srect
.left()),
3139 dright
= std::abs(wright
- srect
.right()),
3140 dtop
= std::abs(wtop
- srect
.top()),
3141 dbottom
= std::abs(wbottom
- srect
.bottom());
3144 if (dleft
< snap_distance
&& dleft
<= dright
)
3147 else if (dright
< snap_distance
)
3148 dx
= srect
.right() - frame
.rect
.width() + 1;
3151 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3154 else if (dbottom
< snap_distance
)
3155 dy
= srect
.bottom() - frame
.rect
.height() + 1;
3159 if (screen
->doOpaqueMove()) {
3160 configure(dx
, dy
, frame
.rect
.width(), frame
.rect
.height());
3162 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3166 frame
.changing
.width() - 1,
3167 frame
.changing
.height() - 1);
3169 frame
.changing
.setPos(dx
, dy
);
3171 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3175 frame
.changing
.width() - 1,
3176 frame
.changing
.height() - 1);
3179 screen
->showPosition(dx
, dy
);
3183 void BlackboxWindow::endMove(void) {
3184 assert(flags
.moving
);
3185 assert(blackbox
->getChangingWindow() == this);
3187 flags
.moving
= False
;
3188 blackbox
->setChangingWindow(0);
3190 if (! screen
->doOpaqueMove()) {
3191 /* when drawing the rubber band, we need to make sure we only draw inside
3192 * the frame... frame.changing_* contain the new coords for the window,
3193 * so we need to subtract 1 from changing_w/changing_h every where we
3194 * draw the rubber band (for both moving and resizing)
3196 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3197 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3198 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3199 XUngrabServer(blackbox
->getXDisplay());
3201 configure(frame
.changing
.x(), frame
.changing
.y(),
3202 frame
.changing
.width(), frame
.changing
.height());
3204 configure(frame
.rect
.x(), frame
.rect
.y(),
3205 frame
.rect
.width(), frame
.rect
.height());
3207 screen
->hideGeometry();
3209 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3211 // if there are any left over motions from the move, drop them now
3212 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3214 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3219 void BlackboxWindow::beginResize(int x_root
, int y_root
, Corner dir
) {
3220 assert(! (flags
.resizing
|| flags
.moving
));
3223 Only one window can be moved/resized at a time. If another window is already
3224 being moved or resized, then stop it before whating to work with this one.
3226 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3227 if (changing
&& changing
!= this) {
3228 if (changing
->flags
.moving
)
3229 changing
->endMove();
3230 else // if (changing->flags.resizing)
3231 changing
->endResize();
3239 switch (resize_dir
) {
3242 cursor
= blackbox
->getLowerLeftAngleCursor();
3247 cursor
= blackbox
->getLowerRightAngleCursor();
3251 anchor
= BottomRight
;
3252 cursor
= blackbox
->getUpperLeftAngleCursor();
3256 anchor
= BottomLeft
;
3257 cursor
= blackbox
->getUpperRightAngleCursor();
3261 assert(false); // unhandled Corner
3262 return; // unreachable, for the compiler
3265 XGrabServer(blackbox
->getXDisplay());
3266 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3267 PointerMotionMask
| ButtonReleaseMask
,
3268 GrabModeAsync
, GrabModeAsync
, None
, cursor
, CurrentTime
);
3270 flags
.resizing
= True
;
3271 blackbox
->setChangingWindow(this);
3274 frame
.changing
= frame
.rect
;
3276 constrain(anchor
, &gw
, &gh
);
3278 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3279 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3280 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3282 screen
->showGeometry(gw
, gh
);
3284 frame
.grab_x
= x_root
;
3285 frame
.grab_y
= y_root
;
3289 void BlackboxWindow::doResize(int x_root
, int y_root
) {
3290 assert(flags
.resizing
);
3291 assert(blackbox
->getChangingWindow() == this);
3293 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3294 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3295 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3300 switch (resize_dir
) {
3303 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3304 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3308 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3309 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3312 anchor
= BottomRight
;
3313 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3314 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3317 anchor
= BottomLeft
;
3318 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3319 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3323 assert(false); // unhandled Corner
3324 return; // unreachable, for the compiler
3327 constrain(anchor
, &gw
, &gh
);
3329 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3330 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3331 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3333 screen
->showGeometry(gw
, gh
);
3337 void BlackboxWindow::endResize(void) {
3338 assert(flags
.resizing
);
3339 assert(blackbox
->getChangingWindow() == this);
3341 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3342 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3343 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3344 XUngrabServer(blackbox
->getXDisplay());
3346 // unset maximized state after resized when fully maximized
3347 if (flags
.maximized
== 1)
3350 flags
.resizing
= False
;
3351 blackbox
->setChangingWindow(0);
3353 configure(frame
.changing
.x(), frame
.changing
.y(),
3354 frame
.changing
.width(), frame
.changing
.height());
3355 screen
->hideGeometry();
3357 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3359 // if there are any left over motions from the resize, drop them now
3360 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3362 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3367 void BlackboxWindow::motionNotifyEvent(const XMotionEvent
*me
) {
3369 fprintf(stderr
, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n",
3374 doMove(me
->x_root
, me
->y_root
);
3375 } else if (flags
.resizing
) {
3376 doResize(me
->x_root
, me
->y_root
);
3378 if (!flags
.resizing
&& me
->state
& Button1Mask
&& (functions
& Func_Move
) &&
3379 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3380 frame
.handle
== me
->window
|| frame
.window
== me
->window
)) {
3381 beginMove(me
->x_root
, me
->y_root
);
3382 } else if ((functions
& Func_Resize
) &&
3383 (me
->state
& Button1Mask
&& (me
->window
== frame
.right_grip
||
3384 me
->window
== frame
.left_grip
)) ||
3385 (me
->state
& Button3Mask
&& me
->state
& ModMask
&&
3386 me
->window
== frame
.window
)) {
3387 unsigned int zones
= screen
->getResizeZones();
3390 if (me
->window
== frame
.left_grip
) {
3391 corner
= BottomLeft
;
3392 } else if (me
->window
== frame
.right_grip
|| zones
== 1) {
3393 corner
= BottomRight
;
3396 bool left
= (me
->x_root
- frame
.rect
.x() <=
3397 static_cast<signed>(frame
.rect
.width() / 2));
3400 else // (zones == 4)
3401 top
= (me
->y_root
- frame
.rect
.y() <=
3402 static_cast<signed>(frame
.rect
.height() / 2));
3403 corner
= (top
? (left
? TopLeft
: TopRight
) :
3404 (left
? BottomLeft
: BottomRight
));
3407 beginResize(me
->x_root
, me
->y_root
, corner
);
3414 void BlackboxWindow::shapeEvent(XShapeEvent
*) {
3415 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
3422 bool BlackboxWindow::validateClient(void) const {
3423 XSync(blackbox
->getXDisplay(), False
);
3426 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3427 DestroyNotify
, &e
) ||
3428 XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3430 XPutBackEvent(blackbox
->getXDisplay(), &e
);
3439 void BlackboxWindow::restore(bool remap
) {
3440 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeDelete
);
3441 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
3442 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, NoEventMask
);
3444 // do not leave a shaded window as an icon unless it was an icon
3445 if (flags
.shaded
&& ! flags
.iconic
) setState(NormalState
);
3447 restoreGravity(client
.rect
);
3449 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
3450 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
3452 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, client
.old_bw
);
3455 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3456 ReparentNotify
, &ev
)) {
3459 // according to the ICCCM - if the client doesn't reparent to
3460 // root, then we have to do it for them
3461 XReparentWindow(blackbox
->getXDisplay(), client
.window
,
3462 screen
->getRootWindow(),
3463 client
.rect
.x(), client
.rect
.y());
3466 if (remap
) XMapWindow(blackbox
->getXDisplay(), client
.window
);
3470 // timer for autoraise
3471 void BlackboxWindow::timeout(void) {
3472 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3476 void BlackboxWindow::changeBlackboxHints(BlackboxHints
*net
) {
3477 if ((net
->flags
& AttribShaded
) &&
3478 ((blackbox_attrib
.attrib
& AttribShaded
) !=
3479 (net
->attrib
& AttribShaded
)))
3482 if (flags
.visible
&& // watch out for requests when we can not be seen
3483 (net
->flags
& (AttribMaxVert
| AttribMaxHoriz
)) &&
3484 ((blackbox_attrib
.attrib
& (AttribMaxVert
| AttribMaxHoriz
)) !=
3485 (net
->attrib
& (AttribMaxVert
| AttribMaxHoriz
)))) {
3486 if (flags
.maximized
) {
3491 if ((net
->flags
& AttribMaxHoriz
) && (net
->flags
& AttribMaxVert
))
3492 button
= ((net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0);
3493 else if (net
->flags
& AttribMaxVert
)
3494 button
= ((net
->attrib
& AttribMaxVert
) ? 2 : 0);
3495 else if (net
->flags
& AttribMaxHoriz
)
3496 button
= ((net
->attrib
& AttribMaxHoriz
) ? 3 : 0);
3502 if ((net
->flags
& AttribOmnipresent
) &&
3503 ((blackbox_attrib
.attrib
& AttribOmnipresent
) !=
3504 (net
->attrib
& AttribOmnipresent
)))
3507 if ((net
->flags
& AttribWorkspace
) &&
3508 (blackbox_attrib
.workspace
!= net
->workspace
)) {
3509 screen
->reassociateWindow(this, net
->workspace
, True
);
3511 if (screen
->getCurrentWorkspaceID() != net
->workspace
) {
3515 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3519 if (net
->flags
& AttribDecoration
) {
3520 switch (net
->decoration
) {
3522 // clear all decorations except close
3523 decorations
&= Decor_Close
;
3529 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Iconify
;
3531 decorations
= ((functions
& Func_Resize
) && !isTransient() ?
3532 decorations
| Decor_Handle
:
3533 decorations
&= ~Decor_Handle
);
3534 decorations
= (functions
& Func_Maximize
?
3535 decorations
| Decor_Maximize
:
3536 decorations
&= ~Decor_Maximize
);
3541 decorations
|= Decor_Titlebar
| Decor_Iconify
;
3542 decorations
&= ~(Decor_Border
| Decor_Handle
);
3544 decorations
= (functions
& Func_Maximize
?
3545 decorations
| Decor_Maximize
:
3546 decorations
&= ~Decor_Maximize
);
3551 decorations
|= Decor_Titlebar
;
3552 decorations
&= ~(Decor_Iconify
| Decor_Border
);
3554 decorations
= ((functions
& Func_Resize
) && !isTransient() ?
3555 decorations
| Decor_Handle
:
3556 decorations
&= ~Decor_Handle
);
3557 decorations
= (functions
& Func_Maximize
?
3558 decorations
| Decor_Maximize
:
3559 decorations
&= ~Decor_Maximize
);
3564 // we can not be shaded if we lack a titlebar
3565 if (flags
.shaded
&& ! (decorations
& Decor_Titlebar
))
3568 if (flags
.visible
&& frame
.window
) {
3569 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
3570 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
3574 setState(current_state
);
3580 * Set the sizes of all components of the window frame
3581 * (the window decorations).
3582 * These values are based upon the current style settings and the client
3583 * window's dimensions.
3585 void BlackboxWindow::upsize(void) {
3586 frame
.bevel_w
= screen
->getBevelWidth();
3588 if (decorations
& Decor_Border
) {
3589 frame
.border_w
= screen
->getBorderWidth();
3590 if (! isTransient())
3591 frame
.mwm_border_w
= screen
->getFrameWidth();
3593 frame
.mwm_border_w
= 0;
3595 frame
.mwm_border_w
= frame
.border_w
= 0;
3598 if (decorations
& Decor_Titlebar
) {
3599 // the height of the titlebar is based upon the height of the font being
3600 // used to display the window's title
3601 WindowStyle
*style
= screen
->getWindowStyle();
3602 frame
.title_h
= style
->font
->height() + (frame
.bevel_w
* 2) + 2;
3604 frame
.label_h
= frame
.title_h
- (frame
.bevel_w
* 2);
3605 frame
.button_w
= (frame
.label_h
- 2);
3607 // set the top frame margin
3608 frame
.margin
.top
= frame
.border_w
+ frame
.title_h
+
3609 frame
.border_w
+ frame
.mwm_border_w
;
3615 // set the top frame margin
3616 frame
.margin
.top
= frame
.border_w
+ frame
.mwm_border_w
;
3619 // set the left/right frame margin
3620 frame
.margin
.left
= frame
.margin
.right
= frame
.border_w
+ frame
.mwm_border_w
;
3622 if (decorations
& Decor_Handle
) {
3623 frame
.grip_w
= frame
.button_w
* 2;
3624 frame
.handle_h
= screen
->getHandleWidth();
3626 // set the bottom frame margin
3627 frame
.margin
.bottom
= frame
.border_w
+ frame
.handle_h
+
3628 frame
.border_w
+ frame
.mwm_border_w
;
3633 // set the bottom frame margin
3634 frame
.margin
.bottom
= frame
.border_w
+ frame
.mwm_border_w
;
3638 We first get the normal dimensions and use this to define the inside_w/h
3639 then we modify the height if shading is in effect.
3640 If the shade state is not considered then frame.rect gets reset to the
3641 normal window size on a reconfigure() call resulting in improper
3642 dimensions appearing in move/resize and other events.
3645 height
= client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
,
3646 width
= client
.rect
.width() + frame
.margin
.left
+ frame
.margin
.right
;
3648 frame
.inside_w
= width
- (frame
.border_w
* 2);
3649 frame
.inside_h
= height
- (frame
.border_w
* 2);
3652 height
= frame
.title_h
+ (frame
.border_w
* 2);
3653 frame
.rect
.setSize(width
, height
);
3658 * Calculate the size of the client window and constrain it to the
3659 * size specified by the size hints of the client window.
3661 * The logical width and height are placed into pw and ph, if they
3662 * are non-zero. Logical size refers to the users perception of
3663 * the window size (for example an xterm resizes in cells, not in pixels).
3665 * The physical geometry is placed into frame.changing_{x,y,width,height}.
3666 * Physical geometry refers to the geometry of the window in pixels.
3668 void BlackboxWindow::constrain(Corner anchor
, int *pw
, int *ph
) {
3669 // frame.changing represents the requested frame size, we need to
3670 // strip the frame margin off and constrain the client size
3671 frame
.changing
.setCoords(frame
.changing
.left() + frame
.margin
.left
,
3672 frame
.changing
.top() + frame
.margin
.top
,
3673 frame
.changing
.right() - frame
.margin
.right
,
3674 frame
.changing
.bottom() - frame
.margin
.bottom
);
3676 int dw
= frame
.changing
.width(), dh
= frame
.changing
.height(),
3677 base_width
= (client
.base_width
) ? client
.base_width
: client
.min_width
,
3678 base_height
= (client
.base_height
) ? client
.base_height
:
3682 if (dw
< static_cast<signed>(client
.min_width
)) dw
= client
.min_width
;
3683 if (dh
< static_cast<signed>(client
.min_height
)) dh
= client
.min_height
;
3684 if (dw
> static_cast<signed>(client
.max_width
)) dw
= client
.max_width
;
3685 if (dh
> static_cast<signed>(client
.max_height
)) dh
= client
.max_height
;
3688 dw
/= client
.width_inc
;
3690 dh
/= client
.height_inc
;
3693 if (client
.width_inc
== 1)
3694 *pw
= dw
+ base_width
;
3699 if (client
.height_inc
== 1)
3700 *ph
= dh
+ base_height
;
3705 dw
*= client
.width_inc
;
3707 dh
*= client
.height_inc
;
3710 frame
.changing
.setSize(dw
, dh
);
3712 // add the frame margin back onto frame.changing
3713 frame
.changing
.setCoords(frame
.changing
.left() - frame
.margin
.left
,
3714 frame
.changing
.top() - frame
.margin
.top
,
3715 frame
.changing
.right() + frame
.margin
.right
,
3716 frame
.changing
.bottom() + frame
.margin
.bottom
);
3718 // move frame.changing to the specified anchor
3726 dx
= frame
.rect
.right() - frame
.changing
.right();
3730 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3734 dx
= frame
.rect
.right() - frame
.changing
.right();
3735 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3739 assert(false); // unhandled corner
3741 frame
.changing
.setPos(frame
.changing
.x() + dx
, frame
.changing
.y() + dy
);
3745 void WindowStyle::doJustify(const std::string
&text
, int &start_pos
,
3746 unsigned int max_length
,
3747 unsigned int modifier
) const {
3748 size_t text_len
= text
.size();
3749 unsigned int length
;
3752 length
= font
->measureString(string(text
, 0, text_len
)) + modifier
;
3753 } while (length
> max_length
&& text_len
-- > 0);
3757 start_pos
+= max_length
- length
;
3761 start_pos
+= (max_length
- length
) / 2;
3771 BWindowGroup::BWindowGroup(Blackbox
*b
, Window _group
)
3772 : blackbox(b
), group(_group
) {
3773 XWindowAttributes wattrib
;
3774 if (! XGetWindowAttributes(blackbox
->getXDisplay(), group
, &wattrib
)) {
3775 // group window doesn't seem to exist anymore
3780 XSelectInput(blackbox
->getXDisplay(), group
,
3781 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
3783 blackbox
->saveGroupSearch(group
, this);
3787 BWindowGroup::~BWindowGroup(void) {
3788 blackbox
->removeGroupSearch(group
);
3793 BWindowGroup::find(BScreen
*screen
, bool allow_transients
) const {
3794 BlackboxWindow
*ret
= blackbox
->getFocusedWindow();
3796 // does the focus window match (or any transient_fors)?
3798 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3799 if (ret
->isTransient() && allow_transients
) break;
3800 else if (! ret
->isTransient()) break;
3803 ret
= ret
->getTransientFor();
3806 if (ret
) return ret
;
3808 // the focus window didn't match, look in the group's window list
3809 BlackboxWindowList::const_iterator it
, end
= windowList
.end();
3810 for (it
= windowList
.begin(); it
!= end
; ++it
) {
3812 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3813 if (ret
->isTransient() && allow_transients
) break;
3814 else if (! ret
->isTransient()) break;