1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2 // Window.cc for Blackbox - an X11 Window manager
3 // Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry <shaleh at debian.org>
4 // Copyright (c) 1997 - 2000, 2002 Brad Hughes <bhughes at trolltech.com>
6 // Permission is hereby granted, free of charge, to any person obtaining a
7 // copy of this software and associated documentation files (the "Software"),
8 // to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 // and/or sell copies of the Software, and to permit persons to whom the
11 // Software is furnished to do so, subject to the following conditions:
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 // DEALINGS IN THE SOFTWARE.
25 # include "../config.h"
26 #endif // HAVE_CONFIG_H
29 #include <X11/Xatom.h>
30 #include <X11/keysym.h>
34 #endif // HAVE_STRING_H
39 # endif // HAVE_STDIO_H
44 #endif // HAVE_STDLIB_H
48 #include "blackbox.hh"
49 #include "Clientmenu.hh"
52 #include "Iconmenu.hh"
58 #include "Windowmenu.hh"
59 #include "Workspace.hh"
65 // change this to change what modifier keys openbox uses for mouse bindings
66 // for example: Mod1Mask | ControlMask
67 // or: ControlMask| ShiftMask
68 const unsigned int ModMask
= Mod1Mask
;
71 * Initializes the class with default values/the window's set initial values.
73 BlackboxWindow::BlackboxWindow(Blackbox
*b
, Window w
, BScreen
*s
) {
74 // fprintf(stderr, "BlackboxWindow size: %d bytes\n",
75 // sizeof(BlackboxWindow));
78 fprintf(stderr
, "BlackboxWindow::BlackboxWindow(): creating 0x%lx\n", w
);
82 set timer to zero... it is initialized properly later, so we check
83 if timer is zero in the destructor, and assume that the window is not
84 fully constructed if timer is zero...
90 xatom
= blackbox
->getXAtom();
92 if (! validateClient()) {
97 // fetch client size and placement
98 XWindowAttributes wattrib
;
99 if (! XGetWindowAttributes(blackbox
->getXDisplay(),
100 client
.window
, &wattrib
) ||
101 ! wattrib
.screen
|| wattrib
.override_redirect
) {
104 "BlackboxWindow::BlackboxWindow(): XGetWindowAttributes failed\n");
111 // set the eventmask early in the game so that we make sure we get
112 // all the events we are interested in
113 XSetWindowAttributes attrib_set
;
114 attrib_set
.event_mask
= PropertyChangeMask
| FocusChangeMask
|
116 attrib_set
.do_not_propagate_mask
= ButtonPressMask
| ButtonReleaseMask
|
118 XChangeWindowAttributes(blackbox
->getXDisplay(), client
.window
,
119 CWEventMask
|CWDontPropagate
, &attrib_set
);
121 flags
.moving
= flags
.resizing
= flags
.shaded
= flags
.visible
=
122 flags
.iconic
= flags
.focused
= flags
.stuck
= flags
.modal
=
123 flags
.send_focus_message
= flags
.shaped
= flags
.skip_taskbar
=
124 flags
.skip_pager
= flags
.fullscreen
= False
;
127 blackbox_attrib
.workspace
= window_number
= BSENTINEL
;
129 blackbox_attrib
.flags
= blackbox_attrib
.attrib
= blackbox_attrib
.stack
130 = blackbox_attrib
.decoration
= 0l;
131 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
132 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
135 frame
.window
= frame
.plate
= frame
.title
= frame
.handle
= None
;
136 frame
.close_button
= frame
.iconify_button
= frame
.maximize_button
= None
;
137 frame
.right_grip
= frame
.left_grip
= None
;
139 frame
.ulabel_pixel
= frame
.flabel_pixel
= frame
.utitle_pixel
=
140 frame
.ftitle_pixel
= frame
.uhandle_pixel
= frame
.fhandle_pixel
=
141 frame
.ubutton_pixel
= frame
.fbutton_pixel
= frame
.pbutton_pixel
=
142 frame
.uborder_pixel
= frame
.fborder_pixel
= frame
.ugrip_pixel
=
143 frame
.fgrip_pixel
= 0;
144 frame
.utitle
= frame
.ftitle
= frame
.uhandle
= frame
.fhandle
= None
;
145 frame
.ulabel
= frame
.flabel
= frame
.ubutton
= frame
.fbutton
= None
;
146 frame
.pbutton
= frame
.ugrip
= frame
.fgrip
= None
;
148 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
149 mwm_decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
150 Decor_Iconify
| Decor_Maximize
| Decor_Close
;
152 client
.normal_hint_flags
= 0;
153 client
.window_group
= None
;
154 client
.transient_for
= 0;
156 current_state
= NormalState
;
161 get the initial size and location of client window (relative to the
162 _root window_). This position is the reference point used with the
163 window's gravity to find the window's initial position.
165 client
.rect
.setRect(wattrib
.x
, wattrib
.y
, wattrib
.width
, wattrib
.height
);
166 client
.old_bw
= wattrib
.border_width
;
168 lastButtonPressTime
= 0;
170 timer
= new BTimer(blackbox
, this);
171 timer
->setTimeout(blackbox
->getAutoRaiseDelay());
173 // get size, aspect, minimum/maximum size and other hints set by the
176 if (! getBlackboxHints()) {
184 frame
.window
= createToplevelWindow();
186 blackbox
->saveWindowSearch(frame
.window
, this);
188 frame
.plate
= createChildWindow(frame
.window
);
189 blackbox
->saveWindowSearch(frame
.plate
, this);
191 // determine if this is a transient window
194 // determine the window's type, so we can decide its decorations and
195 // functionality, or if we should not manage it at all
196 if (getWindowType()) {
197 // adjust the window decorations/behavior based on the window type
198 switch (window_type
) {
202 blackbox_attrib
.workspace
= 0; // we do need to belong to a workspace
203 flags
.stuck
= True
; // we show up on all workspaces
205 // none of these windows are manipulated by the window manager
211 // these windows get less functionality
212 functions
&= ~(Func_Maximize
| Func_Resize
| Func_Iconify
);
216 // dialogs cannot be maximized
217 functions
&= ~Func_Maximize
;
221 // normal windows retain all of the possible decorations and functionality
228 // further adjeust the window's decorations/behavior based on window sizes
229 if ((client
.normal_hint_flags
& PMinSize
) &&
230 (client
.normal_hint_flags
& PMaxSize
) &&
231 client
.max_width
<= client
.min_width
&&
232 client
.max_height
<= client
.min_height
) {
233 functions
&= ~(Func_Resize
| Func_Maximize
);
240 // apply the size and gravity hint to the frame
244 bool place_window
= True
;
245 if (blackbox
->isStartup() || isTransient() ||
246 client
.normal_hint_flags
& (PPosition
|USPosition
)) {
247 applyGravity(frame
.rect
);
249 if (blackbox
->isStartup() || client
.rect
.intersects(screen
->getRect()))
250 place_window
= False
;
253 // add the window's strut. note this is done *after* placing the window.
254 screen
->addStrut(&client
.strut
);
258 the server needs to be grabbed here to prevent client's from sending
259 events while we are in the process of configuring their window.
260 We hold the grab until after we are done moving the window around.
263 XGrabServer(blackbox
->getXDisplay());
265 associateClientWindow();
267 blackbox
->saveWindowSearch(client
.window
, this);
269 if (blackbox_attrib
.workspace
>= screen
->getWorkspaceCount())
270 screen
->getCurrentWorkspace()->addWindow(this, place_window
);
272 screen
->getWorkspace(blackbox_attrib
.workspace
)->
273 addWindow(this, place_window
);
275 if (! place_window
) {
276 // don't need to call configure if we are letting the workspace
278 configure(frame
.rect
.x(), frame
.rect
.y(),
279 frame
.rect
.width(), frame
.rect
.height());
285 XUngrabServer(blackbox
->getXDisplay());
288 if (blackbox
->hasShapeExtensions() && flags
.shaped
)
292 // now that we know where to put the window and what it should look like
293 // we apply the decorations
298 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
300 // this ensures the title, buttons, and other decor are properly displayed
303 // preserve the window's initial state on first map, and its current state
305 unsigned long initial_state
= current_state
;
307 current_state
= initial_state
;
309 // get sticky state from our parent window if we've got one
310 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
311 client
.transient_for
->isStuck() != flags
.stuck
)
315 flags
.shaded
= False
;
316 initial_state
= current_state
;
320 At this point in the life of a window, current_state should only be set
321 to IconicState if the window was an *icon*, not if it was shaded.
323 if (initial_state
!= IconicState
)
324 current_state
= NormalState
;
332 if (flags
.maximized
&& (functions
& Func_Maximize
))
335 // create this last so it only needs to be configured once
336 windowmenu
= new Windowmenu(this);
340 BlackboxWindow::~BlackboxWindow(void) {
342 fprintf(stderr
, "BlackboxWindow::~BlackboxWindow: destroying 0x%lx\n",
346 if (! timer
) // window not managed...
352 screen
->removeStrut(&client
.strut
);
353 screen
->updateAvailableArea();
355 // We don't need to worry about resizing because resizing always grabs the X
356 // server. This should only ever happen if using opaque moving.
364 if (client
.window_group
) {
365 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
366 if (group
) group
->removeWindow(this);
369 // remove ourselves from our transient_for
371 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul)
372 client
.transient_for
->client
.transientList
.remove(this);
373 client
.transient_for
= (BlackboxWindow
*) 0;
376 if (client
.transientList
.size() > 0) {
377 // reset transient_for for all transients
378 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
379 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
380 (*it
)->client
.transient_for
= (BlackboxWindow
*) 0;
390 blackbox
->removeWindowSearch(frame
.plate
);
391 XDestroyWindow(blackbox
->getXDisplay(), frame
.plate
);
395 blackbox
->removeWindowSearch(frame
.window
);
396 XDestroyWindow(blackbox
->getXDisplay(), frame
.window
);
399 blackbox
->removeWindowSearch(client
.window
);
403 void BlackboxWindow::enableDecor(bool enable
) {
405 // start with everything on
407 (mwm_decorations
& Decor_Titlebar
? Decor_Titlebar
: 0) |
408 (mwm_decorations
& Decor_Border
? Decor_Border
: 0) |
409 (mwm_decorations
& Decor_Handle
? Decor_Handle
: 0) |
410 (mwm_decorations
& Decor_Iconify
? Decor_Iconify
: 0) |
411 (mwm_decorations
& Decor_Maximize
? Decor_Maximize
: 0) |
412 (mwm_decorations
& Decor_Close
? Decor_Close
: 0);
414 if (! (functions
& Func_Close
)) decorations
&= ~Decor_Close
;
415 if (! (functions
& Func_Maximize
)) decorations
&= ~Decor_Maximize
;
416 if (! (functions
& Func_Iconify
)) decorations
&= ~Decor_Iconify
;
417 if (! (functions
& Func_Resize
)) decorations
&= ~Decor_Handle
;
419 switch (window_type
) {
424 // none of these windows are decorated by the window manager at all
430 decorations
&= ~(Decor_Border
);
434 decorations
&= ~Decor_Handle
;
445 if (decorations
& Decor_Titlebar
)
449 if (decorations
& Decor_Handle
)
454 * Creates a new top level window, with a given location, size, and border
456 * Returns: the newly created window
458 Window
BlackboxWindow::createToplevelWindow(void) {
459 XSetWindowAttributes attrib_create
;
460 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
| CWColormap
|
461 CWOverrideRedirect
| CWEventMask
;
463 attrib_create
.background_pixmap
= None
;
464 attrib_create
.colormap
= screen
->getColormap();
465 attrib_create
.override_redirect
= True
;
466 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
468 EnterWindowMask
| LeaveWindowMask
;
470 return XCreateWindow(blackbox
->getXDisplay(), screen
->getRootWindow(),
471 0, 0, 1, 1, frame
.border_w
, screen
->getDepth(),
472 InputOutput
, screen
->getVisual(), create_mask
,
478 * Creates a child window, and optionally associates a given cursor with
481 Window
BlackboxWindow::createChildWindow(Window parent
, Cursor cursor
) {
482 XSetWindowAttributes attrib_create
;
483 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
|
486 attrib_create
.background_pixmap
= None
;
487 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
488 ButtonMotionMask
| ExposureMask
;
491 create_mask
|= CWCursor
;
492 attrib_create
.cursor
= cursor
;
495 return XCreateWindow(blackbox
->getXDisplay(), parent
, 0, 0, 1, 1, 0,
496 screen
->getDepth(), InputOutput
, screen
->getVisual(),
497 create_mask
, &attrib_create
);
501 void BlackboxWindow::associateClientWindow(void) {
502 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, 0);
506 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeInsert
);
508 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, SubstructureRedirectMask
);
511 note we used to grab around this call to XReparentWindow however the
512 server is now grabbed before this method is called
514 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
516 XSelectInput(blackbox
->getXDisplay(), client
.window
,
517 event_mask
& ~StructureNotifyMask
);
518 XReparentWindow(blackbox
->getXDisplay(), client
.window
, frame
.plate
, 0, 0);
519 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
521 XRaiseWindow(blackbox
->getXDisplay(), frame
.plate
);
522 XMapSubwindows(blackbox
->getXDisplay(), frame
.plate
);
525 if (blackbox
->hasShapeExtensions()) {
526 XShapeSelectInput(blackbox
->getXDisplay(), client
.window
,
533 XShapeQueryExtents(blackbox
->getXDisplay(), client
.window
, &shaped
,
534 &foo
, &foo
, &ufoo
, &ufoo
, &foo
, &foo
, &foo
,
536 flags
.shaped
= shaped
;
542 void BlackboxWindow::decorate(void) {
545 texture
= &(screen
->getWindowStyle()->b_focus
);
546 frame
.fbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
549 frame
.fbutton_pixel
= texture
->color().pixel();
551 texture
= &(screen
->getWindowStyle()->b_unfocus
);
552 frame
.ubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
555 frame
.ubutton_pixel
= texture
->color().pixel();
557 texture
= &(screen
->getWindowStyle()->b_pressed
);
558 frame
.pbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
561 frame
.pbutton_pixel
= texture
->color().pixel();
563 if (decorations
& Decor_Titlebar
) {
564 texture
= &(screen
->getWindowStyle()->t_focus
);
565 frame
.ftitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
568 frame
.ftitle_pixel
= texture
->color().pixel();
570 texture
= &(screen
->getWindowStyle()->t_unfocus
);
571 frame
.utitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
574 frame
.utitle_pixel
= texture
->color().pixel();
576 XSetWindowBorder(blackbox
->getXDisplay(), frame
.title
,
577 screen
->getBorderColor()->pixel());
582 if (decorations
& Decor_Border
) {
583 frame
.fborder_pixel
= screen
->getWindowStyle()->f_focus
.pixel();
584 frame
.uborder_pixel
= screen
->getWindowStyle()->f_unfocus
.pixel();
585 blackbox_attrib
.flags
|= AttribDecoration
;
586 blackbox_attrib
.decoration
= DecorNormal
;
588 blackbox_attrib
.flags
|= AttribDecoration
;
589 blackbox_attrib
.decoration
= DecorNone
;
592 if (decorations
& Decor_Handle
) {
593 texture
= &(screen
->getWindowStyle()->h_focus
);
594 frame
.fhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
597 frame
.fhandle_pixel
= texture
->color().pixel();
599 texture
= &(screen
->getWindowStyle()->h_unfocus
);
600 frame
.uhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
603 frame
.uhandle_pixel
= texture
->color().pixel();
605 texture
= &(screen
->getWindowStyle()->g_focus
);
606 frame
.fgrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.fgrip
);
608 frame
.fgrip_pixel
= texture
->color().pixel();
610 texture
= &(screen
->getWindowStyle()->g_unfocus
);
611 frame
.ugrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.ugrip
);
613 frame
.ugrip_pixel
= texture
->color().pixel();
615 XSetWindowBorder(blackbox
->getXDisplay(), frame
.handle
,
616 screen
->getBorderColor()->pixel());
617 XSetWindowBorder(blackbox
->getXDisplay(), frame
.left_grip
,
618 screen
->getBorderColor()->pixel());
619 XSetWindowBorder(blackbox
->getXDisplay(), frame
.right_grip
,
620 screen
->getBorderColor()->pixel());
623 XSetWindowBorder(blackbox
->getXDisplay(), frame
.window
,
624 screen
->getBorderColor()->pixel());
628 void BlackboxWindow::decorateLabel(void) {
631 texture
= &(screen
->getWindowStyle()->l_focus
);
632 frame
.flabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.flabel
);
634 frame
.flabel_pixel
= texture
->color().pixel();
636 texture
= &(screen
->getWindowStyle()->l_unfocus
);
637 frame
.ulabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.ulabel
);
639 frame
.ulabel_pixel
= texture
->color().pixel();
643 void BlackboxWindow::createHandle(void) {
644 frame
.handle
= createChildWindow(frame
.window
);
645 blackbox
->saveWindowSearch(frame
.handle
, this);
648 createChildWindow(frame
.handle
, blackbox
->getLowerLeftAngleCursor());
649 blackbox
->saveWindowSearch(frame
.left_grip
, this);
652 createChildWindow(frame
.handle
, blackbox
->getLowerRightAngleCursor());
653 blackbox
->saveWindowSearch(frame
.right_grip
, this);
657 void BlackboxWindow::destroyHandle(void) {
659 screen
->getImageControl()->removeImage(frame
.fhandle
);
662 screen
->getImageControl()->removeImage(frame
.uhandle
);
665 screen
->getImageControl()->removeImage(frame
.fgrip
);
668 screen
->getImageControl()->removeImage(frame
.ugrip
);
670 blackbox
->removeWindowSearch(frame
.left_grip
);
671 blackbox
->removeWindowSearch(frame
.right_grip
);
673 XDestroyWindow(blackbox
->getXDisplay(), frame
.left_grip
);
674 XDestroyWindow(blackbox
->getXDisplay(), frame
.right_grip
);
675 frame
.left_grip
= frame
.right_grip
= None
;
677 blackbox
->removeWindowSearch(frame
.handle
);
678 XDestroyWindow(blackbox
->getXDisplay(), frame
.handle
);
683 void BlackboxWindow::createTitlebar(void) {
684 frame
.title
= createChildWindow(frame
.window
);
685 frame
.label
= createChildWindow(frame
.title
);
686 blackbox
->saveWindowSearch(frame
.title
, this);
687 blackbox
->saveWindowSearch(frame
.label
, this);
689 if (decorations
& Decor_Iconify
) createIconifyButton();
690 if (decorations
& Decor_Maximize
) createMaximizeButton();
691 if (decorations
& Decor_Close
) createCloseButton();
695 void BlackboxWindow::destroyTitlebar(void) {
696 if (frame
.close_button
)
697 destroyCloseButton();
699 if (frame
.iconify_button
)
700 destroyIconifyButton();
702 if (frame
.maximize_button
)
703 destroyMaximizeButton();
706 screen
->getImageControl()->removeImage(frame
.ftitle
);
709 screen
->getImageControl()->removeImage(frame
.utitle
);
712 screen
->getImageControl()->removeImage(frame
.flabel
);
715 screen
->getImageControl()->removeImage(frame
.ulabel
);
718 screen
->getImageControl()->removeImage(frame
.fbutton
);
721 screen
->getImageControl()->removeImage(frame
.ubutton
);
724 screen
->getImageControl()->removeImage(frame
.pbutton
);
726 blackbox
->removeWindowSearch(frame
.title
);
727 blackbox
->removeWindowSearch(frame
.label
);
729 XDestroyWindow(blackbox
->getXDisplay(), frame
.label
);
730 XDestroyWindow(blackbox
->getXDisplay(), frame
.title
);
731 frame
.title
= frame
.label
= None
;
735 void BlackboxWindow::createCloseButton(void) {
736 if (frame
.title
!= None
) {
737 frame
.close_button
= createChildWindow(frame
.title
);
738 blackbox
->saveWindowSearch(frame
.close_button
, this);
743 void BlackboxWindow::destroyCloseButton(void) {
744 blackbox
->removeWindowSearch(frame
.close_button
);
745 XDestroyWindow(blackbox
->getXDisplay(), frame
.close_button
);
746 frame
.close_button
= None
;
750 void BlackboxWindow::createIconifyButton(void) {
751 if (frame
.title
!= None
) {
752 frame
.iconify_button
= createChildWindow(frame
.title
);
753 blackbox
->saveWindowSearch(frame
.iconify_button
, this);
758 void BlackboxWindow::destroyIconifyButton(void) {
759 blackbox
->removeWindowSearch(frame
.iconify_button
);
760 XDestroyWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
761 frame
.iconify_button
= None
;
765 void BlackboxWindow::createMaximizeButton(void) {
766 if (frame
.title
!= None
) {
767 frame
.maximize_button
= createChildWindow(frame
.title
);
768 blackbox
->saveWindowSearch(frame
.maximize_button
, this);
773 void BlackboxWindow::destroyMaximizeButton(void) {
774 blackbox
->removeWindowSearch(frame
.maximize_button
);
775 XDestroyWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
776 frame
.maximize_button
= None
;
780 void BlackboxWindow::positionButtons(bool redecorate_label
) {
781 string layout
= blackbox
->getTitlebarLayout();
784 bool hasclose
, hasiconify
, hasmaximize
, haslabel
;
785 hasclose
= hasiconify
= hasmaximize
= haslabel
= false;
787 string::const_iterator it
, end
;
788 for (it
= layout
.begin(), end
= layout
.end(); it
!= end
; ++it
) {
791 if (! hasclose
&& (decorations
& Decor_Close
)) {
797 if (! hasiconify
&& (decorations
& Decor_Iconify
)) {
803 if (! hasmaximize
&& (decorations
& Decor_Maximize
)) {
815 if (! hasclose
&& frame
.close_button
)
816 destroyCloseButton();
817 if (! hasiconify
&& frame
.iconify_button
)
818 destroyIconifyButton();
819 if (! hasmaximize
&& frame
.maximize_button
)
820 destroyMaximizeButton();
822 parsed
+= 'L'; // require that the label be in the layout
824 const unsigned int bsep
= frame
.bevel_w
+ 1; // separation between elements
825 const unsigned int by
= frame
.bevel_w
+ 1;
826 const unsigned int ty
= frame
.bevel_w
;
828 frame
.label_w
= frame
.inside_w
- bsep
* 2 -
829 (frame
.button_w
+ bsep
) * (parsed
.size() - 1);
831 unsigned int x
= bsep
;
832 for (it
= parsed
.begin(), end
= parsed
.end(); it
!= end
; ++it
) {
835 if (! frame
.close_button
) createCloseButton();
836 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.close_button
, x
, by
,
837 frame
.button_w
, frame
.button_w
);
838 x
+= frame
.button_w
+ bsep
;
841 if (! frame
.iconify_button
) createIconifyButton();
842 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.iconify_button
, x
, by
,
843 frame
.button_w
, frame
.button_w
);
844 x
+= frame
.button_w
+ bsep
;
847 if (! frame
.maximize_button
) createMaximizeButton();
848 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.maximize_button
, x
, by
,
849 frame
.button_w
, frame
.button_w
);
850 x
+= frame
.button_w
+ bsep
;
853 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.label
, x
, ty
,
854 frame
.label_w
, frame
.label_h
);
855 x
+= frame
.label_w
+ bsep
;
860 if (redecorate_label
) decorateLabel();
866 void BlackboxWindow::reconfigure(void) {
867 restoreGravity(client
.rect
);
869 applyGravity(frame
.rect
);
878 windowmenu
->move(windowmenu
->getX(), frame
.rect
.y() + frame
.title_h
);
879 windowmenu
->reconfigure();
884 void BlackboxWindow::grabButtons(void) {
885 if (! screen
->isSloppyFocus() || screen
->doClickRaise())
886 // grab button 1 for changing focus/raising
887 blackbox
->grabButton(Button1
, 0, frame
.plate
, True
, ButtonPressMask
,
888 GrabModeSync
, GrabModeSync
, frame
.plate
, None
,
889 screen
->allowScrollLock());
891 if (functions
& Func_Move
)
892 blackbox
->grabButton(Button1
, ModMask
, frame
.window
, True
,
893 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
894 GrabModeAsync
, frame
.window
, None
,
895 screen
->allowScrollLock());
896 if (functions
& Func_Resize
)
897 blackbox
->grabButton(Button3
, ModMask
, frame
.window
, True
,
898 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
899 GrabModeAsync
, frame
.window
, None
,
900 screen
->allowScrollLock());
901 // alt+middle lowers the window
902 blackbox
->grabButton(Button2
, ModMask
, frame
.window
, True
,
903 ButtonReleaseMask
, GrabModeAsync
, GrabModeAsync
,
905 screen
->allowScrollLock());
909 void BlackboxWindow::ungrabButtons(void) {
910 blackbox
->ungrabButton(Button1
, 0, frame
.plate
);
911 blackbox
->ungrabButton(Button1
, ModMask
, frame
.window
);
912 blackbox
->ungrabButton(Button2
, ModMask
, frame
.window
);
913 blackbox
->ungrabButton(Button3
, ModMask
, frame
.window
);
917 void BlackboxWindow::positionWindows(void) {
918 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.window
,
919 frame
.rect
.x(), frame
.rect
.y(), frame
.inside_w
,
920 (flags
.shaded
) ? frame
.title_h
: frame
.inside_h
);
921 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.window
,
923 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.plate
,
925 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.plate
,
926 frame
.margin
.left
- frame
.mwm_border_w
- frame
.border_w
,
927 frame
.margin
.top
- frame
.mwm_border_w
- frame
.border_w
,
928 client
.rect
.width(), client
.rect
.height());
929 XMoveResizeWindow(blackbox
->getXDisplay(), client
.window
,
930 0, 0, client
.rect
.width(), client
.rect
.height());
931 // ensure client.rect contains the real location
932 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
933 frame
.rect
.top() + frame
.margin
.top
);
935 if (decorations
& Decor_Titlebar
) {
936 if (frame
.title
== None
) createTitlebar();
938 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.title
,
940 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.title
, -frame
.border_w
,
941 -frame
.border_w
, frame
.inside_w
, frame
.title_h
);
944 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
945 XMapWindow(blackbox
->getXDisplay(), frame
.title
);
946 } else if (frame
.title
) {
949 if (decorations
& Decor_Handle
) {
950 if (frame
.handle
== None
) createHandle();
951 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.handle
,
953 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.left_grip
,
955 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.right_grip
,
958 // use client.rect here so the value is correct even if shaded
959 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.handle
,
961 client
.rect
.height() + frame
.margin
.top
+
962 frame
.mwm_border_w
- frame
.border_w
,
963 frame
.inside_w
, frame
.handle_h
);
964 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.left_grip
,
965 -frame
.border_w
, -frame
.border_w
,
966 frame
.grip_w
, frame
.handle_h
);
967 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.right_grip
,
968 frame
.inside_w
- frame
.grip_w
- frame
.border_w
,
969 -frame
.border_w
, frame
.grip_w
, frame
.handle_h
);
971 XMapSubwindows(blackbox
->getXDisplay(), frame
.handle
);
972 XMapWindow(blackbox
->getXDisplay(), frame
.handle
);
973 } else if (frame
.handle
) {
976 XSync(blackbox
->getXDisplay(), False
);
980 void BlackboxWindow::updateStrut(void) {
981 unsigned long num
= 4;
983 if (! xatom
->getValue(client
.window
, XAtom::net_wm_strut
, XAtom::cardinal
,
988 client
.strut
.left
= data
[0];
989 client
.strut
.right
= data
[1];
990 client
.strut
.top
= data
[2];
991 client
.strut
.bottom
= data
[3];
993 screen
->updateAvailableArea();
1000 bool BlackboxWindow::getWindowType(void) {
1002 if (xatom
->getValue(client
.window
, XAtom::net_wm_window_type
, XAtom::atom
,
1004 if (val
== xatom
->getAtom(XAtom::net_wm_window_type_desktop
))
1005 window_type
= Type_Desktop
;
1006 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_dock
))
1007 window_type
= Type_Dock
;
1008 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_toolbar
))
1009 window_type
= Type_Toolbar
;
1010 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_menu
))
1011 window_type
= Type_Menu
;
1012 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_utility
))
1013 window_type
= Type_Utility
;
1014 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_splash
))
1015 window_type
= Type_Splash
;
1016 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_dialog
))
1017 window_type
= Type_Dialog
;
1018 else //if (val[0] == xatom->getAtom(XAtom::net_wm_window_type_normal))
1019 window_type
= Type_Normal
;
1025 * the window type hint was not set, which means we either classify ourself
1026 * as a normal window or a dialog, depending on if we are a transient.
1029 window_type
= Type_Dialog
;
1031 window_type
= Type_Normal
;
1037 void BlackboxWindow::getWMName(void) {
1038 if (xatom
->getValue(client
.window
, XAtom::net_wm_name
,
1039 XAtom::utf8
, client
.title
) &&
1040 !client
.title
.empty()) {
1041 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
1044 //fall through to using WM_NAME
1045 if (xatom
->getValue(client
.window
, XAtom::wm_name
, XAtom::ansi
, client
.title
)
1046 && !client
.title
.empty()) {
1047 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
1050 // fall back to an internal default
1051 client
.title
= i18n(WindowSet
, WindowUnnamed
, "Unnamed");
1052 xatom
->setValue(client
.window
, XAtom::net_wm_visible_name
, XAtom::utf8
,
1057 void BlackboxWindow::getWMIconName(void) {
1058 if (xatom
->getValue(client
.window
, XAtom::net_wm_icon_name
,
1059 XAtom::utf8
, client
.icon_title
) &&
1060 !client
.icon_title
.empty()) {
1061 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1064 //fall through to using WM_ICON_NAME
1065 if (xatom
->getValue(client
.window
, XAtom::wm_icon_name
, XAtom::ansi
,
1066 client
.icon_title
) &&
1067 !client
.icon_title
.empty()) {
1068 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1071 // fall back to using the main name
1072 client
.icon_title
= client
.title
;
1073 xatom
->setValue(client
.window
, XAtom::net_wm_visible_icon_name
, XAtom::utf8
,
1079 * Retrieve which WM Protocols are supported by the client window.
1080 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
1081 * window's decorations and allow the close behavior.
1082 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
1085 void BlackboxWindow::getWMProtocols(void) {
1089 if (XGetWMProtocols(blackbox
->getXDisplay(), client
.window
,
1090 &proto
, &num_return
)) {
1091 for (int i
= 0; i
< num_return
; ++i
) {
1092 if (proto
[i
] == xatom
->getAtom(XAtom::wm_delete_window
)) {
1093 decorations
|= Decor_Close
;
1094 functions
|= Func_Close
;
1095 } else if (proto
[i
] == xatom
->getAtom(XAtom::wm_take_focus
))
1096 flags
.send_focus_message
= True
;
1097 else if (proto
[i
] == xatom
->getAtom(XAtom::blackbox_structure_messages
))
1098 screen
->addNetizen(new Netizen(screen
, client
.window
));
1107 * Gets the value of the WM_HINTS property.
1108 * If the property is not set, then use a set of default values.
1110 void BlackboxWindow::getWMHints(void) {
1111 focus_mode
= F_Passive
;
1113 // remove from current window group
1114 if (client
.window_group
) {
1115 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1116 if (group
) group
->removeWindow(this);
1118 client
.window_group
= None
;
1120 XWMHints
*wmhint
= XGetWMHints(blackbox
->getXDisplay(), client
.window
);
1125 if (wmhint
->flags
& InputHint
) {
1126 if (wmhint
->input
== True
) {
1127 if (flags
.send_focus_message
)
1128 focus_mode
= F_LocallyActive
;
1130 if (flags
.send_focus_message
)
1131 focus_mode
= F_GloballyActive
;
1133 focus_mode
= F_NoInput
;
1137 if (wmhint
->flags
& StateHint
)
1138 current_state
= wmhint
->initial_state
;
1140 if (wmhint
->flags
& WindowGroupHint
) {
1141 client
.window_group
= wmhint
->window_group
;
1143 // add window to the appropriate group
1144 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1145 if (! group
) { // no group found, create it!
1146 new BWindowGroup(blackbox
, client
.window_group
);
1147 group
= blackbox
->searchGroup(client
.window_group
);
1150 group
->addWindow(this);
1158 * Gets the value of the WM_NORMAL_HINTS property.
1159 * If the property is not set, then use a set of default values.
1161 void BlackboxWindow::getWMNormalHints(void) {
1163 XSizeHints sizehint
;
1165 client
.min_width
= client
.min_height
=
1166 client
.width_inc
= client
.height_inc
= 1;
1167 client
.base_width
= client
.base_height
= 0;
1168 client
.win_gravity
= NorthWestGravity
;
1170 client
.min_aspect_x
= client
.min_aspect_y
=
1171 client
.max_aspect_x
= client
.max_aspect_y
= 1;
1175 use the full screen, not the strut modified size. otherwise when the
1176 availableArea changes max_width/height will be incorrect and lead to odd
1179 const Rect
& screen_area
= screen
->getRect();
1180 client
.max_width
= screen_area
.width();
1181 client
.max_height
= screen_area
.height();
1183 if (! XGetWMNormalHints(blackbox
->getXDisplay(), client
.window
,
1184 &sizehint
, &icccm_mask
))
1187 client
.normal_hint_flags
= sizehint
.flags
;
1189 if (sizehint
.flags
& PMinSize
) {
1190 if (sizehint
.min_width
>= 0)
1191 client
.min_width
= sizehint
.min_width
;
1192 if (sizehint
.min_height
>= 0)
1193 client
.min_height
= sizehint
.min_height
;
1196 if (sizehint
.flags
& PMaxSize
) {
1197 if (sizehint
.max_width
> static_cast<signed>(client
.min_width
))
1198 client
.max_width
= sizehint
.max_width
;
1200 client
.max_width
= client
.min_width
;
1202 if (sizehint
.max_height
> static_cast<signed>(client
.min_height
))
1203 client
.max_height
= sizehint
.max_height
;
1205 client
.max_height
= client
.min_height
;
1208 if (sizehint
.flags
& PResizeInc
) {
1209 client
.width_inc
= sizehint
.width_inc
;
1210 client
.height_inc
= sizehint
.height_inc
;
1213 #if 0 // we do not support this at the moment
1214 if (sizehint
.flags
& PAspect
) {
1215 client
.min_aspect_x
= sizehint
.min_aspect
.x
;
1216 client
.min_aspect_y
= sizehint
.min_aspect
.y
;
1217 client
.max_aspect_x
= sizehint
.max_aspect
.x
;
1218 client
.max_aspect_y
= sizehint
.max_aspect
.y
;
1222 if (sizehint
.flags
& PBaseSize
) {
1223 client
.base_width
= sizehint
.base_width
;
1224 client
.base_height
= sizehint
.base_height
;
1227 if (sizehint
.flags
& PWinGravity
)
1228 client
.win_gravity
= sizehint
.win_gravity
;
1233 * Gets the NETWM hints for the class' contained window.
1235 void BlackboxWindow::getNetWMHints(void) {
1236 unsigned long workspace
;
1238 if (xatom
->getValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1240 if (workspace
== 0xffffffff)
1243 blackbox_attrib
.workspace
= workspace
;
1246 unsigned long *state
;
1247 unsigned long num
= (unsigned) -1;
1248 if (xatom
->getValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
1252 for (unsigned long i
= 0; i
< num
; ++i
) {
1253 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
))
1255 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_shaded
))
1256 flags
.shaded
= True
;
1257 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
))
1258 flags
.skip_taskbar
= True
;
1259 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_pager
))
1260 flags
.skip_pager
= True
;
1261 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_fullscreen
))
1262 flags
.fullscreen
= True
;
1263 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_hidden
))
1264 setState(IconicState
);
1265 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_vert
))
1267 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_horz
))
1271 flags
.maximized
= 1;
1273 flags
.maximized
= 2;
1275 flags
.maximized
= 3;
1283 * Gets the MWM hints for the class' contained window.
1284 * This is used while initializing the window to its first state, and not
1286 * Returns: true if the MWM hints are successfully retreived and applied;
1287 * false if they are not.
1289 void BlackboxWindow::getMWMHints(void) {
1293 num
= PropMwmHintsElements
;
1294 if (! xatom
->getValue(client
.window
, XAtom::motif_wm_hints
,
1295 XAtom::motif_wm_hints
, num
,
1296 (unsigned long **)&mwm_hint
))
1298 if (num
< PropMwmHintsElements
) {
1303 if (mwm_hint
->flags
& MwmHintsDecorations
) {
1304 if (mwm_hint
->decorations
& MwmDecorAll
) {
1305 mwm_decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
1306 Decor_Iconify
| Decor_Maximize
| Decor_Close
;
1308 mwm_decorations
= 0;
1310 if (mwm_hint
->decorations
& MwmDecorBorder
)
1311 mwm_decorations
|= Decor_Border
;
1312 if (mwm_hint
->decorations
& MwmDecorHandle
)
1313 mwm_decorations
|= Decor_Handle
;
1314 if (mwm_hint
->decorations
& MwmDecorTitle
)
1315 mwm_decorations
|= Decor_Titlebar
;
1316 if (mwm_hint
->decorations
& MwmDecorIconify
)
1317 mwm_decorations
|= Decor_Iconify
;
1318 if (mwm_hint
->decorations
& MwmDecorMaximize
)
1319 mwm_decorations
|= Decor_Maximize
;
1323 if (mwm_hint
->flags
& MwmHintsFunctions
) {
1324 if (mwm_hint
->functions
& MwmFuncAll
) {
1325 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
|
1330 if (mwm_hint
->functions
& MwmFuncResize
)
1331 functions
|= Func_Resize
;
1332 if (mwm_hint
->functions
& MwmFuncMove
)
1333 functions
|= Func_Move
;
1334 if (mwm_hint
->functions
& MwmFuncIconify
)
1335 functions
|= Func_Iconify
;
1336 if (mwm_hint
->functions
& MwmFuncMaximize
)
1337 functions
|= Func_Maximize
;
1338 if (mwm_hint
->functions
& MwmFuncClose
)
1339 functions
|= Func_Close
;
1347 * Gets the blackbox hints from the class' contained window.
1348 * This is used while initializing the window to its first state, and not
1350 * Returns: true if the hints are successfully retreived and applied; false if
1353 bool BlackboxWindow::getBlackboxHints(void) {
1355 BlackboxHints
*blackbox_hint
;
1357 num
= PropBlackboxHintsElements
;
1358 if (! xatom
->getValue(client
.window
, XAtom::blackbox_hints
,
1359 XAtom::blackbox_hints
, num
,
1360 (unsigned long **)&blackbox_hint
))
1362 if (num
< PropBlackboxHintsElements
) {
1363 delete [] blackbox_hint
;
1367 if (blackbox_hint
->flags
& AttribShaded
)
1368 flags
.shaded
= (blackbox_hint
->attrib
& AttribShaded
);
1370 if ((blackbox_hint
->flags
& AttribMaxHoriz
) &&
1371 (blackbox_hint
->flags
& AttribMaxVert
))
1372 flags
.maximized
= (blackbox_hint
->attrib
&
1373 (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1374 else if (blackbox_hint
->flags
& AttribMaxVert
)
1375 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxVert
) ? 2 : 0;
1376 else if (blackbox_hint
->flags
& AttribMaxHoriz
)
1377 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1379 if (blackbox_hint
->flags
& AttribOmnipresent
)
1380 flags
.stuck
= (blackbox_hint
->attrib
& AttribOmnipresent
);
1382 if (blackbox_hint
->flags
& AttribWorkspace
)
1383 blackbox_attrib
.workspace
= blackbox_hint
->workspace
;
1385 // if (blackbox_hint->flags & AttribStack)
1386 // don't yet have always on top/bottom for blackbox yet... working
1389 if (blackbox_hint
->flags
& AttribDecoration
) {
1390 switch (blackbox_hint
->decoration
) {
1406 delete [] blackbox_hint
;
1412 void BlackboxWindow::getTransientInfo(void) {
1413 if (client
.transient_for
&&
1414 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1415 // reset transient_for in preparation of looking for a new owner
1416 client
.transient_for
->client
.transientList
.remove(this);
1419 // we have no transient_for until we find a new one
1420 client
.transient_for
= 0;
1423 if (! XGetTransientForHint(blackbox
->getXDisplay(), client
.window
,
1425 // transient_for hint not set
1429 if (trans_for
== client
.window
) {
1430 // wierd client... treat this window as a normal window
1434 if (trans_for
== None
|| trans_for
== screen
->getRootWindow()) {
1435 // this is an undocumented interpretation of the ICCCM. a transient
1436 // associated with None/Root/itself is assumed to be a modal root
1437 // transient. we don't support the concept of a global transient,
1438 // so we just associate this transient with nothing, and perhaps
1439 // we will add support later for global modality.
1440 client
.transient_for
= (BlackboxWindow
*) ~0ul;
1445 client
.transient_for
= blackbox
->searchWindow(trans_for
);
1446 if (! client
.transient_for
&&
1447 client
.window_group
&& trans_for
== client
.window_group
) {
1448 // no direct transient_for, perhaps this is a group transient?
1449 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1450 if (group
) client
.transient_for
= group
->find(screen
);
1453 if (! client
.transient_for
|| client
.transient_for
== this) {
1454 // no transient_for found, or we have a wierd client that wants to be
1455 // a transient for itself, so we treat this window as a normal window
1456 client
.transient_for
= (BlackboxWindow
*) 0;
1460 // Check for a circular transient state: this can lock up Blackbox
1461 // when it tries to find the non-transient window for a transient.
1462 BlackboxWindow
*w
= this;
1463 while(w
->client
.transient_for
&&
1464 w
->client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1465 if(w
->client
.transient_for
== this) {
1466 client
.transient_for
= (BlackboxWindow
*) 0;
1469 w
= w
->client
.transient_for
;
1472 if (client
.transient_for
&&
1473 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1474 // register ourselves with our new transient_for
1475 client
.transient_for
->client
.transientList
.push_back(this);
1476 flags
.stuck
= client
.transient_for
->flags
.stuck
;
1481 BlackboxWindow
*BlackboxWindow::getTransientFor(void) const {
1482 if (client
.transient_for
&&
1483 client
.transient_for
!= (BlackboxWindow
*) ~0ul)
1484 return client
.transient_for
;
1490 * This function is responsible for updating both the client and the frame
1492 * According to the ICCCM a client message is not sent for a resize, only a
1495 void BlackboxWindow::configure(int dx
, int dy
,
1496 unsigned int dw
, unsigned int dh
) {
1497 bool send_event
= ((frame
.rect
.x() != dx
|| frame
.rect
.y() != dy
) &&
1500 if (dw
!= frame
.rect
.width() || dh
!= frame
.rect
.height()) {
1501 frame
.rect
.setRect(dx
, dy
, dw
, dh
);
1502 frame
.inside_w
= frame
.rect
.width() - (frame
.border_w
* 2);
1503 frame
.inside_h
= frame
.rect
.height() - (frame
.border_w
* 2);
1505 if (frame
.rect
.right() <= 0 || frame
.rect
.bottom() <= 0)
1506 frame
.rect
.setPos(0, 0);
1508 client
.rect
.setCoords(frame
.rect
.left() + frame
.margin
.left
,
1509 frame
.rect
.top() + frame
.margin
.top
,
1510 frame
.rect
.right() - frame
.margin
.right
,
1511 frame
.rect
.bottom() - frame
.margin
.bottom
);
1514 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
1521 redrawWindowFrame();
1523 frame
.rect
.setPos(dx
, dy
);
1525 XMoveWindow(blackbox
->getXDisplay(), frame
.window
,
1526 frame
.rect
.x(), frame
.rect
.y());
1528 we may have been called just after an opaque window move, so even though
1529 the old coords match the new ones no ConfigureNotify has been sent yet.
1530 There are likely other times when this will be relevant as well.
1532 if (! flags
.moving
) send_event
= True
;
1536 // if moving, the update and event will occur when the move finishes
1537 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1538 frame
.rect
.top() + frame
.margin
.top
);
1541 event
.type
= ConfigureNotify
;
1543 event
.xconfigure
.display
= blackbox
->getXDisplay();
1544 event
.xconfigure
.event
= client
.window
;
1545 event
.xconfigure
.window
= client
.window
;
1546 event
.xconfigure
.x
= client
.rect
.x();
1547 event
.xconfigure
.y
= client
.rect
.y();
1548 event
.xconfigure
.width
= client
.rect
.width();
1549 event
.xconfigure
.height
= client
.rect
.height();
1550 event
.xconfigure
.border_width
= client
.old_bw
;
1551 event
.xconfigure
.above
= frame
.window
;
1552 event
.xconfigure
.override_redirect
= False
;
1554 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1555 StructureNotifyMask
, &event
);
1556 screen
->updateNetizenConfigNotify(&event
);
1557 XFlush(blackbox
->getXDisplay());
1563 void BlackboxWindow::configureShape(void) {
1564 XShapeCombineShape(blackbox
->getXDisplay(), frame
.window
, ShapeBounding
,
1565 frame
.margin
.left
- frame
.border_w
,
1566 frame
.margin
.top
- frame
.border_w
,
1567 client
.window
, ShapeBounding
, ShapeSet
);
1570 XRectangle xrect
[2];
1572 if (decorations
& Decor_Titlebar
) {
1573 xrect
[0].x
= xrect
[0].y
= -frame
.border_w
;
1574 xrect
[0].width
= frame
.rect
.width();
1575 xrect
[0].height
= frame
.title_h
+ (frame
.border_w
* 2);
1579 if (decorations
& Decor_Handle
) {
1580 xrect
[1].x
= -frame
.border_w
;
1581 xrect
[1].y
= frame
.rect
.height() - frame
.margin
.bottom
+
1582 frame
.mwm_border_w
- frame
.border_w
;
1583 xrect
[1].width
= frame
.rect
.width();
1584 xrect
[1].height
= frame
.handle_h
+ (frame
.border_w
* 2);
1588 XShapeCombineRectangles(blackbox
->getXDisplay(), frame
.window
,
1589 ShapeBounding
, 0, 0, xrect
, num
,
1590 ShapeUnion
, Unsorted
);
1595 bool BlackboxWindow::setInputFocus(void) {
1596 if (flags
.focused
) return True
;
1598 assert(flags
.stuck
|| // window must be on the current workspace or sticky
1599 blackbox_attrib
.workspace
== screen
->getCurrentWorkspaceID());
1602 We only do this check for normal windows and dialogs because other windows
1603 do this on purpose, such as kde's kicker, and we don't want to go moving
1606 if (window_type
== Type_Normal
|| window_type
== Type_Dialog
)
1607 if (! frame
.rect
.intersects(screen
->getRect())) {
1608 // client is outside the screen, move it to the center
1609 configure((screen
->getWidth() - frame
.rect
.width()) / 2,
1610 (screen
->getHeight() - frame
.rect
.height()) / 2,
1611 frame
.rect
.width(), frame
.rect
.height());
1614 if (client
.transientList
.size() > 0) {
1615 // transfer focus to any modal transients
1616 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1617 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1618 if ((*it
)->flags
.modal
) return (*it
)->setInputFocus();
1622 if (focus_mode
== F_LocallyActive
|| focus_mode
== F_Passive
) {
1623 XSetInputFocus(blackbox
->getXDisplay(), client
.window
,
1624 RevertToPointerRoot
, CurrentTime
);
1626 /* we could set the focus to none, since the window doesn't accept focus,
1627 * but we shouldn't set focus to nothing since this would surely make
1633 if (flags
.send_focus_message
) {
1635 ce
.xclient
.type
= ClientMessage
;
1636 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1637 ce
.xclient
.display
= blackbox
->getXDisplay();
1638 ce
.xclient
.window
= client
.window
;
1639 ce
.xclient
.format
= 32;
1640 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_take_focus
);
1641 ce
.xclient
.data
.l
[1] = blackbox
->getLastTime();
1642 ce
.xclient
.data
.l
[2] = 0l;
1643 ce
.xclient
.data
.l
[3] = 0l;
1644 ce
.xclient
.data
.l
[4] = 0l;
1645 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1647 XFlush(blackbox
->getXDisplay());
1654 void BlackboxWindow::iconify(void) {
1655 if (flags
.iconic
) return;
1657 // We don't need to worry about resizing because resizing always grabs the X
1658 // server. This should only ever happen if using opaque moving.
1662 if (windowmenu
) windowmenu
->hide();
1665 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1666 * we need to clear the event mask on client.window for a split second.
1667 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1668 * split second, leaving us with a ghost window... so, we need to do this
1669 * while the X server is grabbed
1671 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1672 StructureNotifyMask
;
1673 XGrabServer(blackbox
->getXDisplay());
1674 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1675 event_mask
& ~StructureNotifyMask
);
1676 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1677 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1678 XUngrabServer(blackbox
->getXDisplay());
1680 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1681 flags
.visible
= False
;
1682 flags
.iconic
= True
;
1684 setState(IconicState
);
1686 screen
->getWorkspace(blackbox_attrib
.workspace
)->removeWindow(this);
1688 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
1689 if (i
!= blackbox_attrib
.workspace
)
1690 screen
->getWorkspace(i
)->removeWindow(this, True
);
1693 if (isTransient()) {
1694 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1695 ! client
.transient_for
->flags
.iconic
) {
1696 // iconify our transient_for
1697 client
.transient_for
->iconify();
1701 screen
->addIcon(this);
1703 if (client
.transientList
.size() > 0) {
1704 // iconify all transients
1705 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1706 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1707 if (! (*it
)->flags
.iconic
) (*it
)->iconify();
1710 screen
->updateStackingList();
1714 void BlackboxWindow::show(void) {
1715 flags
.visible
= True
;
1716 flags
.iconic
= False
;
1718 current_state
= (flags
.shaded
) ? IconicState
: NormalState
;
1719 setState(current_state
);
1721 XMapWindow(blackbox
->getXDisplay(), client
.window
);
1722 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
1723 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
1728 XTranslateCoordinates(blackbox
->getXDisplay(), client
.window
,
1729 screen
->getRootWindow(),
1730 0, 0, &real_x
, &real_y
, &child
);
1731 fprintf(stderr
, "%s -- assumed: (%d, %d), real: (%d, %d)\n", getTitle(),
1732 client
.rect
.left(), client
.rect
.top(), real_x
, real_y
);
1733 assert(client
.rect
.left() == real_x
&& client
.rect
.top() == real_y
);
1738 void BlackboxWindow::deiconify(bool reassoc
, bool raise
) {
1739 if (flags
.iconic
|| reassoc
)
1740 screen
->reassociateWindow(this, BSENTINEL
, False
);
1741 else if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID())
1746 // reassociate and deiconify all transients
1747 if (reassoc
&& client
.transientList
.size() > 0) {
1748 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1749 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1750 (*it
)->deiconify(True
, False
);
1754 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1758 void BlackboxWindow::close(void) {
1760 ce
.xclient
.type
= ClientMessage
;
1761 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1762 ce
.xclient
.display
= blackbox
->getXDisplay();
1763 ce
.xclient
.window
= client
.window
;
1764 ce
.xclient
.format
= 32;
1765 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_delete_window
);
1766 ce
.xclient
.data
.l
[1] = CurrentTime
;
1767 ce
.xclient
.data
.l
[2] = 0l;
1768 ce
.xclient
.data
.l
[3] = 0l;
1769 ce
.xclient
.data
.l
[4] = 0l;
1770 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
, NoEventMask
, &ce
);
1771 XFlush(blackbox
->getXDisplay());
1775 void BlackboxWindow::withdraw(void) {
1776 // We don't need to worry about resizing because resizing always grabs the X
1777 // server. This should only ever happen if using opaque moving.
1781 flags
.visible
= False
;
1782 flags
.iconic
= False
;
1784 setState(current_state
);
1786 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1788 XGrabServer(blackbox
->getXDisplay());
1790 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1791 StructureNotifyMask
;
1792 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1793 event_mask
& ~StructureNotifyMask
);
1794 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1795 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1797 XUngrabServer(blackbox
->getXDisplay());
1799 if (windowmenu
) windowmenu
->hide();
1803 void BlackboxWindow::maximize(unsigned int button
) {
1804 // We don't need to worry about resizing because resizing always grabs the X
1805 // server. This should only ever happen if using opaque moving.
1809 // handle case where menu is open then the max button is used instead
1810 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
1812 if (flags
.maximized
) {
1813 flags
.maximized
= 0;
1815 blackbox_attrib
.flags
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1816 blackbox_attrib
.attrib
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1819 when a resize finishes, maximize(0) is called to clear any maximization
1820 flags currently set. Otherwise it still thinks it is maximized.
1821 so we do not need to call configure() because resizing will handle it
1823 if (! flags
.resizing
)
1824 configure(blackbox_attrib
.premax_x
, blackbox_attrib
.premax_y
,
1825 blackbox_attrib
.premax_w
, blackbox_attrib
.premax_h
);
1827 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
1828 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
1830 redrawAllButtons(); // in case it is not called in configure()
1831 setState(current_state
);
1835 blackbox_attrib
.premax_x
= frame
.rect
.x();
1836 blackbox_attrib
.premax_y
= frame
.rect
.y();
1837 blackbox_attrib
.premax_w
= frame
.rect
.width();
1838 // use client.rect so that clients can be restored even if shaded
1839 blackbox_attrib
.premax_h
=
1840 client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
;
1843 if (screen
->isXineramaActive() && blackbox
->doXineramaMaximizing()) {
1844 // find the area to use
1845 RectList availableAreas
= screen
->allAvailableAreas();
1846 RectList::iterator it
, end
= availableAreas
.end();
1848 for (it
= availableAreas
.begin(); it
!= end
; ++it
)
1849 if (it
->intersects(frame
.rect
)) break;
1850 if (it
== end
) // the window isn't inside an area
1851 it
= availableAreas
.begin(); // so just default to the first one
1853 frame
.changing
= *it
;
1856 frame
.changing
= screen
->availableArea();
1860 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1861 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1865 blackbox_attrib
.flags
|= AttribMaxVert
;
1866 blackbox_attrib
.attrib
|= AttribMaxVert
;
1868 frame
.changing
.setX(frame
.rect
.x());
1869 frame
.changing
.setWidth(frame
.rect
.width());
1873 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1874 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1876 frame
.changing
.setY(frame
.rect
.y());
1877 frame
.changing
.setHeight(frame
.rect
.height());
1884 blackbox_attrib
.flags
^= AttribShaded
;
1885 blackbox_attrib
.attrib
^= AttribShaded
;
1886 flags
.shaded
= False
;
1889 flags
.maximized
= button
;
1891 configure(frame
.changing
.x(), frame
.changing
.y(),
1892 frame
.changing
.width(), frame
.changing
.height());
1894 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1895 redrawAllButtons(); // in case it is not called in configure()
1896 setState(current_state
);
1900 // re-maximizes the window to take into account availableArea changes
1901 void BlackboxWindow::remaximize(void) {
1903 // we only update the window's attributes otherwise we lose the shade bit
1904 switch(flags
.maximized
) {
1906 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1907 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1911 blackbox_attrib
.flags
|= AttribMaxVert
;
1912 blackbox_attrib
.attrib
|= AttribMaxVert
;
1916 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1917 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1923 // save the original dimensions because maximize will wipe them out
1924 int premax_x
= blackbox_attrib
.premax_x
,
1925 premax_y
= blackbox_attrib
.premax_y
,
1926 premax_w
= blackbox_attrib
.premax_w
,
1927 premax_h
= blackbox_attrib
.premax_h
;
1929 unsigned int button
= flags
.maximized
;
1930 flags
.maximized
= 0; // trick maximize() into working
1933 // restore saved values
1934 blackbox_attrib
.premax_x
= premax_x
;
1935 blackbox_attrib
.premax_y
= premax_y
;
1936 blackbox_attrib
.premax_w
= premax_w
;
1937 blackbox_attrib
.premax_h
= premax_h
;
1941 void BlackboxWindow::setWorkspace(unsigned int n
) {
1942 blackbox_attrib
.flags
|= AttribWorkspace
;
1943 blackbox_attrib
.workspace
= n
;
1944 if (n
== BSENTINEL
) { // iconified window
1946 we set the workspace to 'all workspaces' so that taskbars will show the
1947 window. otherwise, it made uniconifying a window imposible without the
1948 blackbox workspace menu
1952 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
, n
);
1956 void BlackboxWindow::shade(void) {
1958 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1959 frame
.inside_w
, frame
.inside_h
);
1960 flags
.shaded
= False
;
1961 blackbox_attrib
.flags
^= AttribShaded
;
1962 blackbox_attrib
.attrib
^= AttribShaded
;
1964 setState(NormalState
);
1966 // set the frame rect to the normal size
1967 frame
.rect
.setHeight(client
.rect
.height() + frame
.margin
.top
+
1968 frame
.margin
.bottom
);
1970 if (! (decorations
& Decor_Titlebar
))
1971 return; // can't shade it without a titlebar!
1973 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1974 frame
.inside_w
, frame
.title_h
);
1975 flags
.shaded
= True
;
1976 blackbox_attrib
.flags
|= AttribShaded
;
1977 blackbox_attrib
.attrib
|= AttribShaded
;
1979 setState(IconicState
);
1981 // set the frame rect to the shaded size
1982 frame
.rect
.setHeight(frame
.title_h
+ (frame
.border_w
* 2));
1988 * (Un)Sticks a window and its relatives.
1990 void BlackboxWindow::stick(void) {
1992 blackbox_attrib
.flags
^= AttribOmnipresent
;
1993 blackbox_attrib
.attrib
^= AttribOmnipresent
;
1995 flags
.stuck
= False
;
1997 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
1998 if (i
!= blackbox_attrib
.workspace
)
1999 screen
->getWorkspace(i
)->removeWindow(this, True
);
2002 screen
->reassociateWindow(this, BSENTINEL
, True
);
2003 // temporary fix since sticky windows suck. set the hint to what we
2004 // actually hold in our data.
2005 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
2006 blackbox_attrib
.workspace
);
2008 setState(current_state
);
2012 blackbox_attrib
.flags
|= AttribOmnipresent
;
2013 blackbox_attrib
.attrib
|= AttribOmnipresent
;
2015 // temporary fix since sticky windows suck. set the hint to a different
2016 // value than that contained in the class' data.
2017 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
2020 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
2021 if (i
!= blackbox_attrib
.workspace
)
2022 screen
->getWorkspace(i
)->addWindow(this, False
, True
);
2024 setState(current_state
);
2027 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
2028 client
.transient_for
->isStuck() != flags
.stuck
)
2029 client
.transient_for
->stick();
2030 // go down the chain
2031 BlackboxWindowList::iterator it
;
2032 const BlackboxWindowList::iterator end
= client
.transientList
.end();
2033 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
2034 if ((*it
)->isStuck() != flags
.stuck
)
2039 void BlackboxWindow::redrawWindowFrame(void) const {
2040 if (decorations
& Decor_Titlebar
) {
2041 if (flags
.focused
) {
2043 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2044 frame
.title
, frame
.ftitle
);
2046 XSetWindowBackground(blackbox
->getXDisplay(),
2047 frame
.title
, frame
.ftitle_pixel
);
2050 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2051 frame
.title
, frame
.utitle
);
2053 XSetWindowBackground(blackbox
->getXDisplay(),
2054 frame
.title
, frame
.utitle_pixel
);
2056 XClearWindow(blackbox
->getXDisplay(), frame
.title
);
2062 if (decorations
& Decor_Handle
) {
2063 if (flags
.focused
) {
2065 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2066 frame
.handle
, frame
.fhandle
);
2068 XSetWindowBackground(blackbox
->getXDisplay(),
2069 frame
.handle
, frame
.fhandle_pixel
);
2072 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2073 frame
.left_grip
, frame
.fgrip
);
2074 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2075 frame
.right_grip
, frame
.fgrip
);
2077 XSetWindowBackground(blackbox
->getXDisplay(),
2078 frame
.left_grip
, frame
.fgrip_pixel
);
2079 XSetWindowBackground(blackbox
->getXDisplay(),
2080 frame
.right_grip
, frame
.fgrip_pixel
);
2084 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2085 frame
.handle
, frame
.uhandle
);
2087 XSetWindowBackground(blackbox
->getXDisplay(),
2088 frame
.handle
, frame
.uhandle_pixel
);
2091 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2092 frame
.left_grip
, frame
.ugrip
);
2093 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2094 frame
.right_grip
, frame
.ugrip
);
2096 XSetWindowBackground(blackbox
->getXDisplay(),
2097 frame
.left_grip
, frame
.ugrip_pixel
);
2098 XSetWindowBackground(blackbox
->getXDisplay(),
2099 frame
.right_grip
, frame
.ugrip_pixel
);
2102 XClearWindow(blackbox
->getXDisplay(), frame
.handle
);
2103 XClearWindow(blackbox
->getXDisplay(), frame
.left_grip
);
2104 XClearWindow(blackbox
->getXDisplay(), frame
.right_grip
);
2107 if (decorations
& Decor_Border
) {
2109 XSetWindowBorder(blackbox
->getXDisplay(),
2110 frame
.plate
, frame
.fborder_pixel
);
2112 XSetWindowBorder(blackbox
->getXDisplay(),
2113 frame
.plate
, frame
.uborder_pixel
);
2118 void BlackboxWindow::setFocusFlag(bool focus
) {
2119 // only focus a window if it is visible
2120 if (focus
&& ! flags
.visible
)
2123 flags
.focused
= focus
;
2125 redrawWindowFrame();
2128 blackbox
->setFocusedWindow(this);
2130 if (! flags
.iconic
) {
2131 // iconic windows arent in a workspace menu!
2133 screen
->getCurrentWorkspace()->setFocused(this, isFocused());
2135 screen
->getWorkspace(blackbox_attrib
.workspace
)->
2136 setFocused(this, flags
.focused
);
2141 void BlackboxWindow::installColormap(bool install
) {
2142 int i
= 0, ncmap
= 0;
2143 Colormap
*cmaps
= XListInstalledColormaps(blackbox
->getXDisplay(),
2144 client
.window
, &ncmap
);
2146 XWindowAttributes wattrib
;
2147 if (XGetWindowAttributes(blackbox
->getXDisplay(),
2148 client
.window
, &wattrib
)) {
2150 // install the window's colormap
2151 for (i
= 0; i
< ncmap
; i
++) {
2152 if (*(cmaps
+ i
) == wattrib
.colormap
)
2153 // this window is using an installed color map... do not install
2156 // otherwise, install the window's colormap
2158 XInstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2160 // uninstall the window's colormap
2161 for (i
= 0; i
< ncmap
; i
++) {
2162 if (*(cmaps
+ i
) == wattrib
.colormap
)
2163 // we found the colormap to uninstall
2164 XUninstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2174 void BlackboxWindow::setAllowedActions(void) {
2178 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_shade
);
2179 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_change_desktop
);
2180 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_close
);
2182 if (functions
& Func_Move
)
2183 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_move
);
2184 if (functions
& Func_Resize
)
2185 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_resize
);
2186 if (functions
& Func_Maximize
) {
2187 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_horz
);
2188 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_vert
);
2191 xatom
->setValue(client
.window
, XAtom::net_wm_allowed_actions
, XAtom::atom
,
2196 void BlackboxWindow::setState(unsigned long new_state
) {
2197 current_state
= new_state
;
2199 unsigned long state
[2];
2200 state
[0] = current_state
;
2202 xatom
->setValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
, state
, 2);
2204 xatom
->setValue(client
.window
, XAtom::blackbox_attributes
,
2205 XAtom::blackbox_attributes
, (unsigned long *)&blackbox_attrib
,
2206 PropBlackboxAttributesElements
);
2211 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_modal
);
2213 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_shaded
);
2215 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_hidden
);
2216 if (flags
.skip_taskbar
)
2217 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
);
2218 if (flags
.skip_pager
)
2219 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_pager
);
2220 if (flags
.fullscreen
)
2221 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_fullscreen
);
2222 if (flags
.maximized
== 1 || flags
.maximized
== 2)
2223 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_vert
);
2224 if (flags
.maximized
== 1 || flags
.maximized
== 3)
2225 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_horz
);
2226 xatom
->setValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
2231 bool BlackboxWindow::getState(void) {
2232 bool ret
= xatom
->getValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
,
2234 if (! ret
) current_state
= 0;
2239 void BlackboxWindow::restoreAttributes(void) {
2240 unsigned long num
= PropBlackboxAttributesElements
;
2241 BlackboxAttributes
*net
;
2242 if (! xatom
->getValue(client
.window
, XAtom::blackbox_attributes
,
2243 XAtom::blackbox_attributes
, num
,
2244 (unsigned long **)&net
))
2246 if (num
< PropBlackboxAttributesElements
) {
2251 if (net
->flags
& AttribShaded
&& net
->attrib
& AttribShaded
) {
2252 flags
.shaded
= False
;
2253 unsigned long orig_state
= current_state
;
2257 At this point in the life of a window, current_state should only be set
2258 to IconicState if the window was an *icon*, not if it was shaded.
2260 if (orig_state
!= IconicState
)
2261 current_state
= WithdrawnState
;
2264 if (net
->workspace
!= screen
->getCurrentWorkspaceID() &&
2265 net
->workspace
< screen
->getWorkspaceCount())
2266 screen
->reassociateWindow(this, net
->workspace
, True
);
2268 if ((blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID()) &&
2269 (blackbox_attrib
.workspace
< screen
->getWorkspaceCount())) {
2270 // set to WithdrawnState so it will be mapped on the new workspace
2271 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2272 } else if (current_state
== WithdrawnState
) {
2273 // the window is on this workspace and is Withdrawn, so it is waiting to
2275 current_state
= NormalState
;
2278 if (net
->flags
& AttribOmnipresent
&& net
->attrib
& AttribOmnipresent
&&
2282 // if the window was on another workspace, it was going to be hidden. this
2283 // specifies that the window should be mapped since it is sticky.
2284 if (current_state
== WithdrawnState
) current_state
= NormalState
;
2287 if (net
->flags
& AttribMaxHoriz
|| net
->flags
& AttribMaxVert
) {
2288 int x
= net
->premax_x
, y
= net
->premax_y
;
2289 unsigned int w
= net
->premax_w
, h
= net
->premax_h
;
2290 flags
.maximized
= 0;
2293 if ((net
->flags
& AttribMaxHoriz
) &&
2294 (net
->flags
& AttribMaxVert
))
2295 m
= (net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
2296 else if (net
->flags
& AttribMaxVert
)
2297 m
= (net
->attrib
& AttribMaxVert
) ? 2 : 0;
2298 else if (net
->flags
& AttribMaxHoriz
)
2299 m
= (net
->attrib
& AttribMaxHoriz
) ? 3 : 0;
2303 blackbox_attrib
.premax_x
= x
;
2304 blackbox_attrib
.premax_y
= y
;
2305 blackbox_attrib
.premax_w
= w
;
2306 blackbox_attrib
.premax_h
= h
;
2309 if (net
->flags
& AttribDecoration
) {
2310 switch (net
->decoration
) {
2315 /* since tools only let you toggle this anyways, we'll just make that all
2316 it supports for now.
2326 // we can not be shaded if we lack a titlebar
2327 if (! (decorations
& Decor_Titlebar
) && flags
.shaded
)
2330 if (flags
.visible
&& frame
.window
) {
2331 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
2332 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
2336 setState(current_state
);
2339 // with the state set it will then be the map event's job to read the
2340 // window's state and behave accordingly
2347 * Positions the Rect r according the the client window position and
2350 void BlackboxWindow::applyGravity(Rect
&r
) {
2351 // apply horizontal window gravity
2352 switch (client
.win_gravity
) {
2354 case NorthWestGravity
:
2355 case SouthWestGravity
:
2357 r
.setX(client
.rect
.x());
2363 r
.setX(client
.rect
.x() - (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2366 case NorthEastGravity
:
2367 case SouthEastGravity
:
2369 r
.setX(client
.rect
.x() - frame
.margin
.left
- frame
.margin
.right
+ 2);
2374 r
.setX(client
.rect
.x() - frame
.margin
.left
);
2378 // apply vertical window gravity
2379 switch (client
.win_gravity
) {
2381 case NorthWestGravity
:
2382 case NorthEastGravity
:
2384 r
.setY(client
.rect
.y());
2390 r
.setY(client
.rect
.y() - (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2393 case SouthWestGravity
:
2394 case SouthEastGravity
:
2396 r
.setY(client
.rect
.y() - frame
.margin
.top
- frame
.margin
.bottom
+ 2);
2401 r
.setY(client
.rect
.y() - frame
.margin
.top
);
2408 * The reverse of the applyGravity function.
2410 * Positions the Rect r according to the frame window position and
2413 void BlackboxWindow::restoreGravity(Rect
&r
) {
2414 // restore horizontal window gravity
2415 switch (client
.win_gravity
) {
2417 case NorthWestGravity
:
2418 case SouthWestGravity
:
2420 r
.setX(frame
.rect
.x());
2426 r
.setX(frame
.rect
.x() + (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2429 case NorthEastGravity
:
2430 case SouthEastGravity
:
2432 r
.setX(frame
.rect
.x() + frame
.margin
.left
+ frame
.margin
.right
- 2);
2437 r
.setX(frame
.rect
.x() + frame
.margin
.left
);
2441 // restore vertical window gravity
2442 switch (client
.win_gravity
) {
2444 case NorthWestGravity
:
2445 case NorthEastGravity
:
2447 r
.setY(frame
.rect
.y());
2453 r
.setY(frame
.rect
.y() + (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2456 case SouthWestGravity
:
2457 case SouthEastGravity
:
2459 r
.setY(frame
.rect
.y() + frame
.margin
.top
+ frame
.margin
.bottom
- 2);
2464 r
.setY(frame
.rect
.y() + frame
.margin
.top
);
2470 void BlackboxWindow::redrawLabel(void) const {
2471 if (flags
.focused
) {
2473 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2474 frame
.label
, frame
.flabel
);
2476 XSetWindowBackground(blackbox
->getXDisplay(),
2477 frame
.label
, frame
.flabel_pixel
);
2480 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2481 frame
.label
, frame
.ulabel
);
2483 XSetWindowBackground(blackbox
->getXDisplay(),
2484 frame
.label
, frame
.ulabel_pixel
);
2486 XClearWindow(blackbox
->getXDisplay(), frame
.label
);
2488 WindowStyle
*style
= screen
->getWindowStyle();
2490 int pos
= frame
.bevel_w
* 2;
2491 style
->doJustify(client
.title
.c_str(), pos
, frame
.label_w
, frame
.bevel_w
* 4);
2492 style
->font
->drawString(frame
.label
, pos
, 1,
2493 (flags
.focused
? style
->l_text_focus
:
2494 style
->l_text_unfocus
),
2499 void BlackboxWindow::redrawAllButtons(void) const {
2500 if (frame
.iconify_button
) redrawIconifyButton(False
);
2501 if (frame
.maximize_button
) redrawMaximizeButton(flags
.maximized
);
2502 if (frame
.close_button
) redrawCloseButton(False
);
2506 void BlackboxWindow::redrawIconifyButton(bool pressed
) const {
2508 if (flags
.focused
) {
2510 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2511 frame
.iconify_button
, frame
.fbutton
);
2513 XSetWindowBackground(blackbox
->getXDisplay(),
2514 frame
.iconify_button
, frame
.fbutton_pixel
);
2517 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2518 frame
.iconify_button
, frame
.ubutton
);
2520 XSetWindowBackground(blackbox
->getXDisplay(), frame
.iconify_button
,
2521 frame
.ubutton_pixel
);
2525 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2526 frame
.iconify_button
, frame
.pbutton
);
2528 XSetWindowBackground(blackbox
->getXDisplay(),
2529 frame
.iconify_button
, frame
.pbutton_pixel
);
2531 XClearWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
2533 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2534 screen
->getWindowStyle()->b_pic_unfocus
);
2535 XDrawRectangle(blackbox
->getXDisplay(), frame
.iconify_button
, pen
.gc(),
2536 2, (frame
.button_w
- 5), (frame
.button_w
- 5), 2);
2540 void BlackboxWindow::redrawMaximizeButton(bool pressed
) const {
2542 if (flags
.focused
) {
2544 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2545 frame
.maximize_button
, frame
.fbutton
);
2547 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2548 frame
.fbutton_pixel
);
2551 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2552 frame
.maximize_button
, frame
.ubutton
);
2554 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2555 frame
.ubutton_pixel
);
2559 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2560 frame
.maximize_button
, frame
.pbutton
);
2562 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2563 frame
.pbutton_pixel
);
2565 XClearWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
2567 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2568 screen
->getWindowStyle()->b_pic_unfocus
);
2569 XDrawRectangle(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2570 2, 2, (frame
.button_w
- 5), (frame
.button_w
- 5));
2571 XDrawLine(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2572 2, 3, (frame
.button_w
- 3), 3);
2576 void BlackboxWindow::redrawCloseButton(bool pressed
) const {
2578 if (flags
.focused
) {
2580 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2583 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2584 frame
.fbutton_pixel
);
2587 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2590 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2591 frame
.ubutton_pixel
);
2595 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2596 frame
.close_button
, frame
.pbutton
);
2598 XSetWindowBackground(blackbox
->getXDisplay(),
2599 frame
.close_button
, frame
.pbutton_pixel
);
2601 XClearWindow(blackbox
->getXDisplay(), frame
.close_button
);
2603 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2604 screen
->getWindowStyle()->b_pic_unfocus
);
2605 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2606 2, 2, (frame
.button_w
- 3), (frame
.button_w
- 3));
2607 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2608 2, (frame
.button_w
- 3), (frame
.button_w
- 3), 2);
2612 void BlackboxWindow::mapRequestEvent(const XMapRequestEvent
*re
) {
2613 if (re
->window
!= client
.window
)
2617 fprintf(stderr
, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2621 switch (current_state
) {
2626 case WithdrawnState
:
2635 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2637 if (! blackbox
->isStartup()) {
2638 XSync(blackbox
->getXDisplay(), False
); // make sure the frame is mapped
2639 if (screen
->doFocusNew()|| (isTransient() && getTransientFor() &&
2640 getTransientFor()->isFocused())) {
2643 if (screen
->getPlacementPolicy() == BScreen::ClickMousePlacement
) {
2647 XQueryPointer(blackbox
->getXDisplay(), screen
->getRootWindow(),
2648 &r
, &c
, &rx
, &ry
, &x
, &y
, &m
);
2658 void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent
*ue
) {
2659 if (ue
->window
!= client
.window
)
2663 fprintf(stderr
, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2667 screen
->unmanageWindow(this, False
);
2671 void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent
*de
) {
2672 if (de
->window
!= client
.window
)
2676 fprintf(stderr
, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2680 screen
->unmanageWindow(this, False
);
2684 void BlackboxWindow::reparentNotifyEvent(const XReparentEvent
*re
) {
2685 if (re
->window
!= client
.window
|| re
->parent
== frame
.plate
)
2689 fprintf(stderr
, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2690 "0x%lx.\n", client
.window
, re
->parent
);
2695 XPutBackEvent(blackbox
->getXDisplay(), &ev
);
2696 screen
->unmanageWindow(this, True
);
2700 void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent
*pe
) {
2701 if (pe
->state
== PropertyDelete
)
2705 fprintf(stderr
, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n",
2711 case XA_WM_CLIENT_MACHINE
:
2715 case XA_WM_TRANSIENT_FOR
: {
2716 // determine if this is a transient window
2719 // adjust the window decorations based on transience
2720 if (isTransient()) {
2721 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2722 functions
&= ~Func_Maximize
;
2723 setAllowedActions();
2734 case XA_WM_ICON_NAME
:
2736 if (flags
.iconic
) screen
->propagateWindowName(this);
2739 case XAtom::net_wm_name
:
2743 if (decorations
& Decor_Titlebar
)
2746 screen
->propagateWindowName(this);
2749 case XA_WM_NORMAL_HINTS
: {
2752 if ((client
.normal_hint_flags
& PMinSize
) &&
2753 (client
.normal_hint_flags
& PMaxSize
)) {
2754 // the window now can/can't resize itself, so the buttons need to be
2757 if (client
.max_width
<= client
.min_width
&&
2758 client
.max_height
<= client
.min_height
) {
2759 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2760 functions
&= ~(Func_Resize
| Func_Maximize
);
2762 if (! isTransient()) {
2763 decorations
|= Decor_Maximize
| Decor_Handle
;
2764 functions
|= Func_Maximize
;
2766 functions
|= Func_Resize
;
2769 setAllowedActions();
2772 Rect old_rect
= frame
.rect
;
2776 if (old_rect
!= frame
.rect
)
2783 if (pe
->atom
== xatom
->getAtom(XAtom::wm_protocols
)) {
2786 if ((decorations
& Decor_Close
) && (! frame
.close_button
)) {
2787 createCloseButton();
2788 if (decorations
& Decor_Titlebar
) {
2789 positionButtons(True
);
2790 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
2792 if (windowmenu
) windowmenu
->reconfigure();
2794 } else if (pe
->atom
== xatom
->getAtom(XAtom::net_wm_strut
)) {
2803 void BlackboxWindow::exposeEvent(const XExposeEvent
*ee
) {
2805 fprintf(stderr
, "BlackboxWindow::exposeEvent() for 0x%lx\n", client
.window
);
2808 if (frame
.label
== ee
->window
&& (decorations
& Decor_Titlebar
))
2810 else if (frame
.close_button
== ee
->window
)
2811 redrawCloseButton(False
);
2812 else if (frame
.maximize_button
== ee
->window
)
2813 redrawMaximizeButton(flags
.maximized
);
2814 else if (frame
.iconify_button
== ee
->window
)
2815 redrawIconifyButton(False
);
2819 void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent
*cr
) {
2820 if (cr
->window
!= client
.window
|| flags
.iconic
)
2823 if (cr
->value_mask
& CWBorderWidth
)
2824 client
.old_bw
= cr
->border_width
;
2826 if (cr
->value_mask
& (CWX
| CWY
| CWWidth
| CWHeight
)) {
2827 Rect req
= frame
.rect
;
2829 if (cr
->value_mask
& (CWX
| CWY
)) {
2830 if (cr
->value_mask
& CWX
)
2831 client
.rect
.setX(cr
->x
);
2832 if (cr
->value_mask
& CWY
)
2833 client
.rect
.setY(cr
->y
);
2838 if (cr
->value_mask
& CWWidth
)
2839 req
.setWidth(cr
->width
+ frame
.margin
.left
+ frame
.margin
.right
);
2841 if (cr
->value_mask
& CWHeight
)
2842 req
.setHeight(cr
->height
+ frame
.margin
.top
+ frame
.margin
.bottom
);
2844 configure(req
.x(), req
.y(), req
.width(), req
.height());
2847 if (cr
->value_mask
& CWStackMode
&& !isDesktop()) {
2848 switch (cr
->detail
) {
2851 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2857 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2864 void BlackboxWindow::buttonPressEvent(const XButtonEvent
*be
) {
2866 fprintf(stderr
, "BlackboxWindow::buttonPressEvent() for 0x%lx\n",
2870 if (frame
.maximize_button
== be
->window
&& be
->button
<= 3) {
2871 redrawMaximizeButton(True
);
2872 } else if (be
->button
== 1 || (be
->button
== 3 && be
->state
== ModMask
)) {
2873 if (! flags
.focused
)
2876 if (frame
.iconify_button
== be
->window
) {
2877 redrawIconifyButton(True
);
2878 } else if (frame
.close_button
== be
->window
) {
2879 redrawCloseButton(True
);
2880 } else if (frame
.plate
== be
->window
) {
2881 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2883 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2885 XAllowEvents(blackbox
->getXDisplay(), ReplayPointer
, be
->time
);
2887 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
2888 if (((be
->time
- lastButtonPressTime
) <=
2889 blackbox
->getDoubleClickInterval()) ||
2890 (be
->state
== ControlMask
)) {
2891 lastButtonPressTime
= 0;
2894 lastButtonPressTime
= be
->time
;
2898 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2900 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2902 } else if (be
->button
== 2 && (be
->window
!= frame
.iconify_button
) &&
2903 (be
->window
!= frame
.close_button
)) {
2904 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2905 } else if (windowmenu
&& be
->button
== 3 &&
2906 (frame
.title
== be
->window
|| frame
.label
== be
->window
||
2907 frame
.handle
== be
->window
|| frame
.window
== be
->window
)) {
2908 if (windowmenu
->isVisible()) {
2911 int mx
= be
->x_root
- windowmenu
->getWidth() / 2,
2912 my
= be
->y_root
- windowmenu
->getHeight() / 2;
2914 // snap the window menu into a corner/side if necessary
2915 int left_edge
, right_edge
, top_edge
, bottom_edge
;
2918 the " + (frame.border_w * 2) - 1" bits are to get the proper width
2919 and height of the menu, as the sizes returned by it do not include
2922 left_edge
= frame
.rect
.x();
2923 right_edge
= frame
.rect
.right() -
2924 (windowmenu
->getWidth() + (frame
.border_w
* 2) - 1);
2925 top_edge
= client
.rect
.top() - (frame
.border_w
+ frame
.mwm_border_w
);
2926 bottom_edge
= client
.rect
.bottom() -
2927 (windowmenu
->getHeight() + (frame
.border_w
* 2) - 1) +
2928 (frame
.border_w
+ frame
.mwm_border_w
);
2932 if (mx
> right_edge
)
2936 if (my
> bottom_edge
)
2939 windowmenu
->move(mx
, my
);
2941 XRaiseWindow(blackbox
->getXDisplay(), windowmenu
->getWindowID());
2942 XRaiseWindow(blackbox
->getXDisplay(),
2943 windowmenu
->getSendToMenu()->getWindowID());
2946 } else if (be
->button
== 4) {
2947 if ((be
->window
== frame
.label
||
2948 be
->window
== frame
.title
||
2949 be
->window
== frame
.maximize_button
||
2950 be
->window
== frame
.iconify_button
||
2951 be
->window
== frame
.close_button
) &&
2955 } else if (be
->button
== 5) {
2956 if ((be
->window
== frame
.label
||
2957 be
->window
== frame
.title
||
2958 be
->window
== frame
.maximize_button
||
2959 be
->window
== frame
.iconify_button
||
2960 be
->window
== frame
.close_button
) &&
2967 void BlackboxWindow::buttonReleaseEvent(const XButtonEvent
*re
) {
2969 fprintf(stderr
, "BlackboxWindow::buttonReleaseEvent() for 0x%lx\n",
2973 if (re
->window
== frame
.maximize_button
&&
2974 re
->button
>= 1 && re
->button
<= 3) {
2975 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2976 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2977 maximize(re
->button
);
2979 redrawMaximizeButton(flags
.maximized
);
2981 } else if (re
->window
== frame
.iconify_button
&& re
->button
== 1) {
2982 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2983 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2986 redrawIconifyButton(False
);
2988 } else if (re
->window
== frame
.close_button
& re
->button
== 1) {
2989 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2990 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
)))
2992 redrawCloseButton(False
);
2993 } else if (flags
.moving
) {
2995 } else if (flags
.resizing
) {
2997 } else if (re
->window
== frame
.window
) {
2998 if (re
->button
== 2 && re
->state
== ModMask
)
2999 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3005 void BlackboxWindow::beginMove(int x_root
, int y_root
) {
3006 assert(! (flags
.resizing
|| flags
.moving
));
3009 Only one window can be moved/resized at a time. If another window is already
3010 being moved or resized, then stop it before whating to work with this one.
3012 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3013 if (changing
&& changing
!= this) {
3014 if (changing
->flags
.moving
)
3015 changing
->endMove();
3016 else // if (changing->flags.resizing)
3017 changing
->endResize();
3020 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3021 PointerMotionMask
| ButtonReleaseMask
,
3022 GrabModeAsync
, GrabModeAsync
,
3023 None
, blackbox
->getMoveCursor(), CurrentTime
);
3025 if (windowmenu
&& windowmenu
->isVisible())
3028 flags
.moving
= True
;
3029 blackbox
->setChangingWindow(this);
3031 if (! screen
->doOpaqueMove()) {
3032 XGrabServer(blackbox
->getXDisplay());
3034 frame
.changing
= frame
.rect
;
3035 screen
->showPosition(frame
.changing
.x(), frame
.changing
.y());
3037 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3041 frame
.changing
.width() - 1,
3042 frame
.changing
.height() - 1);
3045 frame
.grab_x
= x_root
- frame
.rect
.x() - frame
.border_w
;
3046 frame
.grab_y
= y_root
- frame
.rect
.y() - frame
.border_w
;
3050 void BlackboxWindow::doMove(int x_root
, int y_root
) {
3051 assert(flags
.moving
);
3052 assert(blackbox
->getChangingWindow() == this);
3054 int dx
= x_root
- frame
.grab_x
, dy
= y_root
- frame
.grab_y
;
3055 dx
-= frame
.border_w
;
3056 dy
-= frame
.border_w
;
3058 if (screen
->doWorkspaceWarping())
3059 if (doWorkspaceWarping(x_root
, y_root
, dx
, dy
))
3062 doWindowSnapping(dx
, dy
);
3064 if (screen
->doOpaqueMove()) {
3065 configure(dx
, dy
, frame
.rect
.width(), frame
.rect
.height());
3067 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3071 frame
.changing
.width() - 1,
3072 frame
.changing
.height() - 1);
3074 frame
.changing
.setPos(dx
, dy
);
3076 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3080 frame
.changing
.width() - 1,
3081 frame
.changing
.height() - 1);
3084 screen
->showPosition(dx
, dy
);
3088 bool BlackboxWindow::doWorkspaceWarping(int x_root
, int y_root
,
3090 // workspace warping
3092 unsigned int dest
= screen
->getCurrentWorkspaceID();
3096 if (dest
> 0) dest
--;
3097 else dest
= screen
->getNumberOfWorkspaces() - 1;
3099 } else if (x_root
>= screen
->getRect().right()) {
3102 if (dest
< screen
->getNumberOfWorkspaces() - 1) dest
++;
3109 bool focus
= flags
.focused
; // had focus while moving?
3111 screen
->reassociateWindow(this, dest
, False
);
3112 screen
->changeWorkspaceID(dest
);
3117 We grab the X server here because we are moving the window and then the
3118 mouse cursor. When one moves, it could end up putting the mouse cursor
3119 over another window for a moment. This can cause the warp to iniate a
3120 move on another window.
3122 XGrabServer(blackbox
->getXDisplay());
3125 dest_x
= screen
->getRect().right() - 1;
3126 configure(dx
+ (screen
->getRect().width() - 1), dy
,
3127 frame
.rect
.width(), frame
.rect
.height());
3130 configure(dx
- (screen
->getRect().width() - 1), dy
,
3131 frame
.rect
.width(), frame
.rect
.height());
3133 XWarpPointer(blackbox
->getXDisplay(), None
,
3134 screen
->getRootWindow(), 0, 0, 0, 0,
3136 XUngrabServer(blackbox
->getXDisplay());
3138 beginMove(dest_x
, y_root
);
3143 void BlackboxWindow::doWindowSnapping(int &dx
, int &dy
) {
3144 // how much resistance to edges to provide
3145 const int resistance_size
= screen
->getResistanceSize();
3147 // how far away to snap
3148 const int snap_distance
= screen
->getSnapThreshold();
3150 // how to snap windows
3151 const int snap_to_windows
= screen
->getWindowToWindowSnap();
3152 const int snap_to_edges
= screen
->getWindowToEdgeSnap();
3153 // the amount of space away from the edge to provide resistance/snap
3154 const int snap_offset
= screen
->getSnapOffset();
3156 // find the geomeetery where the moving window currently is
3157 const Rect
&moving
= screen
->doOpaqueMove() ? frame
.rect
: frame
.changing
;
3160 const int wleft
= dx
,
3161 wright
= dx
+ frame
.rect
.width() - 1,
3163 wbottom
= dy
+ frame
.rect
.height() - 1;
3165 if (snap_to_windows
) {
3168 Workspace
*w
= screen
->getWorkspace(getWorkspaceNumber());
3171 // add windows on the workspace to the rect list
3172 const BlackboxWindowList
& stack_list
= w
->getStackingList();
3173 BlackboxWindowList::const_iterator st_it
, st_end
= stack_list
.end();
3174 for (st_it
= stack_list
.begin(); st_it
!= st_end
; ++st_it
)
3175 if (*st_it
!= this) // don't snap to ourself
3176 rectlist
.push_back( (*st_it
)->frameRect() );
3178 // add the toolbar and the slit to the rect list.
3179 // (only if they are not hidden)
3180 Toolbar
*tbar
= screen
->getToolbar();
3181 Slit
*slit
= screen
->getSlit();
3182 Rect tbar_rect
, slit_rect
;
3183 unsigned int bwidth
= screen
->getBorderWidth() * 2;
3185 if (! (screen
->doHideToolbar() || tbar
->isHidden())) {
3186 tbar_rect
.setRect(tbar
->getX(), tbar
->getY(), tbar
->getWidth() + bwidth
,
3187 tbar
->getHeight() + bwidth
);
3188 rectlist
.push_back(tbar_rect
);
3191 if (! slit
->isHidden()) {
3192 slit_rect
.setRect(slit
->getX(), slit
->getY(), slit
->getWidth() + bwidth
,
3193 slit
->getHeight() + bwidth
);
3194 rectlist
.push_back(slit_rect
);
3197 RectList::const_iterator it
, end
= rectlist
.end();
3198 for (it
= rectlist
.begin(); it
!= end
; ++it
) {
3199 bool snapped
= False
;
3200 const Rect
&winrect
= *it
;
3202 offsetrect
.setCoords(winrect
.left() - snap_offset
,
3203 winrect
.top() - snap_offset
,
3204 winrect
.right() + snap_offset
,
3205 winrect
.bottom() + snap_offset
);
3207 if (snap_to_windows
== BScreen::WindowResistance
)
3208 // if the window is already over top of this snap target, then
3209 // resistance is futile, so just ignore it
3210 if (winrect
.intersects(moving
))
3213 int dleft
, dright
, dtop
, dbottom
;
3215 // if the windows are in the same plane vertically
3216 if (wtop
>= (signed)(winrect
.y() - frame
.rect
.height() + 1) &&
3217 wtop
< (signed)(winrect
.y() + winrect
.height() - 1)) {
3219 if (snap_to_windows
== BScreen::WindowResistance
) {
3220 dleft
= wright
- offsetrect
.left();
3221 dright
= offsetrect
.right() - wleft
;
3223 // snap left of other window?
3224 if (dleft
>= 0 && dleft
< resistance_size
&&
3225 dleft
< (wright
- wleft
)) {
3226 dx
= offsetrect
.left() - frame
.rect
.width();
3229 // snap right of other window?
3230 else if (dright
>= 0 && dright
< resistance_size
&&
3231 dright
< (wright
- wleft
)) {
3232 dx
= offsetrect
.right() + 1;
3235 } else { // BScreen::WindowSnap
3236 dleft
= abs(wright
- offsetrect
.left());
3237 dright
= abs(wleft
- offsetrect
.right());
3239 // snap left of other window?
3240 if (dleft
< snap_distance
&& dleft
<= dright
) {
3241 dx
= offsetrect
.left() - frame
.rect
.width();
3244 // snap right of other window?
3245 else if (dright
< snap_distance
) {
3246 dx
= offsetrect
.right() + 1;
3252 if (screen
->getWindowCornerSnap()) {
3253 // try corner-snap to its other sides
3254 if (snap_to_windows
== BScreen::WindowResistance
) {
3255 dtop
= winrect
.top() - wtop
;
3256 dbottom
= wbottom
- winrect
.bottom();
3257 if (dtop
> 0 && dtop
< resistance_size
) {
3258 // if we're already past the top edge, then don't provide
3260 if (moving
.top() >= winrect
.top())
3262 } else if (dbottom
> 0 && dbottom
< resistance_size
) {
3263 // if we're already past the bottom edge, then don't provide
3265 if (moving
.bottom() <= winrect
.bottom())
3266 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
3268 } else { // BScreen::WindowSnap
3269 dtop
= abs(wtop
- winrect
.top());
3270 dbottom
= abs(wbottom
- winrect
.bottom());
3271 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3273 else if (dbottom
< snap_distance
)
3274 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
3282 // if the windows are on the same plane horizontally
3283 if (wleft
>= (signed)(winrect
.x() - frame
.rect
.width() + 1) &&
3284 wleft
< (signed)(winrect
.x() + winrect
.width() - 1)) {
3286 if (snap_to_windows
== BScreen::WindowResistance
) {
3287 dtop
= wbottom
- offsetrect
.top();
3288 dbottom
= offsetrect
.bottom() - wtop
;
3290 // snap top of other window?
3291 if (dtop
>= 0 && dtop
< resistance_size
&& dtop
< (wbottom
- wtop
)) {
3292 dy
= offsetrect
.top() - frame
.rect
.height();
3295 // snap bottom of other window?
3296 else if (dbottom
>= 0 && dbottom
< resistance_size
&&
3297 dbottom
< (wbottom
- wtop
)) {
3298 dy
= offsetrect
.bottom() + 1;
3301 } else { // BScreen::WindowSnap
3302 dtop
= abs(wbottom
- offsetrect
.top());
3303 dbottom
= abs(wtop
- offsetrect
.bottom());
3305 // snap top of other window?
3306 if (dtop
< snap_distance
&& dtop
<= dbottom
) {
3307 dy
= offsetrect
.top() - frame
.rect
.height();
3310 // snap bottom of other window?
3311 else if (dbottom
< snap_distance
) {
3312 dy
= offsetrect
.bottom() + 1;
3319 if (screen
->getWindowCornerSnap()) {
3320 // try corner-snap to its other sides
3321 if (snap_to_windows
== BScreen::WindowResistance
) {
3322 dleft
= winrect
.left() - wleft
;
3323 dright
= wright
- winrect
.right();
3324 if (dleft
> 0 && dleft
< resistance_size
) {
3325 // if we're already past the left edge, then don't provide
3327 if (moving
.left() >= winrect
.left())
3328 dx
= winrect
.left();
3329 } else if (dright
> 0 && dright
< resistance_size
) {
3330 // if we're already past the right edge, then don't provide
3332 if (moving
.right() <= winrect
.right())
3333 dx
= winrect
.right() - frame
.rect
.width() + 1;
3335 } else { // BScreen::WindowSnap
3336 dleft
= abs(wleft
- winrect
.left());
3337 dright
= abs(wright
- winrect
.right());
3338 if (dleft
< snap_distance
&& dleft
<= dright
)
3339 dx
= winrect
.left();
3340 else if (dright
< snap_distance
)
3341 dx
= winrect
.right() - frame
.rect
.width() + 1;
3351 if (snap_to_edges
) {
3354 // snap to the screen edges (and screen boundaries for xinerama)
3356 if (screen
->isXineramaActive() && blackbox
->doXineramaSnapping()) {
3357 rectlist
.insert(rectlist
.begin(),
3358 screen
->getXineramaAreas().begin(),
3359 screen
->getXineramaAreas().end());
3362 rectlist
.push_back(screen
->getRect());
3364 RectList::const_iterator it
, end
= rectlist
.end();
3365 for (it
= rectlist
.begin(); it
!= end
; ++it
) {
3366 const Rect
&srect
= *it
;
3368 offsetrect
.setCoords(srect
.left() + snap_offset
,
3369 srect
.top() + snap_offset
,
3370 srect
.right() - snap_offset
,
3371 srect
.bottom() - snap_offset
);
3373 if (snap_to_edges
== BScreen::WindowResistance
) {
3374 // if we're not in the rectangle then don't snap to it.
3375 if (! srect
.contains(moving
))
3377 } else { // BScreen::WindowSnap
3378 // if we're not in the rectangle then don't snap to it.
3379 if (! srect
.intersects(Rect(wleft
, wtop
, frame
.rect
.width(),
3380 frame
.rect
.height())))
3384 if (snap_to_edges
== BScreen::WindowResistance
) {
3385 int dleft
= offsetrect
.left() - wleft
,
3386 dright
= wright
- offsetrect
.right(),
3387 dtop
= offsetrect
.top() - wtop
,
3388 dbottom
= wbottom
- offsetrect
.bottom();
3391 if (dleft
> 0 && dleft
< resistance_size
)
3392 dx
= offsetrect
.left();
3394 else if (dright
> 0 && dright
< resistance_size
)
3395 dx
= offsetrect
.right() - frame
.rect
.width() + 1;
3398 if (dtop
> 0 && dtop
< resistance_size
)
3399 dy
= offsetrect
.top();
3401 else if (dbottom
> 0 && dbottom
< resistance_size
)
3402 dy
= offsetrect
.bottom() - frame
.rect
.height() + 1;
3403 } else { // BScreen::WindowSnap
3404 int dleft
= abs(wleft
- offsetrect
.left()),
3405 dright
= abs(wright
- offsetrect
.right()),
3406 dtop
= abs(wtop
- offsetrect
.top()),
3407 dbottom
= abs(wbottom
- offsetrect
.bottom());
3410 if (dleft
< snap_distance
&& dleft
<= dright
)
3411 dx
= offsetrect
.left();
3413 else if (dright
< snap_distance
)
3414 dx
= offsetrect
.right() - frame
.rect
.width() + 1;
3417 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3418 dy
= offsetrect
.top();
3420 else if (dbottom
< snap_distance
)
3421 dy
= offsetrect
.bottom() - frame
.rect
.height() + 1;
3428 void BlackboxWindow::endMove(void) {
3429 assert(flags
.moving
);
3430 assert(blackbox
->getChangingWindow() == this);
3432 flags
.moving
= False
;
3433 blackbox
->setChangingWindow(0);
3435 if (! screen
->doOpaqueMove()) {
3436 /* when drawing the rubber band, we need to make sure we only draw inside
3437 * the frame... frame.changing_* contain the new coords for the window,
3438 * so we need to subtract 1 from changing_w/changing_h every where we
3439 * draw the rubber band (for both moving and resizing)
3441 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3442 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3443 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3444 XUngrabServer(blackbox
->getXDisplay());
3446 configure(frame
.changing
.x(), frame
.changing
.y(),
3447 frame
.changing
.width(), frame
.changing
.height());
3449 configure(frame
.rect
.x(), frame
.rect
.y(),
3450 frame
.rect
.width(), frame
.rect
.height());
3452 screen
->hideGeometry();
3454 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3456 // if there are any left over motions from the move, drop them now
3457 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3459 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3464 void BlackboxWindow::beginResize(int x_root
, int y_root
, Corner dir
) {
3465 assert(! (flags
.resizing
|| flags
.moving
));
3468 Only one window can be moved/resized at a time. If another window is already
3469 being moved or resized, then stop it before whating to work with this one.
3471 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3472 if (changing
&& changing
!= this) {
3473 if (changing
->flags
.moving
)
3474 changing
->endMove();
3475 else // if (changing->flags.resizing)
3476 changing
->endResize();
3484 switch (resize_dir
) {
3487 cursor
= blackbox
->getLowerLeftAngleCursor();
3492 cursor
= blackbox
->getLowerRightAngleCursor();
3496 anchor
= BottomRight
;
3497 cursor
= blackbox
->getUpperLeftAngleCursor();
3501 anchor
= BottomLeft
;
3502 cursor
= blackbox
->getUpperRightAngleCursor();
3506 assert(false); // unhandled Corner
3507 return; // unreachable, for the compiler
3510 XGrabServer(blackbox
->getXDisplay());
3511 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3512 PointerMotionMask
| ButtonReleaseMask
,
3513 GrabModeAsync
, GrabModeAsync
, None
, cursor
, CurrentTime
);
3515 flags
.resizing
= True
;
3516 blackbox
->setChangingWindow(this);
3518 unsigned int gw
, gh
;
3519 frame
.changing
= frame
.rect
;
3521 constrain(anchor
, &gw
, &gh
);
3523 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3524 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3525 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3527 screen
->showGeometry(gw
, gh
);
3529 frame
.grab_x
= x_root
;
3530 frame
.grab_y
= y_root
;
3534 void BlackboxWindow::doResize(int x_root
, int y_root
) {
3535 assert(flags
.resizing
);
3536 assert(blackbox
->getChangingWindow() == this);
3538 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3539 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3540 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3542 unsigned int gw
, gh
;
3545 switch (resize_dir
) {
3548 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3549 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3553 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3554 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3557 anchor
= BottomRight
;
3558 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3559 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3562 anchor
= BottomLeft
;
3563 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3564 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3568 assert(false); // unhandled Corner
3569 return; // unreachable, for the compiler
3572 constrain(anchor
, &gw
, &gh
);
3574 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3575 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3576 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3578 screen
->showGeometry(gw
, gh
);
3582 void BlackboxWindow::endResize(void) {
3583 assert(flags
.resizing
);
3584 assert(blackbox
->getChangingWindow() == this);
3586 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3587 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3588 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3589 XUngrabServer(blackbox
->getXDisplay());
3591 // unset maximized state after resized when fully maximized
3592 if (flags
.maximized
== 1)
3595 flags
.resizing
= False
;
3596 blackbox
->setChangingWindow(0);
3598 configure(frame
.changing
.x(), frame
.changing
.y(),
3599 frame
.changing
.width(), frame
.changing
.height());
3600 screen
->hideGeometry();
3602 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3604 // if there are any left over motions from the resize, drop them now
3605 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3607 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3612 void BlackboxWindow::motionNotifyEvent(const XMotionEvent
*me
) {
3614 fprintf(stderr
, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n",
3619 doMove(me
->x_root
, me
->y_root
);
3620 } else if (flags
.resizing
) {
3621 doResize(me
->x_root
, me
->y_root
);
3623 if (!flags
.resizing
&& me
->state
& Button1Mask
&& (functions
& Func_Move
) &&
3624 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3625 frame
.handle
== me
->window
|| frame
.window
== me
->window
)) {
3626 beginMove(me
->x_root
, me
->y_root
);
3627 } else if ((functions
& Func_Resize
) &&
3628 (me
->state
& Button1Mask
&& (me
->window
== frame
.right_grip
||
3629 me
->window
== frame
.left_grip
)) ||
3630 (me
->state
& Button3Mask
&& me
->state
& ModMask
&&
3631 me
->window
== frame
.window
)) {
3632 unsigned int zones
= screen
->getResizeZones();
3635 if (me
->window
== frame
.left_grip
) {
3636 corner
= BottomLeft
;
3637 } else if (me
->window
== frame
.right_grip
|| zones
== 1) {
3638 corner
= BottomRight
;
3641 bool left
= (me
->x_root
- frame
.rect
.x() <=
3642 static_cast<signed>(frame
.rect
.width() / 2));
3645 else // (zones == 4)
3646 top
= (me
->y_root
- frame
.rect
.y() <=
3647 static_cast<signed>(frame
.rect
.height() / 2));
3648 corner
= (top
? (left
? TopLeft
: TopRight
) :
3649 (left
? BottomLeft
: BottomRight
));
3652 beginResize(me
->x_root
, me
->y_root
, corner
);
3658 void BlackboxWindow::enterNotifyEvent(const XCrossingEvent
* ce
) {
3659 if (! (screen
->isSloppyFocus() && isVisible() && isNormal()))
3663 bool leave
= False
, inferior
= False
;
3665 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), ce
->window
,
3667 if (e
.type
== LeaveNotify
&& e
.xcrossing
.mode
== NotifyNormal
) {
3669 inferior
= (e
.xcrossing
.detail
== NotifyInferior
);
3673 if ((! leave
|| inferior
) && ! isFocused()) {
3674 bool success
= setInputFocus();
3675 if (success
) // if focus succeeded install the colormap
3676 installColormap(True
); // XXX: shouldnt we honour no install?
3679 if (screen
->doAutoRaise())
3684 void BlackboxWindow::leaveNotifyEvent(const XCrossingEvent
*) {
3685 if (! (screen
->isSloppyFocus() && screen
->doAutoRaise() && isNormal()))
3688 installColormap(False
);
3690 if (timer
->isTiming())
3696 void BlackboxWindow::shapeEvent(XShapeEvent
*) {
3697 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
3704 bool BlackboxWindow::validateClient(void) const {
3705 XSync(blackbox
->getXDisplay(), False
);
3708 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3709 DestroyNotify
, &e
) ||
3710 XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3712 XPutBackEvent(blackbox
->getXDisplay(), &e
);
3721 void BlackboxWindow::restore(bool remap
) {
3722 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeDelete
);
3723 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
3724 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, NoEventMask
);
3726 // do not leave a shaded window as an icon unless it was an icon
3727 if (flags
.shaded
&& ! flags
.iconic
)
3728 setState(NormalState
);
3730 restoreGravity(client
.rect
);
3732 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
3733 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
3735 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, client
.old_bw
);
3738 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3739 ReparentNotify
, &ev
)) {
3742 // according to the ICCCM - if the client doesn't reparent to
3743 // root, then we have to do it for them
3744 XReparentWindow(blackbox
->getXDisplay(), client
.window
,
3745 screen
->getRootWindow(),
3746 client
.rect
.x(), client
.rect
.y());
3749 if (remap
) XMapWindow(blackbox
->getXDisplay(), client
.window
);
3753 // timer for autoraise
3754 void BlackboxWindow::timeout(void) {
3755 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3759 void BlackboxWindow::changeBlackboxHints(const BlackboxHints
*net
) {
3760 if ((net
->flags
& AttribShaded
) &&
3761 ((blackbox_attrib
.attrib
& AttribShaded
) !=
3762 (net
->attrib
& AttribShaded
)))
3765 if (flags
.visible
&& // watch out for requests when we can not be seen
3766 (net
->flags
& (AttribMaxVert
| AttribMaxHoriz
)) &&
3767 ((blackbox_attrib
.attrib
& (AttribMaxVert
| AttribMaxHoriz
)) !=
3768 (net
->attrib
& (AttribMaxVert
| AttribMaxHoriz
)))) {
3769 if (flags
.maximized
) {
3774 if ((net
->flags
& AttribMaxHoriz
) && (net
->flags
& AttribMaxVert
))
3775 button
= ((net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0);
3776 else if (net
->flags
& AttribMaxVert
)
3777 button
= ((net
->attrib
& AttribMaxVert
) ? 2 : 0);
3778 else if (net
->flags
& AttribMaxHoriz
)
3779 button
= ((net
->attrib
& AttribMaxHoriz
) ? 3 : 0);
3785 if ((net
->flags
& AttribOmnipresent
) &&
3786 ((blackbox_attrib
.attrib
& AttribOmnipresent
) !=
3787 (net
->attrib
& AttribOmnipresent
)))
3790 if ((net
->flags
& AttribWorkspace
) &&
3791 (blackbox_attrib
.workspace
!= net
->workspace
)) {
3792 screen
->reassociateWindow(this, net
->workspace
, True
);
3794 if (screen
->getCurrentWorkspaceID() != net
->workspace
) {
3798 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3802 if (net
->flags
& AttribDecoration
) {
3803 switch (net
->decoration
) {
3816 // we can not be shaded if we lack a titlebar
3817 if (flags
.shaded
&& ! (decorations
& Decor_Titlebar
))
3820 if (flags
.visible
&& frame
.window
) {
3821 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
3822 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
3826 setState(current_state
);
3832 * Set the sizes of all components of the window frame
3833 * (the window decorations).
3834 * These values are based upon the current style settings and the client
3835 * window's dimensions.
3837 void BlackboxWindow::upsize(void) {
3838 frame
.bevel_w
= screen
->getBevelWidth();
3840 if (decorations
& Decor_Border
) {
3841 frame
.border_w
= screen
->getBorderWidth();
3842 if (! isTransient())
3843 frame
.mwm_border_w
= screen
->getFrameWidth();
3845 frame
.mwm_border_w
= 0;
3847 frame
.mwm_border_w
= frame
.border_w
= 0;
3850 if (decorations
& Decor_Titlebar
) {
3851 // the height of the titlebar is based upon the height of the font being
3852 // used to display the window's title
3853 WindowStyle
*style
= screen
->getWindowStyle();
3854 frame
.title_h
= style
->font
->height() + (frame
.bevel_w
* 2) + 2;
3856 frame
.label_h
= frame
.title_h
- (frame
.bevel_w
* 2);
3857 frame
.button_w
= (frame
.label_h
- 2);
3859 // set the top frame margin
3860 frame
.margin
.top
= frame
.border_w
+ frame
.title_h
+
3861 frame
.border_w
+ frame
.mwm_border_w
;
3867 // set the top frame margin
3868 frame
.margin
.top
= frame
.border_w
+ frame
.mwm_border_w
;
3871 // set the left/right frame margin
3872 frame
.margin
.left
= frame
.margin
.right
= frame
.border_w
+ frame
.mwm_border_w
;
3874 if (decorations
& Decor_Handle
) {
3875 frame
.grip_w
= frame
.button_w
* 2;
3876 frame
.handle_h
= screen
->getHandleWidth();
3878 // set the bottom frame margin
3879 frame
.margin
.bottom
= frame
.border_w
+ frame
.handle_h
+
3880 frame
.border_w
+ frame
.mwm_border_w
;
3885 // set the bottom frame margin
3886 frame
.margin
.bottom
= frame
.border_w
+ frame
.mwm_border_w
;
3890 We first get the normal dimensions and use this to define the inside_w/h
3891 then we modify the height if shading is in effect.
3892 If the shade state is not considered then frame.rect gets reset to the
3893 normal window size on a reconfigure() call resulting in improper
3894 dimensions appearing in move/resize and other events.
3897 height
= client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
,
3898 width
= client
.rect
.width() + frame
.margin
.left
+ frame
.margin
.right
;
3900 frame
.inside_w
= width
- (frame
.border_w
* 2);
3901 frame
.inside_h
= height
- (frame
.border_w
* 2);
3904 height
= frame
.title_h
+ (frame
.border_w
* 2);
3905 frame
.rect
.setSize(width
, height
);
3910 * Calculate the size of the client window and constrain it to the
3911 * size specified by the size hints of the client window.
3913 * The logical width and height are placed into pw and ph, if they
3914 * are non-zero. Logical size refers to the users perception of
3915 * the window size (for example an xterm resizes in cells, not in pixels).
3916 * pw and ph are then used to display the geometry during window moves, resize,
3919 * The physical geometry is placed into frame.changing_{x,y,width,height}.
3920 * Physical geometry refers to the geometry of the window in pixels.
3922 void BlackboxWindow::constrain(Corner anchor
,
3923 unsigned int *pw
, unsigned int *ph
) {
3924 // frame.changing represents the requested frame size, we need to
3925 // strip the frame margin off and constrain the client size
3926 frame
.changing
.setCoords(frame
.changing
.left() + frame
.margin
.left
,
3927 frame
.changing
.top() + frame
.margin
.top
,
3928 frame
.changing
.right() - frame
.margin
.right
,
3929 frame
.changing
.bottom() - frame
.margin
.bottom
);
3931 unsigned int dw
= frame
.changing
.width(), dh
= frame
.changing
.height(),
3932 base_width
= (client
.base_width
) ? client
.base_width
: client
.min_width
,
3933 base_height
= (client
.base_height
) ? client
.base_height
:
3937 if (dw
< client
.min_width
) dw
= client
.min_width
;
3938 if (dh
< client
.min_height
) dh
= client
.min_height
;
3939 if (dw
> client
.max_width
) dw
= client
.max_width
;
3940 if (dh
> client
.max_height
) dh
= client
.max_height
;
3942 assert(dw
>= base_width
&& dh
>= base_height
);
3944 if (client
.width_inc
> 1) {
3946 dw
/= client
.width_inc
;
3948 if (client
.height_inc
> 1) {
3950 dh
/= client
.height_inc
;
3959 if (client
.width_inc
> 1) {
3960 dw
*= client
.width_inc
;
3963 if (client
.height_inc
> 1) {
3964 dh
*= client
.height_inc
;
3968 frame
.changing
.setSize(dw
, dh
);
3970 // add the frame margin back onto frame.changing
3971 frame
.changing
.setCoords(frame
.changing
.left() - frame
.margin
.left
,
3972 frame
.changing
.top() - frame
.margin
.top
,
3973 frame
.changing
.right() + frame
.margin
.right
,
3974 frame
.changing
.bottom() + frame
.margin
.bottom
);
3976 // move frame.changing to the specified anchor
3984 dx
= frame
.rect
.right() - frame
.changing
.right();
3988 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3992 dx
= frame
.rect
.right() - frame
.changing
.right();
3993 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3997 assert(false); // unhandled corner
3999 frame
.changing
.setPos(frame
.changing
.x() + dx
, frame
.changing
.y() + dy
);
4003 void WindowStyle::doJustify(const std::string
&text
, int &start_pos
,
4004 unsigned int max_length
,
4005 unsigned int modifier
) const {
4006 size_t text_len
= text
.size();
4007 unsigned int length
;
4010 length
= font
->measureString(string(text
, 0, text_len
)) + modifier
;
4011 } while (length
> max_length
&& text_len
-- > 0);
4015 start_pos
+= max_length
- length
;
4019 start_pos
+= (max_length
- length
) / 2;
4029 BWindowGroup::BWindowGroup(Blackbox
*b
, Window _group
)
4030 : blackbox(b
), group(_group
) {
4031 XWindowAttributes wattrib
;
4032 if (! XGetWindowAttributes(blackbox
->getXDisplay(), group
, &wattrib
)) {
4033 // group window doesn't seem to exist anymore
4038 XSelectInput(blackbox
->getXDisplay(), group
,
4039 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
4041 blackbox
->saveGroupSearch(group
, this);
4045 BWindowGroup::~BWindowGroup(void) {
4046 blackbox
->removeGroupSearch(group
);
4051 BWindowGroup::find(BScreen
*screen
, bool allow_transients
) const {
4052 BlackboxWindow
*ret
= blackbox
->getFocusedWindow();
4054 // does the focus window match (or any transient_fors)?
4055 for (; ret
; ret
= ret
->getTransientFor()) {
4056 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
&&
4057 (! ret
->isTransient() || allow_transients
))
4061 if (ret
) return ret
;
4063 // the focus window didn't match, look in the group's window list
4064 BlackboxWindowList::const_iterator it
, end
= windowList
.end();
4065 for (it
= windowList
.begin(); it
!= end
; ++it
) {
4067 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
&&
4068 (! ret
->isTransient() || allow_transients
))