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"
66 * Initializes the class with default values/the window's set initial values.
68 BlackboxWindow::BlackboxWindow(Blackbox
*b
, Window w
, BScreen
*s
) {
69 // fprintf(stderr, "BlackboxWindow size: %d bytes\n",
70 // sizeof(BlackboxWindow));
73 fprintf(stderr
, "BlackboxWindow::BlackboxWindow(): creating 0x%lx\n", w
);
77 set timer to zero... it is initialized properly later, so we check
78 if timer is zero in the destructor, and assume that the window is not
79 fully constructed if timer is zero...
85 xatom
= blackbox
->getXAtom();
87 if (! validateClient()) {
92 // fetch client size and placement
93 XWindowAttributes wattrib
;
94 if (! XGetWindowAttributes(blackbox
->getXDisplay(),
95 client
.window
, &wattrib
) ||
96 ! wattrib
.screen
|| wattrib
.override_redirect
) {
99 "BlackboxWindow::BlackboxWindow(): XGetWindowAttributes failed\n");
106 // set the eventmask early in the game so that we make sure we get
107 // all the events we are interested in
108 XSetWindowAttributes attrib_set
;
109 attrib_set
.event_mask
= PropertyChangeMask
| FocusChangeMask
|
111 attrib_set
.do_not_propagate_mask
= ButtonPressMask
| ButtonReleaseMask
|
113 XChangeWindowAttributes(blackbox
->getXDisplay(), client
.window
,
114 CWEventMask
|CWDontPropagate
, &attrib_set
);
116 flags
.moving
= flags
.resizing
= flags
.shaded
= flags
.visible
=
117 flags
.iconic
= flags
.focused
= flags
.stuck
= flags
.modal
=
118 flags
.send_focus_message
= flags
.shaped
= flags
.skip_taskbar
=
119 flags
.skip_pager
= flags
.fullscreen
= False
;
122 blackbox_attrib
.workspace
= window_number
= BSENTINEL
;
124 blackbox_attrib
.flags
= blackbox_attrib
.attrib
= blackbox_attrib
.stack
= 0l;
125 blackbox_attrib
.decoration
= DecorNormal
;
126 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
127 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
130 frame
.window
= frame
.plate
= frame
.title
= frame
.handle
= None
;
131 frame
.close_button
= frame
.iconify_button
= frame
.maximize_button
= None
;
132 frame
.right_grip
= frame
.left_grip
= None
;
134 frame
.ulabel_pixel
= frame
.flabel_pixel
= frame
.utitle_pixel
=
135 frame
.ftitle_pixel
= frame
.uhandle_pixel
= frame
.fhandle_pixel
=
136 frame
.ubutton_pixel
= frame
.fbutton_pixel
= frame
.pbutton_pixel
=
137 frame
.uborder_pixel
= frame
.fborder_pixel
= frame
.ugrip_pixel
=
138 frame
.fgrip_pixel
= 0;
139 frame
.utitle
= frame
.ftitle
= frame
.uhandle
= frame
.fhandle
= None
;
140 frame
.ulabel
= frame
.flabel
= frame
.ubutton
= frame
.fbutton
= None
;
141 frame
.pbutton
= frame
.ugrip
= frame
.fgrip
= None
;
143 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
144 mwm_decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
145 Decor_Iconify
| Decor_Maximize
;
147 client
.normal_hint_flags
= 0;
148 client
.window_group
= None
;
149 client
.transient_for
= 0;
151 current_state
= NormalState
;
156 set the initial size and location of client window (relative to the
157 _root window_). This position is the reference point used with the
158 window's gravity to find the window's initial position.
160 client
.rect
.setRect(wattrib
.x
, wattrib
.y
, wattrib
.width
, wattrib
.height
);
161 client
.old_bw
= wattrib
.border_width
;
163 lastButtonPressTime
= 0;
165 timer
= new BTimer(blackbox
, this);
166 timer
->setTimeout(blackbox
->getAutoRaiseDelay());
168 // get size, aspect, minimum/maximum size and other hints set by the
171 if (! getBlackboxHints())
178 frame
.window
= createToplevelWindow();
180 blackbox
->saveWindowSearch(frame
.window
, this);
182 frame
.plate
= createChildWindow(frame
.window
);
183 blackbox
->saveWindowSearch(frame
.plate
, this);
185 // determine if this is a transient window
188 // determine the window's type, so we can decide its decorations and
189 // functionality, or if we should not manage it at all
190 if (getWindowType()) {
191 // adjust the window decorations/behavior based on the window type
192 switch (window_type
) {
196 blackbox_attrib
.workspace
= 0; // we do need to belong to a workspace
197 flags
.stuck
= True
; // we show up on all workspaces
199 // none of these windows are manipulated by the window manager
205 // these windows get less functionality
206 functions
&= ~(Func_Maximize
| Func_Resize
| Func_Iconify
);
210 // dialogs cannot be maximized
211 functions
&= ~Func_Maximize
;
215 // normal windows retain all of the possible decorations and
223 // further adjeust the window's decorations/behavior based on window sizes
224 if ((client
.normal_hint_flags
& PMinSize
) &&
225 (client
.normal_hint_flags
& PMaxSize
) &&
226 client
.max_width
<= client
.min_width
&&
227 client
.max_height
<= client
.min_height
) {
228 functions
&= ~(Func_Resize
| Func_Maximize
);
235 if (decorations
& Decor_Titlebar
)
238 if (decorations
& Decor_Handle
)
241 // apply the size and gravity hint to the frame
245 bool place_window
= True
;
246 if (blackbox
->isStartup() || isTransient() ||
247 client
.normal_hint_flags
& (PPosition
|USPosition
)) {
248 applyGravity(frame
.rect
);
250 if (blackbox
->isStartup() || client
.rect
.intersects(screen
->getRect()))
251 place_window
= False
;
254 // add the window's strut. note this is done *after* placing the window.
255 screen
->addStrut(&client
.strut
);
259 the server needs to be grabbed here to prevent client's from sending
260 events while we are in the process of configuring their window.
261 We hold the grab until after we are done moving the window around.
264 XGrabServer(blackbox
->getXDisplay());
266 associateClientWindow();
268 blackbox
->saveWindowSearch(client
.window
, this);
270 if (blackbox_attrib
.workspace
>= screen
->getWorkspaceCount())
271 screen
->getCurrentWorkspace()->addWindow(this, place_window
);
273 screen
->getWorkspace(blackbox_attrib
.workspace
)->
274 addWindow(this, place_window
);
276 if (! place_window
) {
277 // don't need to call configure if we are letting the workspace
279 configure(frame
.rect
.x(), frame
.rect
.y(),
280 frame
.rect
.width(), frame
.rect
.height());
286 XUngrabServer(blackbox
->getXDisplay());
289 if (blackbox
->hasShapeExtensions() && flags
.shaped
)
293 // now that we know where to put the window and what it should look like
294 // we apply the decorations
299 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
301 // this ensures the title, buttons, and other decor are properly displayed
304 // preserve the window's initial state on first map, and its current state
306 unsigned long initial_state
= current_state
;
308 current_state
= initial_state
;
310 // get sticky state from our parent window if we've got one
311 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
312 client
.transient_for
->isStuck() != flags
.stuck
)
316 flags
.shaded
= False
;
317 initial_state
= current_state
;
321 At this point in the life of a window, current_state should only be set
322 to IconicState if the window was an *icon*, not if it was shaded.
324 if (initial_state
!= IconicState
)
325 current_state
= NormalState
;
333 if (flags
.maximized
&& (functions
& Func_Maximize
))
336 // create this last so it only needs to be configured once
337 windowmenu
= new Windowmenu(this);
341 BlackboxWindow::~BlackboxWindow(void) {
343 fprintf(stderr
, "BlackboxWindow::~BlackboxWindow: destroying 0x%lx\n",
347 if (! timer
) // window not managed...
353 screen
->removeStrut(&client
.strut
);
354 screen
->updateAvailableArea();
356 // We don't need to worry about resizing because resizing always grabs the X
357 // server. This should only ever happen if using opaque moving.
365 if (client
.window_group
) {
366 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
367 if (group
) group
->removeWindow(this);
370 // remove ourselves from our transient_for
372 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul)
373 client
.transient_for
->client
.transientList
.remove(this);
374 client
.transient_for
= (BlackboxWindow
*) 0;
377 if (client
.transientList
.size() > 0) {
378 // reset transient_for for all transients
379 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
380 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
381 (*it
)->client
.transient_for
= (BlackboxWindow
*) 0;
391 blackbox
->removeWindowSearch(frame
.plate
);
392 XDestroyWindow(blackbox
->getXDisplay(), frame
.plate
);
396 blackbox
->removeWindowSearch(frame
.window
);
397 XDestroyWindow(blackbox
->getXDisplay(), frame
.window
);
400 blackbox
->removeWindowSearch(client
.window
);
404 void BlackboxWindow::enableDecor(bool enable
) {
405 blackbox_attrib
.flags
|= AttribDecoration
;
406 blackbox_attrib
.decoration
= enable
? DecorNormal
: DecorNone
;
409 // we can not be shaded if we lack a titlebar
410 if (! (decorations
& Decor_Titlebar
) && flags
.shaded
)
413 if (flags
.visible
&& frame
.window
) {
414 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
415 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
419 setState(current_state
);
423 void BlackboxWindow::setupDecor() {
424 if (blackbox_attrib
.decoration
!= DecorNone
) {
425 // start with everything on
426 decorations
= Decor_Close
|
427 (mwm_decorations
& Decor_Titlebar
? Decor_Titlebar
: 0) |
428 (mwm_decorations
& Decor_Border
? Decor_Border
: 0) |
429 (mwm_decorations
& Decor_Handle
? Decor_Handle
: 0) |
430 (mwm_decorations
& Decor_Iconify
? Decor_Iconify
: 0) |
431 (mwm_decorations
& Decor_Maximize
? Decor_Maximize
: 0);
433 if (! (functions
& Func_Close
)) decorations
&= ~Decor_Close
;
434 if (! (functions
& Func_Maximize
)) decorations
&= ~Decor_Maximize
;
435 if (! (functions
& Func_Iconify
)) decorations
&= ~Decor_Iconify
;
436 if (! (functions
& Func_Resize
)) decorations
&= ~Decor_Handle
;
438 switch (window_type
) {
443 // none of these windows are decorated by the window manager at all
449 decorations
&= ~(Decor_Border
);
453 decorations
&= ~Decor_Handle
;
465 * Creates a new top level window, with a given location, size, and border
467 * Returns: the newly created window
469 Window
BlackboxWindow::createToplevelWindow(void) {
470 XSetWindowAttributes attrib_create
;
471 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
| CWColormap
|
472 CWOverrideRedirect
| CWEventMask
;
474 attrib_create
.background_pixmap
= None
;
475 attrib_create
.colormap
= screen
->getColormap();
476 attrib_create
.override_redirect
= True
;
477 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
479 EnterWindowMask
| LeaveWindowMask
;
481 return XCreateWindow(blackbox
->getXDisplay(), screen
->getRootWindow(),
482 0, 0, 1, 1, frame
.border_w
, screen
->getDepth(),
483 InputOutput
, screen
->getVisual(), create_mask
,
489 * Creates a child window, and optionally associates a given cursor with
492 Window
BlackboxWindow::createChildWindow(Window parent
, Cursor cursor
) {
493 XSetWindowAttributes attrib_create
;
494 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
|
497 attrib_create
.background_pixmap
= None
;
498 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
499 ButtonMotionMask
| ExposureMask
;
502 create_mask
|= CWCursor
;
503 attrib_create
.cursor
= cursor
;
506 return XCreateWindow(blackbox
->getXDisplay(), parent
, 0, 0, 1, 1, 0,
507 screen
->getDepth(), InputOutput
, screen
->getVisual(),
508 create_mask
, &attrib_create
);
512 void BlackboxWindow::associateClientWindow(void) {
513 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, 0);
517 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeInsert
);
519 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, SubstructureRedirectMask
);
522 note we used to grab around this call to XReparentWindow however the
523 server is now grabbed before this method is called
525 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
527 XSelectInput(blackbox
->getXDisplay(), client
.window
,
528 event_mask
& ~StructureNotifyMask
);
529 XReparentWindow(blackbox
->getXDisplay(), client
.window
, frame
.plate
, 0, 0);
530 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
532 XRaiseWindow(blackbox
->getXDisplay(), frame
.plate
);
533 XMapSubwindows(blackbox
->getXDisplay(), frame
.plate
);
536 if (blackbox
->hasShapeExtensions()) {
537 XShapeSelectInput(blackbox
->getXDisplay(), client
.window
,
544 XShapeQueryExtents(blackbox
->getXDisplay(), client
.window
, &shaped
,
545 &foo
, &foo
, &ufoo
, &ufoo
, &foo
, &foo
, &foo
,
547 flags
.shaped
= shaped
;
553 void BlackboxWindow::decorate(void) {
556 texture
= &(screen
->getWindowStyle()->b_focus
);
557 frame
.fbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
560 frame
.fbutton_pixel
= texture
->color().pixel();
562 texture
= &(screen
->getWindowStyle()->b_unfocus
);
563 frame
.ubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
566 frame
.ubutton_pixel
= texture
->color().pixel();
568 texture
= &(screen
->getWindowStyle()->b_pressed
);
569 frame
.pbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
572 frame
.pbutton_pixel
= texture
->color().pixel();
574 if (decorations
& Decor_Titlebar
) {
575 texture
= &(screen
->getWindowStyle()->t_focus
);
576 frame
.ftitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
579 frame
.ftitle_pixel
= texture
->color().pixel();
581 texture
= &(screen
->getWindowStyle()->t_unfocus
);
582 frame
.utitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
585 frame
.utitle_pixel
= texture
->color().pixel();
587 XSetWindowBorder(blackbox
->getXDisplay(), frame
.title
,
588 screen
->getBorderColor()->pixel());
593 if (decorations
& Decor_Border
) {
594 frame
.fborder_pixel
= screen
->getWindowStyle()->f_focus
.color().pixel();
595 frame
.uborder_pixel
= screen
->getWindowStyle()->f_unfocus
.color().pixel();
598 if (decorations
& Decor_Handle
) {
599 texture
= &(screen
->getWindowStyle()->h_focus
);
600 frame
.fhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
603 frame
.fhandle_pixel
= texture
->color().pixel();
605 texture
= &(screen
->getWindowStyle()->h_unfocus
);
606 frame
.uhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
609 frame
.uhandle_pixel
= texture
->color().pixel();
611 texture
= &(screen
->getWindowStyle()->g_focus
);
612 frame
.fgrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.fgrip
);
614 frame
.fgrip_pixel
= texture
->color().pixel();
616 texture
= &(screen
->getWindowStyle()->g_unfocus
);
617 frame
.ugrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.ugrip
);
619 frame
.ugrip_pixel
= texture
->color().pixel();
621 XSetWindowBorder(blackbox
->getXDisplay(), frame
.handle
,
622 screen
->getBorderColor()->pixel());
623 XSetWindowBorder(blackbox
->getXDisplay(), frame
.left_grip
,
624 screen
->getBorderColor()->pixel());
625 XSetWindowBorder(blackbox
->getXDisplay(), frame
.right_grip
,
626 screen
->getBorderColor()->pixel());
629 XSetWindowBorder(blackbox
->getXDisplay(), frame
.window
,
630 screen
->getBorderColor()->pixel());
634 void BlackboxWindow::decorateLabel(void) {
637 texture
= &(screen
->getWindowStyle()->l_focus
);
638 frame
.flabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.flabel
);
640 frame
.flabel_pixel
= texture
->color().pixel();
642 texture
= &(screen
->getWindowStyle()->l_unfocus
);
643 frame
.ulabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.ulabel
);
645 frame
.ulabel_pixel
= texture
->color().pixel();
649 void BlackboxWindow::createHandle(void) {
650 frame
.handle
= createChildWindow(frame
.window
);
651 blackbox
->saveWindowSearch(frame
.handle
, this);
654 createChildWindow(frame
.handle
, blackbox
->getLowerLeftAngleCursor());
655 blackbox
->saveWindowSearch(frame
.left_grip
, this);
658 createChildWindow(frame
.handle
, blackbox
->getLowerRightAngleCursor());
659 blackbox
->saveWindowSearch(frame
.right_grip
, this);
663 void BlackboxWindow::destroyHandle(void) {
665 screen
->getImageControl()->removeImage(frame
.fhandle
);
668 screen
->getImageControl()->removeImage(frame
.uhandle
);
671 screen
->getImageControl()->removeImage(frame
.fgrip
);
674 screen
->getImageControl()->removeImage(frame
.ugrip
);
676 blackbox
->removeWindowSearch(frame
.left_grip
);
677 blackbox
->removeWindowSearch(frame
.right_grip
);
679 XDestroyWindow(blackbox
->getXDisplay(), frame
.left_grip
);
680 XDestroyWindow(blackbox
->getXDisplay(), frame
.right_grip
);
681 frame
.left_grip
= frame
.right_grip
= None
;
683 blackbox
->removeWindowSearch(frame
.handle
);
684 XDestroyWindow(blackbox
->getXDisplay(), frame
.handle
);
689 void BlackboxWindow::createTitlebar(void) {
690 frame
.title
= createChildWindow(frame
.window
);
691 frame
.label
= createChildWindow(frame
.title
);
692 blackbox
->saveWindowSearch(frame
.title
, this);
693 blackbox
->saveWindowSearch(frame
.label
, this);
695 if (decorations
& Decor_Iconify
) createIconifyButton();
696 if (decorations
& Decor_Maximize
) createMaximizeButton();
697 if (decorations
& Decor_Close
) createCloseButton();
701 void BlackboxWindow::destroyTitlebar(void) {
702 if (frame
.close_button
)
703 destroyCloseButton();
705 if (frame
.iconify_button
)
706 destroyIconifyButton();
708 if (frame
.maximize_button
)
709 destroyMaximizeButton();
712 screen
->getImageControl()->removeImage(frame
.ftitle
);
715 screen
->getImageControl()->removeImage(frame
.utitle
);
718 screen
->getImageControl()->removeImage(frame
.flabel
);
721 screen
->getImageControl()->removeImage(frame
.ulabel
);
724 screen
->getImageControl()->removeImage(frame
.fbutton
);
727 screen
->getImageControl()->removeImage(frame
.ubutton
);
730 screen
->getImageControl()->removeImage(frame
.pbutton
);
732 blackbox
->removeWindowSearch(frame
.title
);
733 blackbox
->removeWindowSearch(frame
.label
);
735 XDestroyWindow(blackbox
->getXDisplay(), frame
.label
);
736 XDestroyWindow(blackbox
->getXDisplay(), frame
.title
);
737 frame
.title
= frame
.label
= None
;
741 void BlackboxWindow::createCloseButton(void) {
742 if (frame
.title
!= None
) {
743 frame
.close_button
= createChildWindow(frame
.title
);
744 blackbox
->saveWindowSearch(frame
.close_button
, this);
749 void BlackboxWindow::destroyCloseButton(void) {
750 blackbox
->removeWindowSearch(frame
.close_button
);
751 XDestroyWindow(blackbox
->getXDisplay(), frame
.close_button
);
752 frame
.close_button
= None
;
756 void BlackboxWindow::createIconifyButton(void) {
757 if (frame
.title
!= None
) {
758 frame
.iconify_button
= createChildWindow(frame
.title
);
759 blackbox
->saveWindowSearch(frame
.iconify_button
, this);
764 void BlackboxWindow::destroyIconifyButton(void) {
765 blackbox
->removeWindowSearch(frame
.iconify_button
);
766 XDestroyWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
767 frame
.iconify_button
= None
;
771 void BlackboxWindow::createMaximizeButton(void) {
772 if (frame
.title
!= None
) {
773 frame
.maximize_button
= createChildWindow(frame
.title
);
774 blackbox
->saveWindowSearch(frame
.maximize_button
, this);
779 void BlackboxWindow::destroyMaximizeButton(void) {
780 blackbox
->removeWindowSearch(frame
.maximize_button
);
781 XDestroyWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
782 frame
.maximize_button
= None
;
786 void BlackboxWindow::positionButtons(bool redecorate_label
) {
787 string layout
= blackbox
->getTitlebarLayout();
790 bool hasclose
, hasiconify
, hasmaximize
, haslabel
;
791 hasclose
= hasiconify
= hasmaximize
= haslabel
= false;
793 string::const_iterator it
, end
;
794 for (it
= layout
.begin(), end
= layout
.end(); it
!= end
; ++it
) {
797 if (! hasclose
&& (decorations
& Decor_Close
)) {
803 if (! hasiconify
&& (decorations
& Decor_Iconify
)) {
809 if (! hasmaximize
&& (decorations
& Decor_Maximize
)) {
821 if (! hasclose
&& frame
.close_button
)
822 destroyCloseButton();
823 if (! hasiconify
&& frame
.iconify_button
)
824 destroyIconifyButton();
825 if (! hasmaximize
&& frame
.maximize_button
)
826 destroyMaximizeButton();
828 parsed
+= 'L'; // require that the label be in the layout
830 const unsigned int bsep
= frame
.bevel_w
+ 1; // separation between elements
831 const unsigned int by
= frame
.bevel_w
+ 1;
832 const unsigned int ty
= frame
.bevel_w
;
834 frame
.label_w
= frame
.inside_w
- bsep
* 2 -
835 (frame
.button_w
+ bsep
) * (parsed
.size() - 1);
837 unsigned int x
= bsep
;
838 for (it
= parsed
.begin(), end
= parsed
.end(); it
!= end
; ++it
) {
841 if (! frame
.close_button
) createCloseButton();
842 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.close_button
, x
, by
,
843 frame
.button_w
, frame
.button_w
);
844 x
+= frame
.button_w
+ bsep
;
847 if (! frame
.iconify_button
) createIconifyButton();
848 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.iconify_button
, x
, by
,
849 frame
.button_w
, frame
.button_w
);
850 x
+= frame
.button_w
+ bsep
;
853 if (! frame
.maximize_button
) createMaximizeButton();
854 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.maximize_button
, x
, by
,
855 frame
.button_w
, frame
.button_w
);
856 x
+= frame
.button_w
+ bsep
;
859 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.label
, x
, ty
,
860 frame
.label_w
, frame
.label_h
);
861 x
+= frame
.label_w
+ bsep
;
866 if (redecorate_label
) decorateLabel();
872 void BlackboxWindow::reconfigure(void) {
873 restoreGravity(client
.rect
);
875 applyGravity(frame
.rect
);
884 windowmenu
->move(windowmenu
->getX(), frame
.rect
.y() + frame
.title_h
);
885 windowmenu
->reconfigure();
890 void BlackboxWindow::grabButtons(void) {
891 mod_mask
= blackbox
->getMouseModMask();
893 if (! screen
->isSloppyFocus() || screen
->doClickRaise())
894 // grab button 1 for changing focus/raising
895 blackbox
->grabButton(Button1
, 0, frame
.plate
, True
, ButtonPressMask
,
896 GrabModeSync
, GrabModeSync
, frame
.plate
, None
,
897 screen
->allowScrollLock());
899 if (functions
& Func_Move
)
900 blackbox
->grabButton(Button1
, mod_mask
, frame
.window
, True
,
901 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
902 GrabModeAsync
, frame
.window
, None
,
903 screen
->allowScrollLock());
904 if (functions
& Func_Resize
)
905 blackbox
->grabButton(Button3
, mod_mask
, frame
.window
, True
,
906 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
907 GrabModeAsync
, frame
.window
, None
,
908 screen
->allowScrollLock());
909 // alt+middle lowers the window
910 blackbox
->grabButton(Button2
, mod_mask
, frame
.window
, True
,
911 ButtonReleaseMask
, GrabModeAsync
, GrabModeAsync
,
913 screen
->allowScrollLock());
917 void BlackboxWindow::ungrabButtons(void) {
918 blackbox
->ungrabButton(Button1
, 0, frame
.plate
);
919 blackbox
->ungrabButton(Button1
, mod_mask
, frame
.window
);
920 blackbox
->ungrabButton(Button2
, mod_mask
, frame
.window
);
921 blackbox
->ungrabButton(Button3
, mod_mask
, frame
.window
);
925 void BlackboxWindow::positionWindows(void) {
926 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.window
,
927 frame
.rect
.x(), frame
.rect
.y(), frame
.inside_w
,
928 (flags
.shaded
) ? frame
.title_h
: frame
.inside_h
);
929 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.window
,
931 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.plate
,
933 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.plate
,
934 frame
.margin
.left
- frame
.mwm_border_w
- frame
.border_w
,
935 frame
.margin
.top
- frame
.mwm_border_w
- frame
.border_w
,
936 client
.rect
.width(), client
.rect
.height());
937 XMoveResizeWindow(blackbox
->getXDisplay(), client
.window
,
938 0, 0, client
.rect
.width(), client
.rect
.height());
939 // ensure client.rect contains the real location
940 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
941 frame
.rect
.top() + frame
.margin
.top
);
943 if (decorations
& Decor_Titlebar
) {
944 if (frame
.title
== None
) createTitlebar();
946 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.title
,
948 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.title
, -frame
.border_w
,
949 -frame
.border_w
, frame
.inside_w
, frame
.title_h
);
952 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
953 XMapWindow(blackbox
->getXDisplay(), frame
.title
);
954 } else if (frame
.title
) {
957 if (decorations
& Decor_Handle
) {
958 if (frame
.handle
== None
) createHandle();
959 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.handle
,
961 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.left_grip
,
963 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.right_grip
,
966 // use client.rect here so the value is correct even if shaded
967 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.handle
,
969 client
.rect
.height() + frame
.margin
.top
+
970 frame
.mwm_border_w
- frame
.border_w
,
971 frame
.inside_w
, frame
.handle_h
);
972 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.left_grip
,
973 -frame
.border_w
, -frame
.border_w
,
974 frame
.grip_w
, frame
.handle_h
);
975 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.right_grip
,
976 frame
.inside_w
- frame
.grip_w
- frame
.border_w
,
977 -frame
.border_w
, frame
.grip_w
, frame
.handle_h
);
979 XMapSubwindows(blackbox
->getXDisplay(), frame
.handle
);
980 XMapWindow(blackbox
->getXDisplay(), frame
.handle
);
981 } else if (frame
.handle
) {
984 XSync(blackbox
->getXDisplay(), False
);
988 void BlackboxWindow::updateStrut(void) {
989 unsigned long num
= 4;
991 if (! xatom
->getValue(client
.window
, XAtom::net_wm_strut
, XAtom::cardinal
,
996 client
.strut
.left
= data
[0];
997 client
.strut
.right
= data
[1];
998 client
.strut
.top
= data
[2];
999 client
.strut
.bottom
= data
[3];
1001 screen
->updateAvailableArea();
1008 bool BlackboxWindow::getWindowType(void) {
1009 window_type
= (WindowType
) -1;
1012 unsigned long num
= (unsigned) -1;
1013 if (xatom
->getValue(client
.window
, XAtom::net_wm_window_type
, XAtom::atom
,
1015 for (unsigned long i
= 0; i
< num
; ++i
) {
1016 if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_desktop
))
1017 window_type
= Type_Desktop
;
1018 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_dock
))
1019 window_type
= Type_Dock
;
1020 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_toolbar
))
1021 window_type
= Type_Toolbar
;
1022 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_menu
))
1023 window_type
= Type_Menu
;
1024 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_utility
))
1025 window_type
= Type_Utility
;
1026 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_splash
))
1027 window_type
= Type_Splash
;
1028 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_dialog
))
1029 window_type
= Type_Dialog
;
1030 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_normal
))
1031 window_type
= Type_Normal
;
1033 xatom
->getAtom(XAtom::kde_net_wm_window_type_override
))
1034 mwm_decorations
= 0; // prevent this window from getting any decor
1039 if (window_type
== (WindowType
) -1) {
1041 * the window type hint was not set, which means we either classify ourself
1042 * as a normal window or a dialog, depending on if we are a transient.
1045 window_type
= Type_Dialog
;
1047 window_type
= Type_Normal
;
1056 void BlackboxWindow::getWMName(void) {
1057 if (xatom
->getValue(client
.window
, XAtom::net_wm_name
,
1058 XAtom::utf8
, client
.title
) &&
1059 !client
.title
.empty()) {
1060 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
1063 //fall through to using WM_NAME
1064 if (xatom
->getValue(client
.window
, XAtom::wm_name
, XAtom::ansi
, client
.title
)
1065 && !client
.title
.empty()) {
1066 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
1069 // fall back to an internal default
1070 client
.title
= i18n(WindowSet
, WindowUnnamed
, "Unnamed");
1071 xatom
->setValue(client
.window
, XAtom::net_wm_visible_name
, XAtom::utf8
,
1076 void BlackboxWindow::getWMIconName(void) {
1077 if (xatom
->getValue(client
.window
, XAtom::net_wm_icon_name
,
1078 XAtom::utf8
, client
.icon_title
) &&
1079 !client
.icon_title
.empty()) {
1080 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1083 //fall through to using WM_ICON_NAME
1084 if (xatom
->getValue(client
.window
, XAtom::wm_icon_name
, XAtom::ansi
,
1085 client
.icon_title
) &&
1086 !client
.icon_title
.empty()) {
1087 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1090 // fall back to using the main name
1091 client
.icon_title
= client
.title
;
1092 xatom
->setValue(client
.window
, XAtom::net_wm_visible_icon_name
, XAtom::utf8
,
1098 * Retrieve which WM Protocols are supported by the client window.
1099 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
1100 * window's decorations and allow the close behavior.
1101 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
1104 void BlackboxWindow::getWMProtocols(void) {
1108 if (XGetWMProtocols(blackbox
->getXDisplay(), client
.window
,
1109 &proto
, &num_return
)) {
1110 for (int i
= 0; i
< num_return
; ++i
) {
1111 if (proto
[i
] == xatom
->getAtom(XAtom::wm_delete_window
)) {
1112 decorations
|= Decor_Close
;
1113 functions
|= Func_Close
;
1114 } else if (proto
[i
] == xatom
->getAtom(XAtom::wm_take_focus
))
1115 flags
.send_focus_message
= True
;
1116 else if (proto
[i
] == xatom
->getAtom(XAtom::blackbox_structure_messages
))
1117 screen
->addNetizen(new Netizen(screen
, client
.window
));
1126 * Gets the value of the WM_HINTS property.
1127 * If the property is not set, then use a set of default values.
1129 void BlackboxWindow::getWMHints(void) {
1130 focus_mode
= F_Passive
;
1132 // remove from current window group
1133 if (client
.window_group
) {
1134 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1135 if (group
) group
->removeWindow(this);
1137 client
.window_group
= None
;
1139 XWMHints
*wmhint
= XGetWMHints(blackbox
->getXDisplay(), client
.window
);
1144 if (wmhint
->flags
& InputHint
) {
1145 if (wmhint
->input
== True
) {
1146 if (flags
.send_focus_message
)
1147 focus_mode
= F_LocallyActive
;
1149 if (flags
.send_focus_message
)
1150 focus_mode
= F_GloballyActive
;
1152 focus_mode
= F_NoInput
;
1156 if (wmhint
->flags
& StateHint
)
1157 current_state
= wmhint
->initial_state
;
1159 if (wmhint
->flags
& WindowGroupHint
) {
1160 client
.window_group
= wmhint
->window_group
;
1162 // add window to the appropriate group
1163 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1164 if (! group
) { // no group found, create it!
1165 new BWindowGroup(blackbox
, client
.window_group
);
1166 group
= blackbox
->searchGroup(client
.window_group
);
1169 group
->addWindow(this);
1177 * Gets the value of the WM_NORMAL_HINTS property.
1178 * If the property is not set, then use a set of default values.
1180 void BlackboxWindow::getWMNormalHints(void) {
1182 XSizeHints sizehint
;
1184 client
.min_width
= client
.min_height
=
1185 client
.width_inc
= client
.height_inc
= 1;
1186 client
.base_width
= client
.base_height
= 0;
1187 client
.win_gravity
= NorthWestGravity
;
1189 client
.min_aspect_x
= client
.min_aspect_y
=
1190 client
.max_aspect_x
= client
.max_aspect_y
= 1;
1194 use the full screen, not the strut modified size. otherwise when the
1195 availableArea changes max_width/height will be incorrect and lead to odd
1198 const Rect
& screen_area
= screen
->getRect();
1199 client
.max_width
= screen_area
.width();
1200 client
.max_height
= screen_area
.height();
1202 if (! XGetWMNormalHints(blackbox
->getXDisplay(), client
.window
,
1203 &sizehint
, &icccm_mask
))
1206 client
.normal_hint_flags
= sizehint
.flags
;
1208 if (sizehint
.flags
& PMinSize
) {
1209 if (sizehint
.min_width
>= 0)
1210 client
.min_width
= sizehint
.min_width
;
1211 if (sizehint
.min_height
>= 0)
1212 client
.min_height
= sizehint
.min_height
;
1215 if (sizehint
.flags
& PMaxSize
) {
1216 if (sizehint
.max_width
> static_cast<signed>(client
.min_width
))
1217 client
.max_width
= sizehint
.max_width
;
1219 client
.max_width
= client
.min_width
;
1221 if (sizehint
.max_height
> static_cast<signed>(client
.min_height
))
1222 client
.max_height
= sizehint
.max_height
;
1224 client
.max_height
= client
.min_height
;
1227 if (sizehint
.flags
& PResizeInc
) {
1228 client
.width_inc
= sizehint
.width_inc
;
1229 client
.height_inc
= sizehint
.height_inc
;
1232 #if 0 // we do not support this at the moment
1233 if (sizehint
.flags
& PAspect
) {
1234 client
.min_aspect_x
= sizehint
.min_aspect
.x
;
1235 client
.min_aspect_y
= sizehint
.min_aspect
.y
;
1236 client
.max_aspect_x
= sizehint
.max_aspect
.x
;
1237 client
.max_aspect_y
= sizehint
.max_aspect
.y
;
1241 if (sizehint
.flags
& PBaseSize
) {
1242 client
.base_width
= sizehint
.base_width
;
1243 client
.base_height
= sizehint
.base_height
;
1246 if (sizehint
.flags
& PWinGravity
)
1247 client
.win_gravity
= sizehint
.win_gravity
;
1252 * Gets the NETWM hints for the class' contained window.
1254 void BlackboxWindow::getNetWMHints(void) {
1255 unsigned long workspace
;
1257 if (xatom
->getValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1259 if (workspace
== 0xffffffff)
1262 blackbox_attrib
.workspace
= workspace
;
1265 unsigned long *state
;
1266 unsigned long num
= (unsigned) -1;
1267 if (xatom
->getValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
1271 for (unsigned long i
= 0; i
< num
; ++i
) {
1272 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
))
1274 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_shaded
))
1275 flags
.shaded
= True
;
1276 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
))
1277 flags
.skip_taskbar
= True
;
1278 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_pager
))
1279 flags
.skip_pager
= True
;
1280 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_fullscreen
))
1281 flags
.fullscreen
= True
;
1282 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_hidden
))
1283 setState(IconicState
);
1284 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_vert
))
1286 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_horz
))
1290 flags
.maximized
= 1;
1292 flags
.maximized
= 2;
1294 flags
.maximized
= 3;
1302 * Gets the MWM hints for the class' contained window.
1303 * This is used while initializing the window to its first state, and not
1305 * Returns: true if the MWM hints are successfully retreived and applied;
1306 * false if they are not.
1308 void BlackboxWindow::getMWMHints(void) {
1312 num
= PropMwmHintsElements
;
1313 if (! xatom
->getValue(client
.window
, XAtom::motif_wm_hints
,
1314 XAtom::motif_wm_hints
, num
,
1315 (unsigned long **)&mwm_hint
))
1317 if (num
< PropMwmHintsElements
) {
1322 if (mwm_hint
->flags
& MwmHintsDecorations
) {
1323 if (mwm_hint
->decorations
& MwmDecorAll
) {
1324 mwm_decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
1325 Decor_Iconify
| Decor_Maximize
;
1327 mwm_decorations
= 0;
1329 if (mwm_hint
->decorations
& MwmDecorBorder
)
1330 mwm_decorations
|= Decor_Border
;
1331 if (mwm_hint
->decorations
& MwmDecorHandle
)
1332 mwm_decorations
|= Decor_Handle
;
1333 if (mwm_hint
->decorations
& MwmDecorTitle
)
1334 mwm_decorations
|= Decor_Titlebar
;
1335 if (mwm_hint
->decorations
& MwmDecorIconify
)
1336 mwm_decorations
|= Decor_Iconify
;
1337 if (mwm_hint
->decorations
& MwmDecorMaximize
)
1338 mwm_decorations
|= Decor_Maximize
;
1342 if (mwm_hint
->flags
& MwmHintsFunctions
) {
1343 if (mwm_hint
->functions
& MwmFuncAll
) {
1344 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
|
1349 if (mwm_hint
->functions
& MwmFuncResize
)
1350 functions
|= Func_Resize
;
1351 if (mwm_hint
->functions
& MwmFuncMove
)
1352 functions
|= Func_Move
;
1353 if (mwm_hint
->functions
& MwmFuncIconify
)
1354 functions
|= Func_Iconify
;
1355 if (mwm_hint
->functions
& MwmFuncMaximize
)
1356 functions
|= Func_Maximize
;
1357 if (mwm_hint
->functions
& MwmFuncClose
)
1358 functions
|= Func_Close
;
1366 * Gets the blackbox hints from the class' contained window.
1367 * This is used while initializing the window to its first state, and not
1369 * Returns: true if the hints are successfully retreived and applied; false if
1372 bool BlackboxWindow::getBlackboxHints(void) {
1374 BlackboxHints
*blackbox_hint
;
1376 num
= PropBlackboxHintsElements
;
1377 if (! xatom
->getValue(client
.window
, XAtom::blackbox_hints
,
1378 XAtom::blackbox_hints
, num
,
1379 (unsigned long **)&blackbox_hint
))
1381 if (num
< PropBlackboxHintsElements
) {
1382 delete [] blackbox_hint
;
1386 if (blackbox_hint
->flags
& AttribShaded
)
1387 flags
.shaded
= (blackbox_hint
->attrib
& AttribShaded
);
1389 if ((blackbox_hint
->flags
& AttribMaxHoriz
) &&
1390 (blackbox_hint
->flags
& AttribMaxVert
))
1391 flags
.maximized
= (blackbox_hint
->attrib
&
1392 (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1393 else if (blackbox_hint
->flags
& AttribMaxVert
)
1394 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxVert
) ? 2 : 0;
1395 else if (blackbox_hint
->flags
& AttribMaxHoriz
)
1396 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1398 if (blackbox_hint
->flags
& AttribOmnipresent
)
1399 flags
.stuck
= (blackbox_hint
->attrib
& AttribOmnipresent
);
1401 if (blackbox_hint
->flags
& AttribWorkspace
)
1402 blackbox_attrib
.workspace
= blackbox_hint
->workspace
;
1404 // if (blackbox_hint->flags & AttribStack)
1405 // don't yet have always on top/bottom for blackbox yet... working
1408 if (blackbox_hint
->flags
& AttribDecoration
) {
1409 switch (blackbox_hint
->decoration
) {
1411 blackbox_attrib
.decoration
= DecorNone
;
1418 // blackbox_attrib.decoration defaults to DecorNormal
1423 delete [] blackbox_hint
;
1429 void BlackboxWindow::getTransientInfo(void) {
1430 if (client
.transient_for
&&
1431 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1432 // reset transient_for in preparation of looking for a new owner
1433 client
.transient_for
->client
.transientList
.remove(this);
1436 // we have no transient_for until we find a new one
1437 client
.transient_for
= (BlackboxWindow
*) 0;
1440 if (! XGetTransientForHint(blackbox
->getXDisplay(), client
.window
,
1442 // transient_for hint not set
1446 if (trans_for
== client
.window
) {
1447 // wierd client... treat this window as a normal window
1451 if (trans_for
== None
|| trans_for
== screen
->getRootWindow()) {
1452 // this is an undocumented interpretation of the ICCCM. a transient
1453 // associated with None/Root/itself is assumed to be a modal root
1454 // transient. we don't support the concept of a global transient,
1455 // so we just associate this transient with nothing, and perhaps
1456 // we will add support later for global modality.
1457 client
.transient_for
= (BlackboxWindow
*) ~0ul;
1462 client
.transient_for
= blackbox
->searchWindow(trans_for
);
1463 if (! client
.transient_for
&&
1464 client
.window_group
&& trans_for
== client
.window_group
) {
1465 // no direct transient_for, perhaps this is a group transient?
1466 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1467 if (group
) client
.transient_for
= group
->find(screen
);
1470 if (! client
.transient_for
|| client
.transient_for
== this) {
1471 // no transient_for found, or we have a wierd client that wants to be
1472 // a transient for itself, so we treat this window as a normal window
1473 client
.transient_for
= (BlackboxWindow
*) 0;
1477 // Check for a circular transient state: this can lock up Blackbox
1478 // when it tries to find the non-transient window for a transient.
1479 BlackboxWindow
*w
= this;
1480 while(w
->client
.transient_for
&&
1481 w
->client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1482 if(w
->client
.transient_for
== this) {
1483 client
.transient_for
= (BlackboxWindow
*) 0;
1486 w
= w
->client
.transient_for
;
1489 if (client
.transient_for
&&
1490 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1491 // register ourselves with our new transient_for
1492 client
.transient_for
->client
.transientList
.push_back(this);
1493 flags
.stuck
= client
.transient_for
->flags
.stuck
;
1498 BlackboxWindow
*BlackboxWindow::getTransientFor(void) const {
1499 if (client
.transient_for
&&
1500 client
.transient_for
!= (BlackboxWindow
*) ~0ul)
1501 return client
.transient_for
;
1507 * This function is responsible for updating both the client and the frame
1509 * According to the ICCCM a client message is not sent for a resize, only a
1512 void BlackboxWindow::configure(int dx
, int dy
,
1513 unsigned int dw
, unsigned int dh
) {
1514 bool send_event
= ((frame
.rect
.x() != dx
|| frame
.rect
.y() != dy
) &&
1517 if (dw
!= frame
.rect
.width() || dh
!= frame
.rect
.height()) {
1518 frame
.rect
.setRect(dx
, dy
, dw
, dh
);
1519 frame
.inside_w
= frame
.rect
.width() - (frame
.border_w
* 2);
1520 frame
.inside_h
= frame
.rect
.height() - (frame
.border_w
* 2);
1522 if (frame
.rect
.right() <= 0 || frame
.rect
.bottom() <= 0)
1523 frame
.rect
.setPos(0, 0);
1525 client
.rect
.setCoords(frame
.rect
.left() + frame
.margin
.left
,
1526 frame
.rect
.top() + frame
.margin
.top
,
1527 frame
.rect
.right() - frame
.margin
.right
,
1528 frame
.rect
.bottom() - frame
.margin
.bottom
);
1531 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
1538 redrawWindowFrame();
1540 frame
.rect
.setPos(dx
, dy
);
1542 XMoveWindow(blackbox
->getXDisplay(), frame
.window
,
1543 frame
.rect
.x(), frame
.rect
.y());
1545 we may have been called just after an opaque window move, so even though
1546 the old coords match the new ones no ConfigureNotify has been sent yet.
1547 There are likely other times when this will be relevant as well.
1549 if (! flags
.moving
) send_event
= True
;
1553 // if moving, the update and event will occur when the move finishes
1554 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1555 frame
.rect
.top() + frame
.margin
.top
);
1558 event
.type
= ConfigureNotify
;
1560 event
.xconfigure
.display
= blackbox
->getXDisplay();
1561 event
.xconfigure
.event
= client
.window
;
1562 event
.xconfigure
.window
= client
.window
;
1563 event
.xconfigure
.x
= client
.rect
.x();
1564 event
.xconfigure
.y
= client
.rect
.y();
1565 event
.xconfigure
.width
= client
.rect
.width();
1566 event
.xconfigure
.height
= client
.rect
.height();
1567 event
.xconfigure
.border_width
= client
.old_bw
;
1568 event
.xconfigure
.above
= frame
.window
;
1569 event
.xconfigure
.override_redirect
= False
;
1571 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1572 StructureNotifyMask
, &event
);
1573 screen
->updateNetizenConfigNotify(&event
);
1574 XFlush(blackbox
->getXDisplay());
1580 void BlackboxWindow::configureShape(void) {
1581 XShapeCombineShape(blackbox
->getXDisplay(), frame
.window
, ShapeBounding
,
1582 frame
.margin
.left
- frame
.border_w
,
1583 frame
.margin
.top
- frame
.border_w
,
1584 client
.window
, ShapeBounding
, ShapeSet
);
1587 XRectangle xrect
[2];
1589 if (decorations
& Decor_Titlebar
) {
1590 xrect
[0].x
= xrect
[0].y
= -frame
.border_w
;
1591 xrect
[0].width
= frame
.rect
.width();
1592 xrect
[0].height
= frame
.title_h
+ (frame
.border_w
* 2);
1596 if (decorations
& Decor_Handle
) {
1597 xrect
[1].x
= -frame
.border_w
;
1598 xrect
[1].y
= frame
.rect
.height() - frame
.margin
.bottom
+
1599 frame
.mwm_border_w
- frame
.border_w
;
1600 xrect
[1].width
= frame
.rect
.width();
1601 xrect
[1].height
= frame
.handle_h
+ (frame
.border_w
* 2);
1605 XShapeCombineRectangles(blackbox
->getXDisplay(), frame
.window
,
1606 ShapeBounding
, 0, 0, xrect
, num
,
1607 ShapeUnion
, Unsorted
);
1612 bool BlackboxWindow::setInputFocus(void) {
1613 if (flags
.focused
) return True
;
1615 assert(flags
.stuck
|| // window must be on the current workspace or sticky
1616 blackbox_attrib
.workspace
== screen
->getCurrentWorkspaceID());
1619 We only do this check for normal windows and dialogs because other windows
1620 do this on purpose, such as kde's kicker, and we don't want to go moving
1623 if (window_type
== Type_Normal
|| window_type
== Type_Dialog
)
1624 if (! frame
.rect
.intersects(screen
->getRect())) {
1625 // client is outside the screen, move it to the center
1626 configure((screen
->getWidth() - frame
.rect
.width()) / 2,
1627 (screen
->getHeight() - frame
.rect
.height()) / 2,
1628 frame
.rect
.width(), frame
.rect
.height());
1631 if (client
.transientList
.size() > 0) {
1632 // transfer focus to any modal transients
1633 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1634 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1635 if ((*it
)->flags
.modal
) return (*it
)->setInputFocus();
1639 if (focus_mode
== F_LocallyActive
|| focus_mode
== F_Passive
) {
1640 XSetInputFocus(blackbox
->getXDisplay(), client
.window
,
1641 RevertToPointerRoot
, CurrentTime
);
1643 /* we could set the focus to none, since the window doesn't accept focus,
1644 * but we shouldn't set focus to nothing since this would surely make
1650 if (flags
.send_focus_message
) {
1652 ce
.xclient
.type
= ClientMessage
;
1653 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1654 ce
.xclient
.display
= blackbox
->getXDisplay();
1655 ce
.xclient
.window
= client
.window
;
1656 ce
.xclient
.format
= 32;
1657 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_take_focus
);
1658 ce
.xclient
.data
.l
[1] = blackbox
->getLastTime();
1659 ce
.xclient
.data
.l
[2] = 0l;
1660 ce
.xclient
.data
.l
[3] = 0l;
1661 ce
.xclient
.data
.l
[4] = 0l;
1662 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1664 XFlush(blackbox
->getXDisplay());
1671 void BlackboxWindow::iconify(void) {
1672 if (flags
.iconic
|| ! (functions
& Func_Iconify
)) return;
1674 // We don't need to worry about resizing because resizing always grabs the X
1675 // server. This should only ever happen if using opaque moving.
1679 if (windowmenu
) windowmenu
->hide();
1682 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1683 * we need to clear the event mask on client.window for a split second.
1684 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1685 * split second, leaving us with a ghost window... so, we need to do this
1686 * while the X server is grabbed
1688 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1689 StructureNotifyMask
;
1690 XGrabServer(blackbox
->getXDisplay());
1691 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1692 event_mask
& ~StructureNotifyMask
);
1693 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1694 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1695 XUngrabServer(blackbox
->getXDisplay());
1697 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1698 flags
.visible
= False
;
1699 flags
.iconic
= True
;
1701 setState(IconicState
);
1703 screen
->getWorkspace(blackbox_attrib
.workspace
)->removeWindow(this);
1705 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
1706 if (i
!= blackbox_attrib
.workspace
)
1707 screen
->getWorkspace(i
)->removeWindow(this, True
);
1710 if (isTransient()) {
1711 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1712 ! client
.transient_for
->flags
.iconic
) {
1713 // iconify our transient_for
1714 client
.transient_for
->iconify();
1718 screen
->addIcon(this);
1720 if (client
.transientList
.size() > 0) {
1721 // iconify all transients
1722 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1723 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1724 if (! (*it
)->flags
.iconic
) (*it
)->iconify();
1727 screen
->updateStackingList();
1731 void BlackboxWindow::show(void) {
1732 flags
.visible
= True
;
1733 flags
.iconic
= False
;
1735 current_state
= (flags
.shaded
) ? IconicState
: NormalState
;
1736 setState(current_state
);
1738 XMapWindow(blackbox
->getXDisplay(), client
.window
);
1739 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
1740 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
1745 XTranslateCoordinates(blackbox
->getXDisplay(), client
.window
,
1746 screen
->getRootWindow(),
1747 0, 0, &real_x
, &real_y
, &child
);
1748 fprintf(stderr
, "%s -- assumed: (%d, %d), real: (%d, %d)\n", getTitle(),
1749 client
.rect
.left(), client
.rect
.top(), real_x
, real_y
);
1750 assert(client
.rect
.left() == real_x
&& client
.rect
.top() == real_y
);
1755 void BlackboxWindow::deiconify(bool reassoc
, bool raise
) {
1756 if (flags
.iconic
|| reassoc
)
1757 screen
->reassociateWindow(this, BSENTINEL
, False
);
1758 else if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID())
1763 // reassociate and deiconify all transients
1764 if (reassoc
&& client
.transientList
.size() > 0) {
1765 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1766 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1767 (*it
)->deiconify(True
, False
);
1771 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1775 void BlackboxWindow::close(void) {
1776 if (! (functions
& Func_Close
)) return;
1779 ce
.xclient
.type
= ClientMessage
;
1780 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1781 ce
.xclient
.display
= blackbox
->getXDisplay();
1782 ce
.xclient
.window
= client
.window
;
1783 ce
.xclient
.format
= 32;
1784 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_delete_window
);
1785 ce
.xclient
.data
.l
[1] = CurrentTime
;
1786 ce
.xclient
.data
.l
[2] = 0l;
1787 ce
.xclient
.data
.l
[3] = 0l;
1788 ce
.xclient
.data
.l
[4] = 0l;
1789 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
, NoEventMask
, &ce
);
1790 XFlush(blackbox
->getXDisplay());
1794 void BlackboxWindow::withdraw(void) {
1795 // We don't need to worry about resizing because resizing always grabs the X
1796 // server. This should only ever happen if using opaque moving.
1800 flags
.visible
= False
;
1801 flags
.iconic
= False
;
1803 setState(current_state
);
1805 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1807 XGrabServer(blackbox
->getXDisplay());
1809 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1810 StructureNotifyMask
;
1811 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1812 event_mask
& ~StructureNotifyMask
);
1813 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1814 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1816 XUngrabServer(blackbox
->getXDisplay());
1818 if (windowmenu
) windowmenu
->hide();
1822 void BlackboxWindow::maximize(unsigned int button
) {
1823 if (! (functions
& Func_Maximize
)) return;
1825 // We don't need to worry about resizing because resizing always grabs the X
1826 // server. This should only ever happen if using opaque moving.
1830 // handle case where menu is open then the max button is used instead
1831 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
1833 if (flags
.maximized
) {
1834 flags
.maximized
= 0;
1836 blackbox_attrib
.flags
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1837 blackbox_attrib
.attrib
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1840 when a resize finishes, maximize(0) is called to clear any maximization
1841 flags currently set. Otherwise it still thinks it is maximized.
1842 so we do not need to call configure() because resizing will handle it
1844 if (! flags
.resizing
)
1845 configure(blackbox_attrib
.premax_x
, blackbox_attrib
.premax_y
,
1846 blackbox_attrib
.premax_w
, blackbox_attrib
.premax_h
);
1848 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
1849 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
1851 redrawAllButtons(); // in case it is not called in configure()
1852 setState(current_state
);
1856 blackbox_attrib
.premax_x
= frame
.rect
.x();
1857 blackbox_attrib
.premax_y
= frame
.rect
.y();
1858 blackbox_attrib
.premax_w
= frame
.rect
.width();
1859 // use client.rect so that clients can be restored even if shaded
1860 blackbox_attrib
.premax_h
=
1861 client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
;
1864 if (screen
->isXineramaActive() && blackbox
->doXineramaMaximizing()) {
1865 // find the area to use
1866 RectList availableAreas
= screen
->allAvailableAreas();
1867 RectList::iterator it
, end
= availableAreas
.end();
1869 for (it
= availableAreas
.begin(); it
!= end
; ++it
)
1870 if (it
->intersects(frame
.rect
)) break;
1871 if (it
== end
) // the window isn't inside an area
1872 it
= availableAreas
.begin(); // so just default to the first one
1874 frame
.changing
= *it
;
1877 frame
.changing
= screen
->availableArea();
1881 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1882 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1886 blackbox_attrib
.flags
|= AttribMaxVert
;
1887 blackbox_attrib
.attrib
|= AttribMaxVert
;
1889 frame
.changing
.setX(frame
.rect
.x());
1890 frame
.changing
.setWidth(frame
.rect
.width());
1894 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1895 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1897 frame
.changing
.setY(frame
.rect
.y());
1898 frame
.changing
.setHeight(frame
.rect
.height());
1905 blackbox_attrib
.flags
^= AttribShaded
;
1906 blackbox_attrib
.attrib
^= AttribShaded
;
1907 flags
.shaded
= False
;
1910 flags
.maximized
= button
;
1912 configure(frame
.changing
.x(), frame
.changing
.y(),
1913 frame
.changing
.width(), frame
.changing
.height());
1915 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1916 redrawAllButtons(); // in case it is not called in configure()
1917 setState(current_state
);
1921 // re-maximizes the window to take into account availableArea changes
1922 void BlackboxWindow::remaximize(void) {
1924 // we only update the window's attributes otherwise we lose the shade bit
1925 switch(flags
.maximized
) {
1927 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1928 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1932 blackbox_attrib
.flags
|= AttribMaxVert
;
1933 blackbox_attrib
.attrib
|= AttribMaxVert
;
1937 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1938 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1944 // save the original dimensions because maximize will wipe them out
1945 int premax_x
= blackbox_attrib
.premax_x
,
1946 premax_y
= blackbox_attrib
.premax_y
,
1947 premax_w
= blackbox_attrib
.premax_w
,
1948 premax_h
= blackbox_attrib
.premax_h
;
1950 unsigned int button
= flags
.maximized
;
1951 flags
.maximized
= 0; // trick maximize() into working
1954 // restore saved values
1955 blackbox_attrib
.premax_x
= premax_x
;
1956 blackbox_attrib
.premax_y
= premax_y
;
1957 blackbox_attrib
.premax_w
= premax_w
;
1958 blackbox_attrib
.premax_h
= premax_h
;
1962 void BlackboxWindow::setWorkspace(unsigned int n
) {
1963 blackbox_attrib
.flags
|= AttribWorkspace
;
1964 blackbox_attrib
.workspace
= n
;
1965 if (n
== BSENTINEL
) { // iconified window
1967 we set the workspace to 'all workspaces' so that taskbars will show the
1968 window. otherwise, it made uniconifying a window imposible without the
1969 blackbox workspace menu
1973 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
, n
);
1977 void BlackboxWindow::shade(void) {
1979 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1980 frame
.inside_w
, frame
.inside_h
);
1981 flags
.shaded
= False
;
1982 blackbox_attrib
.flags
^= AttribShaded
;
1983 blackbox_attrib
.attrib
^= AttribShaded
;
1985 setState(NormalState
);
1987 // set the frame rect to the normal size
1988 frame
.rect
.setHeight(client
.rect
.height() + frame
.margin
.top
+
1989 frame
.margin
.bottom
);
1991 if (! (decorations
& Decor_Titlebar
))
1992 return; // can't shade it without a titlebar!
1994 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1995 frame
.inside_w
, frame
.title_h
);
1996 flags
.shaded
= True
;
1997 blackbox_attrib
.flags
|= AttribShaded
;
1998 blackbox_attrib
.attrib
|= AttribShaded
;
2000 setState(IconicState
);
2002 // set the frame rect to the shaded size
2003 frame
.rect
.setHeight(frame
.title_h
+ (frame
.border_w
* 2));
2009 * (Un)Sticks a window and its relatives.
2011 void BlackboxWindow::stick(void) {
2013 blackbox_attrib
.flags
^= AttribOmnipresent
;
2014 blackbox_attrib
.attrib
^= AttribOmnipresent
;
2016 flags
.stuck
= False
;
2018 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
2019 if (i
!= blackbox_attrib
.workspace
)
2020 screen
->getWorkspace(i
)->removeWindow(this, True
);
2023 screen
->reassociateWindow(this, BSENTINEL
, True
);
2024 // temporary fix since sticky windows suck. set the hint to what we
2025 // actually hold in our data.
2026 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
2027 blackbox_attrib
.workspace
);
2029 setState(current_state
);
2033 blackbox_attrib
.flags
|= AttribOmnipresent
;
2034 blackbox_attrib
.attrib
|= AttribOmnipresent
;
2036 // temporary fix since sticky windows suck. set the hint to a different
2037 // value than that contained in the class' data.
2038 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
2041 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
2042 if (i
!= blackbox_attrib
.workspace
)
2043 screen
->getWorkspace(i
)->addWindow(this, False
, True
);
2045 setState(current_state
);
2048 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
2049 client
.transient_for
->isStuck() != flags
.stuck
)
2050 client
.transient_for
->stick();
2051 // go down the chain
2052 BlackboxWindowList::iterator it
;
2053 const BlackboxWindowList::iterator end
= client
.transientList
.end();
2054 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
2055 if ((*it
)->isStuck() != flags
.stuck
)
2060 void BlackboxWindow::redrawWindowFrame(void) const {
2061 if (decorations
& Decor_Titlebar
) {
2062 if (flags
.focused
) {
2064 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2065 frame
.title
, frame
.ftitle
);
2067 XSetWindowBackground(blackbox
->getXDisplay(),
2068 frame
.title
, frame
.ftitle_pixel
);
2071 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2072 frame
.title
, frame
.utitle
);
2074 XSetWindowBackground(blackbox
->getXDisplay(),
2075 frame
.title
, frame
.utitle_pixel
);
2077 XClearWindow(blackbox
->getXDisplay(), frame
.title
);
2083 if (decorations
& Decor_Handle
) {
2084 if (flags
.focused
) {
2086 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2087 frame
.handle
, frame
.fhandle
);
2089 XSetWindowBackground(blackbox
->getXDisplay(),
2090 frame
.handle
, frame
.fhandle_pixel
);
2093 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2094 frame
.left_grip
, frame
.fgrip
);
2095 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2096 frame
.right_grip
, frame
.fgrip
);
2098 XSetWindowBackground(blackbox
->getXDisplay(),
2099 frame
.left_grip
, frame
.fgrip_pixel
);
2100 XSetWindowBackground(blackbox
->getXDisplay(),
2101 frame
.right_grip
, frame
.fgrip_pixel
);
2105 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2106 frame
.handle
, frame
.uhandle
);
2108 XSetWindowBackground(blackbox
->getXDisplay(),
2109 frame
.handle
, frame
.uhandle_pixel
);
2112 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2113 frame
.left_grip
, frame
.ugrip
);
2114 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2115 frame
.right_grip
, frame
.ugrip
);
2117 XSetWindowBackground(blackbox
->getXDisplay(),
2118 frame
.left_grip
, frame
.ugrip_pixel
);
2119 XSetWindowBackground(blackbox
->getXDisplay(),
2120 frame
.right_grip
, frame
.ugrip_pixel
);
2123 XClearWindow(blackbox
->getXDisplay(), frame
.handle
);
2124 XClearWindow(blackbox
->getXDisplay(), frame
.left_grip
);
2125 XClearWindow(blackbox
->getXDisplay(), frame
.right_grip
);
2128 if (decorations
& Decor_Border
) {
2130 XSetWindowBorder(blackbox
->getXDisplay(),
2131 frame
.plate
, frame
.fborder_pixel
);
2133 XSetWindowBorder(blackbox
->getXDisplay(),
2134 frame
.plate
, frame
.uborder_pixel
);
2139 void BlackboxWindow::setFocusFlag(bool focus
) {
2140 // only focus a window if it is visible
2141 if (focus
&& ! flags
.visible
)
2144 flags
.focused
= focus
;
2146 redrawWindowFrame();
2149 blackbox
->setFocusedWindow(this);
2151 if (! flags
.iconic
) {
2152 // iconic windows arent in a workspace menu!
2154 screen
->getCurrentWorkspace()->setFocused(this, isFocused());
2156 screen
->getWorkspace(blackbox_attrib
.workspace
)->
2157 setFocused(this, flags
.focused
);
2162 void BlackboxWindow::installColormap(bool install
) {
2163 int i
= 0, ncmap
= 0;
2164 Colormap
*cmaps
= XListInstalledColormaps(blackbox
->getXDisplay(),
2165 client
.window
, &ncmap
);
2167 XWindowAttributes wattrib
;
2168 if (XGetWindowAttributes(blackbox
->getXDisplay(),
2169 client
.window
, &wattrib
)) {
2171 // install the window's colormap
2172 for (i
= 0; i
< ncmap
; i
++) {
2173 if (*(cmaps
+ i
) == wattrib
.colormap
)
2174 // this window is using an installed color map... do not install
2177 // otherwise, install the window's colormap
2179 XInstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2181 // uninstall the window's colormap
2182 for (i
= 0; i
< ncmap
; i
++) {
2183 if (*(cmaps
+ i
) == wattrib
.colormap
)
2184 // we found the colormap to uninstall
2185 XUninstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2195 void BlackboxWindow::setAllowedActions(void) {
2199 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_shade
);
2200 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_change_desktop
);
2201 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_close
);
2203 if (functions
& Func_Move
)
2204 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_move
);
2205 if (functions
& Func_Resize
)
2206 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_resize
);
2207 if (functions
& Func_Maximize
) {
2208 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_horz
);
2209 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_vert
);
2212 xatom
->setValue(client
.window
, XAtom::net_wm_allowed_actions
, XAtom::atom
,
2217 void BlackboxWindow::setState(unsigned long new_state
) {
2218 current_state
= new_state
;
2220 unsigned long state
[2];
2221 state
[0] = current_state
;
2223 xatom
->setValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
, state
, 2);
2225 xatom
->setValue(client
.window
, XAtom::blackbox_attributes
,
2226 XAtom::blackbox_attributes
, (unsigned long *)&blackbox_attrib
,
2227 PropBlackboxAttributesElements
);
2232 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_modal
);
2234 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_shaded
);
2236 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_hidden
);
2237 if (flags
.skip_taskbar
)
2238 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
);
2239 if (flags
.skip_pager
)
2240 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_pager
);
2241 if (flags
.fullscreen
)
2242 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_fullscreen
);
2243 if (flags
.maximized
== 1 || flags
.maximized
== 2)
2244 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_vert
);
2245 if (flags
.maximized
== 1 || flags
.maximized
== 3)
2246 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_horz
);
2247 xatom
->setValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
2252 bool BlackboxWindow::getState(void) {
2253 bool ret
= xatom
->getValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
,
2255 if (! ret
) current_state
= 0;
2260 void BlackboxWindow::restoreAttributes(void) {
2261 unsigned long num
= PropBlackboxAttributesElements
;
2262 BlackboxAttributes
*net
;
2263 if (! xatom
->getValue(client
.window
, XAtom::blackbox_attributes
,
2264 XAtom::blackbox_attributes
, num
,
2265 (unsigned long **)&net
))
2267 if (num
< PropBlackboxAttributesElements
) {
2272 if (net
->flags
& AttribShaded
&& net
->attrib
& AttribShaded
) {
2273 flags
.shaded
= False
;
2274 unsigned long orig_state
= current_state
;
2278 At this point in the life of a window, current_state should only be set
2279 to IconicState if the window was an *icon*, not if it was shaded.
2281 if (orig_state
!= IconicState
)
2282 current_state
= WithdrawnState
;
2285 if (net
->workspace
!= screen
->getCurrentWorkspaceID() &&
2286 net
->workspace
< screen
->getWorkspaceCount())
2287 screen
->reassociateWindow(this, net
->workspace
, True
);
2289 if ((blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID()) &&
2290 (blackbox_attrib
.workspace
< screen
->getWorkspaceCount())) {
2291 // set to WithdrawnState so it will be mapped on the new workspace
2292 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2293 } else if (current_state
== WithdrawnState
) {
2294 // the window is on this workspace and is Withdrawn, so it is waiting to
2296 current_state
= NormalState
;
2299 if (net
->flags
& AttribOmnipresent
&& net
->attrib
& AttribOmnipresent
&&
2303 // if the window was on another workspace, it was going to be hidden. this
2304 // specifies that the window should be mapped since it is sticky.
2305 if (current_state
== WithdrawnState
) current_state
= NormalState
;
2308 if (net
->flags
& AttribMaxHoriz
|| net
->flags
& AttribMaxVert
) {
2309 int x
= net
->premax_x
, y
= net
->premax_y
;
2310 unsigned int w
= net
->premax_w
, h
= net
->premax_h
;
2311 flags
.maximized
= 0;
2314 if ((net
->flags
& AttribMaxHoriz
) &&
2315 (net
->flags
& AttribMaxVert
))
2316 m
= (net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
2317 else if (net
->flags
& AttribMaxVert
)
2318 m
= (net
->attrib
& AttribMaxVert
) ? 2 : 0;
2319 else if (net
->flags
& AttribMaxHoriz
)
2320 m
= (net
->attrib
& AttribMaxHoriz
) ? 3 : 0;
2324 blackbox_attrib
.premax_x
= x
;
2325 blackbox_attrib
.premax_y
= y
;
2326 blackbox_attrib
.premax_w
= w
;
2327 blackbox_attrib
.premax_h
= h
;
2330 if (net
->flags
& AttribDecoration
) {
2331 switch (net
->decoration
) {
2336 /* since tools only let you toggle this anyways, we'll just make that all
2337 it supports for now.
2348 // with the state set it will then be the map event's job to read the
2349 // window's state and behave accordingly
2356 * Positions the Rect r according the the client window position and
2359 void BlackboxWindow::applyGravity(Rect
&r
) {
2360 // apply horizontal window gravity
2361 switch (client
.win_gravity
) {
2363 case NorthWestGravity
:
2364 case SouthWestGravity
:
2366 r
.setX(client
.rect
.x());
2372 r
.setX(client
.rect
.x() - (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2375 case NorthEastGravity
:
2376 case SouthEastGravity
:
2378 r
.setX(client
.rect
.x() - frame
.margin
.left
- frame
.margin
.right
+ 2);
2383 r
.setX(client
.rect
.x() - frame
.margin
.left
);
2387 // apply vertical window gravity
2388 switch (client
.win_gravity
) {
2390 case NorthWestGravity
:
2391 case NorthEastGravity
:
2393 r
.setY(client
.rect
.y());
2399 r
.setY(client
.rect
.y() - (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2402 case SouthWestGravity
:
2403 case SouthEastGravity
:
2405 r
.setY(client
.rect
.y() - frame
.margin
.top
- frame
.margin
.bottom
+ 2);
2410 r
.setY(client
.rect
.y() - frame
.margin
.top
);
2417 * The reverse of the applyGravity function.
2419 * Positions the Rect r according to the frame window position and
2422 void BlackboxWindow::restoreGravity(Rect
&r
) {
2423 // restore horizontal window gravity
2424 switch (client
.win_gravity
) {
2426 case NorthWestGravity
:
2427 case SouthWestGravity
:
2429 r
.setX(frame
.rect
.x());
2435 r
.setX(frame
.rect
.x() + (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2438 case NorthEastGravity
:
2439 case SouthEastGravity
:
2441 r
.setX(frame
.rect
.x() + frame
.margin
.left
+ frame
.margin
.right
- 2);
2446 r
.setX(frame
.rect
.x() + frame
.margin
.left
);
2450 // restore vertical window gravity
2451 switch (client
.win_gravity
) {
2453 case NorthWestGravity
:
2454 case NorthEastGravity
:
2456 r
.setY(frame
.rect
.y());
2462 r
.setY(frame
.rect
.y() + (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2465 case SouthWestGravity
:
2466 case SouthEastGravity
:
2468 r
.setY(frame
.rect
.y() + frame
.margin
.top
+ frame
.margin
.bottom
- 2);
2473 r
.setY(frame
.rect
.y() + frame
.margin
.top
);
2479 void BlackboxWindow::redrawLabel(void) const {
2480 if (flags
.focused
) {
2482 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2483 frame
.label
, frame
.flabel
);
2485 XSetWindowBackground(blackbox
->getXDisplay(),
2486 frame
.label
, frame
.flabel_pixel
);
2489 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2490 frame
.label
, frame
.ulabel
);
2492 XSetWindowBackground(blackbox
->getXDisplay(),
2493 frame
.label
, frame
.ulabel_pixel
);
2495 XClearWindow(blackbox
->getXDisplay(), frame
.label
);
2497 WindowStyle
*style
= screen
->getWindowStyle();
2499 int pos
= frame
.bevel_w
* 2;
2500 style
->doJustify(client
.title
.c_str(), pos
, frame
.label_w
, frame
.bevel_w
* 4);
2501 style
->font
->drawString(frame
.label
, pos
, 1,
2502 (flags
.focused
? style
->l_text_focus
:
2503 style
->l_text_unfocus
),
2508 void BlackboxWindow::redrawAllButtons(void) const {
2509 if (frame
.iconify_button
) redrawIconifyButton(False
);
2510 if (frame
.maximize_button
) redrawMaximizeButton(flags
.maximized
);
2511 if (frame
.close_button
) redrawCloseButton(False
);
2515 void BlackboxWindow::redrawIconifyButton(bool pressed
) const {
2517 if (flags
.focused
) {
2519 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2520 frame
.iconify_button
, frame
.fbutton
);
2522 XSetWindowBackground(blackbox
->getXDisplay(),
2523 frame
.iconify_button
, frame
.fbutton_pixel
);
2526 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2527 frame
.iconify_button
, frame
.ubutton
);
2529 XSetWindowBackground(blackbox
->getXDisplay(), frame
.iconify_button
,
2530 frame
.ubutton_pixel
);
2534 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2535 frame
.iconify_button
, frame
.pbutton
);
2537 XSetWindowBackground(blackbox
->getXDisplay(),
2538 frame
.iconify_button
, frame
.pbutton_pixel
);
2540 XClearWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
2542 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2543 screen
->getWindowStyle()->b_pic_unfocus
);
2544 XDrawRectangle(blackbox
->getXDisplay(), frame
.iconify_button
, pen
.gc(),
2545 2, (frame
.button_w
- 5), (frame
.button_w
- 5), 2);
2549 void BlackboxWindow::redrawMaximizeButton(bool pressed
) const {
2551 if (flags
.focused
) {
2553 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2554 frame
.maximize_button
, frame
.fbutton
);
2556 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2557 frame
.fbutton_pixel
);
2560 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2561 frame
.maximize_button
, frame
.ubutton
);
2563 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2564 frame
.ubutton_pixel
);
2568 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2569 frame
.maximize_button
, frame
.pbutton
);
2571 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2572 frame
.pbutton_pixel
);
2574 XClearWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
2576 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2577 screen
->getWindowStyle()->b_pic_unfocus
);
2578 XDrawRectangle(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2579 2, 2, (frame
.button_w
- 5), (frame
.button_w
- 5));
2580 XDrawLine(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2581 2, 3, (frame
.button_w
- 3), 3);
2585 void BlackboxWindow::redrawCloseButton(bool pressed
) const {
2587 if (flags
.focused
) {
2589 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2592 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2593 frame
.fbutton_pixel
);
2596 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2599 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2600 frame
.ubutton_pixel
);
2604 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2605 frame
.close_button
, frame
.pbutton
);
2607 XSetWindowBackground(blackbox
->getXDisplay(),
2608 frame
.close_button
, frame
.pbutton_pixel
);
2610 XClearWindow(blackbox
->getXDisplay(), frame
.close_button
);
2612 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2613 screen
->getWindowStyle()->b_pic_unfocus
);
2614 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2615 2, 2, (frame
.button_w
- 3), (frame
.button_w
- 3));
2616 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2617 2, (frame
.button_w
- 3), (frame
.button_w
- 3), 2);
2621 void BlackboxWindow::mapRequestEvent(const XMapRequestEvent
*re
) {
2622 if (re
->window
!= client
.window
)
2626 fprintf(stderr
, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2631 Even though the window wants to be shown, if it is not on the current
2632 workspace, then it isn't going to be shown right now.
2634 if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID() &&
2635 blackbox_attrib
.workspace
< screen
->getWorkspaceCount())
2636 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2638 switch (current_state
) {
2643 case WithdrawnState
:
2652 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2654 if (! blackbox
->isStartup()) {
2655 XSync(blackbox
->getXDisplay(), False
); // make sure the frame is mapped
2656 if (screen
->doFocusNew() || (isTransient() && getTransientFor() &&
2657 getTransientFor()->isFocused())) {
2660 if (screen
->getPlacementPolicy() == BScreen::ClickMousePlacement
) {
2664 XQueryPointer(blackbox
->getXDisplay(), screen
->getRootWindow(),
2665 &r
, &c
, &rx
, &ry
, &x
, &y
, &m
);
2675 void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent
*ue
) {
2676 if (ue
->window
!= client
.window
)
2680 fprintf(stderr
, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2684 screen
->unmanageWindow(this, False
);
2688 void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent
*de
) {
2689 if (de
->window
!= client
.window
)
2693 fprintf(stderr
, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2697 screen
->unmanageWindow(this, False
);
2701 void BlackboxWindow::reparentNotifyEvent(const XReparentEvent
*re
) {
2702 if (re
->window
!= client
.window
|| re
->parent
== frame
.plate
)
2706 fprintf(stderr
, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2707 "0x%lx.\n", client
.window
, re
->parent
);
2712 XPutBackEvent(blackbox
->getXDisplay(), &ev
);
2713 screen
->unmanageWindow(this, True
);
2717 void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent
*pe
) {
2718 if (pe
->state
== PropertyDelete
|| ! validateClient())
2722 fprintf(stderr
, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n",
2728 case XA_WM_CLIENT_MACHINE
:
2732 case XA_WM_TRANSIENT_FOR
: {
2733 bool s
= flags
.stuck
;
2735 // determine if this is a transient window
2738 if (flags
.stuck
!= s
) stick();
2740 // adjust the window decorations based on transience
2741 if (isTransient()) {
2742 functions
&= ~Func_Maximize
;
2743 setAllowedActions();
2755 case XA_WM_ICON_NAME
:
2757 if (flags
.iconic
) screen
->propagateWindowName(this);
2760 case XAtom::net_wm_name
:
2764 if (decorations
& Decor_Titlebar
)
2767 screen
->propagateWindowName(this);
2770 case XA_WM_NORMAL_HINTS
: {
2773 if ((client
.normal_hint_flags
& PMinSize
) &&
2774 (client
.normal_hint_flags
& PMaxSize
)) {
2775 // the window now can/can't resize itself, so the buttons need to be
2778 if (client
.max_width
<= client
.min_width
&&
2779 client
.max_height
<= client
.min_height
) {
2780 functions
&= ~(Func_Resize
| Func_Maximize
);
2782 if (! isTransient())
2783 functions
|= Func_Maximize
;
2784 functions
|= Func_Resize
;
2787 setAllowedActions();
2791 Rect old_rect
= frame
.rect
;
2795 if (old_rect
!= frame
.rect
)
2802 if (pe
->atom
== xatom
->getAtom(XAtom::wm_protocols
)) {
2805 if ((decorations
& Decor_Close
) && (! frame
.close_button
)) {
2806 createCloseButton();
2807 if (decorations
& Decor_Titlebar
) {
2808 positionButtons(True
);
2809 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
2811 if (windowmenu
) windowmenu
->reconfigure();
2813 } else if (pe
->atom
== xatom
->getAtom(XAtom::net_wm_strut
)) {
2822 void BlackboxWindow::exposeEvent(const XExposeEvent
*ee
) {
2824 fprintf(stderr
, "BlackboxWindow::exposeEvent() for 0x%lx\n", client
.window
);
2827 if (frame
.label
== ee
->window
&& (decorations
& Decor_Titlebar
))
2829 else if (frame
.close_button
== ee
->window
)
2830 redrawCloseButton(False
);
2831 else if (frame
.maximize_button
== ee
->window
)
2832 redrawMaximizeButton(flags
.maximized
);
2833 else if (frame
.iconify_button
== ee
->window
)
2834 redrawIconifyButton(False
);
2838 void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent
*cr
) {
2839 if (cr
->window
!= client
.window
|| flags
.iconic
)
2842 if (cr
->value_mask
& CWBorderWidth
)
2843 client
.old_bw
= cr
->border_width
;
2845 if (cr
->value_mask
& (CWX
| CWY
| CWWidth
| CWHeight
)) {
2846 frame
.changing
= frame
.rect
;
2848 if (cr
->value_mask
& (CWX
| CWY
)) {
2849 if (cr
->value_mask
& CWX
)
2850 client
.rect
.setX(cr
->x
);
2851 if (cr
->value_mask
& CWY
)
2852 client
.rect
.setY(cr
->y
);
2854 applyGravity(frame
.changing
);
2857 if (cr
->value_mask
& (CWWidth
| CWHeight
)) {
2858 if (cr
->value_mask
& CWWidth
)
2859 frame
.changing
.setWidth(cr
->width
+
2860 frame
.margin
.left
+ frame
.margin
.right
);
2862 if (cr
->value_mask
& CWHeight
)
2863 frame
.changing
.setHeight(cr
->height
+
2864 frame
.margin
.top
+ frame
.margin
.bottom
);
2867 if a position change ha been specified, then that position will be used
2868 instead of determining a position based on the window's gravity.
2870 if (cr
->value_mask
& (CWX
| CWY
)) {
2872 switch (client
.win_gravity
) {
2873 case NorthEastGravity
:
2877 case SouthWestGravity
:
2879 corner
= BottomLeft
;
2881 case SouthEastGravity
:
2882 corner
= BottomRight
;
2884 default: // NorthWest, Static, etc
2891 configure(frame
.changing
.x(), frame
.changing
.y(),
2892 frame
.changing
.width(), frame
.changing
.height());
2895 if (cr
->value_mask
& CWStackMode
&& !isDesktop()) {
2896 switch (cr
->detail
) {
2899 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2905 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2912 void BlackboxWindow::buttonPressEvent(const XButtonEvent
*be
) {
2914 fprintf(stderr
, "BlackboxWindow::buttonPressEvent() for 0x%lx\n",
2918 if (frame
.maximize_button
== be
->window
&& be
->button
<= 3) {
2919 redrawMaximizeButton(True
);
2920 } else if (be
->button
== 1 || (be
->button
== 3 && be
->state
== mod_mask
)) {
2921 if (! flags
.focused
)
2924 if (frame
.iconify_button
== be
->window
) {
2925 redrawIconifyButton(True
);
2926 } else if (frame
.close_button
== be
->window
) {
2927 redrawCloseButton(True
);
2928 } else if (frame
.plate
== be
->window
) {
2929 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2931 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2933 XAllowEvents(blackbox
->getXDisplay(), ReplayPointer
, be
->time
);
2935 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
2936 if (((be
->time
- lastButtonPressTime
) <=
2937 blackbox
->getDoubleClickInterval()) ||
2938 (be
->state
== ControlMask
)) {
2939 lastButtonPressTime
= 0;
2942 lastButtonPressTime
= be
->time
;
2946 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2948 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2950 } else if (be
->button
== 2 && (be
->window
!= frame
.iconify_button
) &&
2951 (be
->window
!= frame
.close_button
)) {
2952 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2953 } else if (windowmenu
&& be
->button
== 3 &&
2954 (frame
.title
== be
->window
|| frame
.label
== be
->window
||
2955 frame
.handle
== be
->window
|| frame
.window
== be
->window
)) {
2956 if (windowmenu
->isVisible()) {
2959 int mx
= be
->x_root
- windowmenu
->getWidth() / 2,
2960 my
= be
->y_root
- windowmenu
->getHeight() / 2;
2962 // snap the window menu into a corner/side if necessary
2963 int left_edge
, right_edge
, top_edge
, bottom_edge
;
2966 the " + (frame.border_w * 2) - 1" bits are to get the proper width
2967 and height of the menu, as the sizes returned by it do not include
2970 left_edge
= frame
.rect
.x();
2971 right_edge
= frame
.rect
.right() -
2972 (windowmenu
->getWidth() + (frame
.border_w
* 2) - 1);
2973 top_edge
= client
.rect
.top() - (frame
.border_w
+ frame
.mwm_border_w
);
2974 bottom_edge
= client
.rect
.bottom() -
2975 (windowmenu
->getHeight() + (frame
.border_w
* 2) - 1) +
2976 (frame
.border_w
+ frame
.mwm_border_w
);
2980 if (mx
> right_edge
)
2984 if (my
> bottom_edge
)
2987 windowmenu
->move(mx
, my
);
2989 XRaiseWindow(blackbox
->getXDisplay(), windowmenu
->getWindowID());
2990 XRaiseWindow(blackbox
->getXDisplay(),
2991 windowmenu
->getSendToMenu()->getWindowID());
2994 } else if (be
->button
== 4) {
2995 if ((be
->window
== frame
.label
||
2996 be
->window
== frame
.title
||
2997 be
->window
== frame
.maximize_button
||
2998 be
->window
== frame
.iconify_button
||
2999 be
->window
== frame
.close_button
) &&
3003 } else if (be
->button
== 5) {
3004 if ((be
->window
== frame
.label
||
3005 be
->window
== frame
.title
||
3006 be
->window
== frame
.maximize_button
||
3007 be
->window
== frame
.iconify_button
||
3008 be
->window
== frame
.close_button
) &&
3015 void BlackboxWindow::buttonReleaseEvent(const XButtonEvent
*re
) {
3017 fprintf(stderr
, "BlackboxWindow::buttonReleaseEvent() for 0x%lx\n",
3021 if (re
->window
== frame
.maximize_button
&&
3022 re
->button
>= 1 && re
->button
<= 3) {
3023 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3024 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
3025 maximize(re
->button
);
3027 redrawMaximizeButton(flags
.maximized
);
3029 } else if (re
->window
== frame
.iconify_button
&& re
->button
== 1) {
3030 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3031 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
3034 redrawIconifyButton(False
);
3036 } else if (re
->window
== frame
.close_button
& re
->button
== 1) {
3037 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3038 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
)))
3040 redrawCloseButton(False
);
3041 } else if (flags
.moving
) {
3043 } else if (flags
.resizing
) {
3045 } else if (re
->window
== frame
.window
) {
3046 if (re
->button
== 2 && re
->state
== mod_mask
)
3047 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3053 void BlackboxWindow::beginMove(int x_root
, int y_root
) {
3054 if (! (functions
& Func_Move
)) return;
3056 assert(! (flags
.resizing
|| flags
.moving
));
3059 Only one window can be moved/resized at a time. If another window is already
3060 being moved or resized, then stop it before whating to work with this one.
3062 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3063 if (changing
&& changing
!= this) {
3064 if (changing
->flags
.moving
)
3065 changing
->endMove();
3066 else // if (changing->flags.resizing)
3067 changing
->endResize();
3070 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3071 PointerMotionMask
| ButtonReleaseMask
,
3072 GrabModeAsync
, GrabModeAsync
,
3073 None
, blackbox
->getMoveCursor(), CurrentTime
);
3075 if (windowmenu
&& windowmenu
->isVisible())
3078 flags
.moving
= True
;
3079 blackbox
->setChangingWindow(this);
3081 if (! screen
->doOpaqueMove()) {
3082 XGrabServer(blackbox
->getXDisplay());
3084 frame
.changing
= frame
.rect
;
3085 screen
->showPosition(frame
.changing
.x(), frame
.changing
.y());
3087 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3091 frame
.changing
.width() - 1,
3092 frame
.changing
.height() - 1);
3095 frame
.grab_x
= x_root
- frame
.rect
.x() - frame
.border_w
;
3096 frame
.grab_y
= y_root
- frame
.rect
.y() - frame
.border_w
;
3100 void BlackboxWindow::doMove(int x_root
, int y_root
) {
3101 assert(flags
.moving
);
3102 assert(blackbox
->getChangingWindow() == this);
3104 int dx
= x_root
- frame
.grab_x
, dy
= y_root
- frame
.grab_y
;
3105 dx
-= frame
.border_w
;
3106 dy
-= frame
.border_w
;
3108 doWindowSnapping(dx
, dy
);
3110 if (screen
->doOpaqueMove()) {
3111 if (screen
->doWorkspaceWarping())
3112 doWorkspaceWarping(x_root
, y_root
, dx
);
3114 configure(dx
, dy
, frame
.rect
.width(), frame
.rect
.height());
3116 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3120 frame
.changing
.width() - 1,
3121 frame
.changing
.height() - 1);
3123 if (screen
->doWorkspaceWarping())
3124 doWorkspaceWarping(x_root
, y_root
, dx
);
3126 frame
.changing
.setPos(dx
, dy
);
3128 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3132 frame
.changing
.width() - 1,
3133 frame
.changing
.height() - 1);
3136 screen
->showPosition(dx
, dy
);
3140 void BlackboxWindow::doWorkspaceWarping(int x_root
, int y_root
, int &dx
) {
3141 // workspace warping
3143 unsigned int dest
= screen
->getCurrentWorkspaceID();
3147 if (dest
> 0) dest
--;
3148 else dest
= screen
->getNumberOfWorkspaces() - 1;
3150 } else if (x_root
>= screen
->getRect().right()) {
3153 if (dest
< screen
->getNumberOfWorkspaces() - 1) dest
++;
3159 bool focus
= flags
.focused
; // had focus while moving?
3161 int dest_x
= x_root
;
3163 dest_x
+= screen
->getRect().width() - 1;
3164 dx
+= screen
->getRect().width() - 1;
3166 dest_x
-= screen
->getRect().width() - 1;
3167 dx
-= screen
->getRect().width() - 1;
3171 screen
->reassociateWindow(this, dest
, False
);
3172 screen
->changeWorkspaceID(dest
);
3174 if (screen
->doOpaqueMove())
3175 XGrabServer(blackbox
->getXDisplay());
3177 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3178 XWarpPointer(blackbox
->getXDisplay(), None
,
3179 screen
->getRootWindow(), 0, 0, 0, 0,
3181 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3182 PointerMotionMask
| ButtonReleaseMask
,
3183 GrabModeAsync
, GrabModeAsync
,
3184 None
, blackbox
->getMoveCursor(), CurrentTime
);
3186 if (screen
->doOpaqueMove())
3187 XUngrabServer(blackbox
->getXDisplay());
3195 void BlackboxWindow::doWindowSnapping(int &dx
, int &dy
) {
3196 // how much resistance to edges to provide
3197 const int resistance_size
= screen
->getResistanceSize();
3199 // how far away to snap
3200 const int snap_distance
= screen
->getSnapThreshold();
3202 // how to snap windows
3203 const int snap_to_windows
= screen
->getWindowToWindowSnap();
3204 const int snap_to_edges
= screen
->getWindowToEdgeSnap();
3205 // the amount of space away from the edge to provide resistance/snap
3206 const int snap_offset
= screen
->getSnapOffset();
3208 // find the geomeetery where the moving window currently is
3209 const Rect
&moving
= screen
->doOpaqueMove() ? frame
.rect
: frame
.changing
;
3212 const int wleft
= dx
,
3213 wright
= dx
+ frame
.rect
.width() - 1,
3215 wbottom
= dy
+ frame
.rect
.height() - 1;
3217 if (snap_to_windows
) {
3220 Workspace
*w
= screen
->getWorkspace(getWorkspaceNumber());
3223 // add windows on the workspace to the rect list
3224 const BlackboxWindowList
& stack_list
= w
->getStackingList();
3225 BlackboxWindowList::const_iterator st_it
, st_end
= stack_list
.end();
3226 for (st_it
= stack_list
.begin(); st_it
!= st_end
; ++st_it
)
3227 if (*st_it
!= this) // don't snap to ourself
3228 rectlist
.push_back( (*st_it
)->frameRect() );
3230 // add the toolbar and the slit to the rect list.
3231 // (only if they are not hidden)
3232 Toolbar
*tbar
= screen
->getToolbar();
3233 Slit
*slit
= screen
->getSlit();
3234 Rect tbar_rect
, slit_rect
;
3235 unsigned int bwidth
= screen
->getBorderWidth() * 2;
3237 if (! (screen
->doHideToolbar() || tbar
->isHidden())) {
3238 tbar_rect
.setRect(tbar
->getX(), tbar
->getY(), tbar
->getWidth() + bwidth
,
3239 tbar
->getHeight() + bwidth
);
3240 rectlist
.push_back(tbar_rect
);
3243 if (! slit
->isHidden()) {
3244 slit_rect
.setRect(slit
->getX(), slit
->getY(), slit
->getWidth() + bwidth
,
3245 slit
->getHeight() + bwidth
);
3246 rectlist
.push_back(slit_rect
);
3249 RectList::const_iterator it
, end
= rectlist
.end();
3250 for (it
= rectlist
.begin(); it
!= end
; ++it
) {
3251 bool snapped
= False
;
3252 const Rect
&winrect
= *it
;
3254 offsetrect
.setCoords(winrect
.left() - snap_offset
,
3255 winrect
.top() - snap_offset
,
3256 winrect
.right() + snap_offset
,
3257 winrect
.bottom() + snap_offset
);
3259 if (snap_to_windows
== BScreen::WindowResistance
)
3260 // if the window is already over top of this snap target, then
3261 // resistance is futile, so just ignore it
3262 if (winrect
.intersects(moving
))
3265 int dleft
, dright
, dtop
, dbottom
;
3267 // if the windows are in the same plane vertically
3268 if (wtop
>= (signed)(winrect
.y() - frame
.rect
.height() + 1) &&
3269 wtop
< (signed)(winrect
.y() + winrect
.height() - 1)) {
3271 if (snap_to_windows
== BScreen::WindowResistance
) {
3272 dleft
= wright
- offsetrect
.left();
3273 dright
= offsetrect
.right() - wleft
;
3275 // snap left of other window?
3276 if (dleft
>= 0 && dleft
< resistance_size
&&
3277 dleft
< (wright
- wleft
)) {
3278 dx
= offsetrect
.left() - frame
.rect
.width();
3281 // snap right of other window?
3282 else if (dright
>= 0 && dright
< resistance_size
&&
3283 dright
< (wright
- wleft
)) {
3284 dx
= offsetrect
.right() + 1;
3287 } else { // BScreen::WindowSnap
3288 dleft
= abs(wright
- offsetrect
.left());
3289 dright
= abs(wleft
- offsetrect
.right());
3291 // snap left of other window?
3292 if (dleft
< snap_distance
&& dleft
<= dright
) {
3293 dx
= offsetrect
.left() - frame
.rect
.width();
3296 // snap right of other window?
3297 else if (dright
< snap_distance
) {
3298 dx
= offsetrect
.right() + 1;
3304 if (screen
->getWindowCornerSnap()) {
3305 // try corner-snap to its other sides
3306 if (snap_to_windows
== BScreen::WindowResistance
) {
3307 dtop
= winrect
.top() - wtop
;
3308 dbottom
= wbottom
- winrect
.bottom();
3309 if (dtop
> 0 && dtop
< resistance_size
) {
3310 // if we're already past the top edge, then don't provide
3312 if (moving
.top() >= winrect
.top())
3314 } else if (dbottom
> 0 && dbottom
< resistance_size
) {
3315 // if we're already past the bottom edge, then don't provide
3317 if (moving
.bottom() <= winrect
.bottom())
3318 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
3320 } else { // BScreen::WindowSnap
3321 dtop
= abs(wtop
- winrect
.top());
3322 dbottom
= abs(wbottom
- winrect
.bottom());
3323 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3325 else if (dbottom
< snap_distance
)
3326 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
3334 // if the windows are on the same plane horizontally
3335 if (wleft
>= (signed)(winrect
.x() - frame
.rect
.width() + 1) &&
3336 wleft
< (signed)(winrect
.x() + winrect
.width() - 1)) {
3338 if (snap_to_windows
== BScreen::WindowResistance
) {
3339 dtop
= wbottom
- offsetrect
.top();
3340 dbottom
= offsetrect
.bottom() - wtop
;
3342 // snap top of other window?
3343 if (dtop
>= 0 && dtop
< resistance_size
&& dtop
< (wbottom
- wtop
)) {
3344 dy
= offsetrect
.top() - frame
.rect
.height();
3347 // snap bottom of other window?
3348 else if (dbottom
>= 0 && dbottom
< resistance_size
&&
3349 dbottom
< (wbottom
- wtop
)) {
3350 dy
= offsetrect
.bottom() + 1;
3353 } else { // BScreen::WindowSnap
3354 dtop
= abs(wbottom
- offsetrect
.top());
3355 dbottom
= abs(wtop
- offsetrect
.bottom());
3357 // snap top of other window?
3358 if (dtop
< snap_distance
&& dtop
<= dbottom
) {
3359 dy
= offsetrect
.top() - frame
.rect
.height();
3362 // snap bottom of other window?
3363 else if (dbottom
< snap_distance
) {
3364 dy
= offsetrect
.bottom() + 1;
3371 if (screen
->getWindowCornerSnap()) {
3372 // try corner-snap to its other sides
3373 if (snap_to_windows
== BScreen::WindowResistance
) {
3374 dleft
= winrect
.left() - wleft
;
3375 dright
= wright
- winrect
.right();
3376 if (dleft
> 0 && dleft
< resistance_size
) {
3377 // if we're already past the left edge, then don't provide
3379 if (moving
.left() >= winrect
.left())
3380 dx
= winrect
.left();
3381 } else if (dright
> 0 && dright
< resistance_size
) {
3382 // if we're already past the right edge, then don't provide
3384 if (moving
.right() <= winrect
.right())
3385 dx
= winrect
.right() - frame
.rect
.width() + 1;
3387 } else { // BScreen::WindowSnap
3388 dleft
= abs(wleft
- winrect
.left());
3389 dright
= abs(wright
- winrect
.right());
3390 if (dleft
< snap_distance
&& dleft
<= dright
)
3391 dx
= winrect
.left();
3392 else if (dright
< snap_distance
)
3393 dx
= winrect
.right() - frame
.rect
.width() + 1;
3403 if (snap_to_edges
) {
3406 // snap to the screen edges (and screen boundaries for xinerama)
3408 if (screen
->isXineramaActive() && blackbox
->doXineramaSnapping()) {
3409 rectlist
.insert(rectlist
.begin(),
3410 screen
->getXineramaAreas().begin(),
3411 screen
->getXineramaAreas().end());
3414 rectlist
.push_back(screen
->getRect());
3416 RectList::const_iterator it
, end
= rectlist
.end();
3417 for (it
= rectlist
.begin(); it
!= end
; ++it
) {
3418 const Rect
&srect
= *it
;
3420 offsetrect
.setCoords(srect
.left() + snap_offset
,
3421 srect
.top() + snap_offset
,
3422 srect
.right() - snap_offset
,
3423 srect
.bottom() - snap_offset
);
3425 if (snap_to_edges
== BScreen::WindowResistance
) {
3426 // if we're not in the rectangle then don't snap to it.
3427 if (! srect
.contains(moving
))
3429 } else { // BScreen::WindowSnap
3430 // if we're not in the rectangle then don't snap to it.
3431 if (! srect
.intersects(Rect(wleft
, wtop
, frame
.rect
.width(),
3432 frame
.rect
.height())))
3436 if (snap_to_edges
== BScreen::WindowResistance
) {
3437 int dleft
= offsetrect
.left() - wleft
,
3438 dright
= wright
- offsetrect
.right(),
3439 dtop
= offsetrect
.top() - wtop
,
3440 dbottom
= wbottom
- offsetrect
.bottom();
3443 if (dleft
> 0 && dleft
< resistance_size
)
3444 dx
= offsetrect
.left();
3446 else if (dright
> 0 && dright
< resistance_size
)
3447 dx
= offsetrect
.right() - frame
.rect
.width() + 1;
3450 if (dtop
> 0 && dtop
< resistance_size
)
3451 dy
= offsetrect
.top();
3453 else if (dbottom
> 0 && dbottom
< resistance_size
)
3454 dy
= offsetrect
.bottom() - frame
.rect
.height() + 1;
3455 } else { // BScreen::WindowSnap
3456 int dleft
= abs(wleft
- offsetrect
.left()),
3457 dright
= abs(wright
- offsetrect
.right()),
3458 dtop
= abs(wtop
- offsetrect
.top()),
3459 dbottom
= abs(wbottom
- offsetrect
.bottom());
3462 if (dleft
< snap_distance
&& dleft
<= dright
)
3463 dx
= offsetrect
.left();
3465 else if (dright
< snap_distance
)
3466 dx
= offsetrect
.right() - frame
.rect
.width() + 1;
3469 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3470 dy
= offsetrect
.top();
3472 else if (dbottom
< snap_distance
)
3473 dy
= offsetrect
.bottom() - frame
.rect
.height() + 1;
3480 void BlackboxWindow::endMove(void) {
3481 assert(flags
.moving
);
3482 assert(blackbox
->getChangingWindow() == this);
3484 flags
.moving
= False
;
3485 blackbox
->setChangingWindow(0);
3487 if (! screen
->doOpaqueMove()) {
3488 /* when drawing the rubber band, we need to make sure we only draw inside
3489 * the frame... frame.changing_* contain the new coords for the window,
3490 * so we need to subtract 1 from changing_w/changing_h every where we
3491 * draw the rubber band (for both moving and resizing)
3493 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3494 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3495 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3496 XUngrabServer(blackbox
->getXDisplay());
3498 configure(frame
.changing
.x(), frame
.changing
.y(),
3499 frame
.changing
.width(), frame
.changing
.height());
3501 configure(frame
.rect
.x(), frame
.rect
.y(),
3502 frame
.rect
.width(), frame
.rect
.height());
3504 screen
->hideGeometry();
3506 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3508 // if there are any left over motions from the move, drop them now
3509 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3511 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3516 void BlackboxWindow::beginResize(int x_root
, int y_root
, Corner dir
) {
3517 if (! (functions
& Func_Resize
)) return;
3519 assert(! (flags
.resizing
|| flags
.moving
));
3522 Only one window can be moved/resized at a time. If another window is
3523 already being moved or resized, then stop it before whating to work with
3526 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3527 if (changing
&& changing
!= this) {
3528 if (changing
->flags
.moving
)
3529 changing
->endMove();
3530 else // if (changing->flags.resizing)
3531 changing
->endResize();
3539 switch (resize_dir
) {
3542 cursor
= blackbox
->getLowerLeftAngleCursor();
3547 cursor
= blackbox
->getLowerRightAngleCursor();
3551 anchor
= BottomRight
;
3552 cursor
= blackbox
->getUpperLeftAngleCursor();
3556 anchor
= BottomLeft
;
3557 cursor
= blackbox
->getUpperRightAngleCursor();
3561 assert(false); // unhandled Corner
3562 return; // unreachable, for the compiler
3565 XGrabServer(blackbox
->getXDisplay());
3566 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3567 PointerMotionMask
| ButtonReleaseMask
,
3568 GrabModeAsync
, GrabModeAsync
, None
, cursor
, CurrentTime
);
3570 flags
.resizing
= True
;
3571 blackbox
->setChangingWindow(this);
3573 unsigned int gw
, gh
;
3574 frame
.changing
= frame
.rect
;
3576 constrain(anchor
, &gw
, &gh
);
3578 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3579 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3580 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3582 screen
->showGeometry(gw
, gh
);
3584 frame
.grab_x
= x_root
;
3585 frame
.grab_y
= y_root
;
3589 void BlackboxWindow::doResize(int x_root
, int y_root
) {
3590 assert(flags
.resizing
);
3591 assert(blackbox
->getChangingWindow() == this);
3593 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3594 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3595 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3597 unsigned int gw
, gh
;
3600 switch (resize_dir
) {
3603 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3604 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3608 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3609 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3612 anchor
= BottomRight
;
3613 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3614 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3617 anchor
= BottomLeft
;
3618 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3619 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3623 assert(false); // unhandled Corner
3624 return; // unreachable, for the compiler
3627 constrain(anchor
, &gw
, &gh
);
3629 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3630 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3631 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3633 screen
->showGeometry(gw
, gh
);
3637 void BlackboxWindow::endResize(void) {
3638 assert(flags
.resizing
);
3639 assert(blackbox
->getChangingWindow() == this);
3641 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3642 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3643 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3644 XUngrabServer(blackbox
->getXDisplay());
3646 // unset maximized state after resized when fully maximized
3647 if (flags
.maximized
== 1)
3650 flags
.resizing
= False
;
3651 blackbox
->setChangingWindow(0);
3653 configure(frame
.changing
.x(), frame
.changing
.y(),
3654 frame
.changing
.width(), frame
.changing
.height());
3655 screen
->hideGeometry();
3657 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3659 // if there are any left over motions from the resize, drop them now
3660 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3662 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3667 void BlackboxWindow::motionNotifyEvent(const XMotionEvent
*me
) {
3669 fprintf(stderr
, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n",
3674 doMove(me
->x_root
, me
->y_root
);
3675 } else if (flags
.resizing
) {
3676 doResize(me
->x_root
, me
->y_root
);
3678 if ((functions
& Func_Move
) &&
3679 (me
->state
& Button1Mask
) &&
3680 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3681 frame
.handle
== me
->window
|| frame
.window
== me
->window
)) {
3682 beginMove(me
->x_root
, me
->y_root
);
3683 } else if ((functions
& Func_Resize
) &&
3684 ((me
->state
& Button1Mask
) && (me
->window
== frame
.right_grip
||
3685 me
->window
== frame
.left_grip
)) ||
3686 ((me
->state
& Button3Mask
) && (me
->state
& mod_mask
) &&
3687 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3688 frame
.handle
== me
->window
|| frame
.window
== me
->window
))) {
3689 unsigned int zones
= screen
->getResizeZones();
3692 if (me
->window
== frame
.left_grip
) {
3693 corner
= BottomLeft
;
3694 } else if (me
->window
== frame
.right_grip
|| zones
== 1) {
3695 corner
= BottomRight
;
3698 bool left
= (me
->x_root
- frame
.rect
.x() <=
3699 static_cast<signed>(frame
.rect
.width() / 2));
3702 else // (zones == 4)
3703 top
= (me
->y_root
- frame
.rect
.y() <=
3704 static_cast<signed>(frame
.rect
.height() / 2));
3705 corner
= (top
? (left
? TopLeft
: TopRight
) :
3706 (left
? BottomLeft
: BottomRight
));
3709 beginResize(me
->x_root
, me
->y_root
, corner
);
3715 void BlackboxWindow::enterNotifyEvent(const XCrossingEvent
* ce
) {
3716 if (! (screen
->isSloppyFocus() && isVisible() && isNormal()))
3720 bool leave
= False
, inferior
= False
;
3722 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), ce
->window
,
3724 if (e
.type
== LeaveNotify
&& e
.xcrossing
.mode
== NotifyNormal
) {
3726 inferior
= (e
.xcrossing
.detail
== NotifyInferior
);
3730 if (! leave
|| inferior
) {
3731 if (! isFocused()) {
3732 bool success
= setInputFocus();
3733 if (success
) // if focus succeeded install the colormap
3734 installColormap(True
); // XXX: shouldnt we honour no install?
3737 if (screen
->doAutoRaise())
3743 void BlackboxWindow::leaveNotifyEvent(const XCrossingEvent
*) {
3744 if (! (screen
->isSloppyFocus() && screen
->doAutoRaise() && isNormal()))
3747 installColormap(False
);
3749 if (timer
->isTiming())
3755 void BlackboxWindow::shapeEvent(XShapeEvent
*) {
3756 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
3763 bool BlackboxWindow::validateClient(void) const {
3764 XSync(blackbox
->getXDisplay(), False
);
3767 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3768 DestroyNotify
, &e
) ||
3769 XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3771 XPutBackEvent(blackbox
->getXDisplay(), &e
);
3780 void BlackboxWindow::restore(bool remap
) {
3781 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeDelete
);
3782 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
3783 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, NoEventMask
);
3785 // do not leave a shaded window as an icon unless it was an icon
3786 if (flags
.shaded
&& ! flags
.iconic
)
3787 setState(NormalState
);
3789 // erase the netwm stuff that we read when a window maps, so that it
3790 // doesn't persist between mappings.
3791 // (these are the ones read in getNetWMFlags().)
3792 xatom
->eraseValue(client
.window
, XAtom::net_wm_desktop
);
3793 xatom
->eraseValue(client
.window
, XAtom::net_wm_state
);
3795 restoreGravity(client
.rect
);
3797 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
3798 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
3800 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, client
.old_bw
);
3803 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3804 ReparentNotify
, &ev
)) {
3807 // according to the ICCCM - if the client doesn't reparent to
3808 // root, then we have to do it for them
3809 XReparentWindow(blackbox
->getXDisplay(), client
.window
,
3810 screen
->getRootWindow(),
3811 client
.rect
.x(), client
.rect
.y());
3814 if (remap
) XMapWindow(blackbox
->getXDisplay(), client
.window
);
3818 // timer for autoraise
3819 void BlackboxWindow::timeout(void) {
3820 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3824 void BlackboxWindow::changeBlackboxHints(const BlackboxHints
*net
) {
3825 if ((net
->flags
& AttribShaded
) &&
3826 ((blackbox_attrib
.attrib
& AttribShaded
) !=
3827 (net
->attrib
& AttribShaded
)))
3830 if (flags
.visible
&& // watch out for requests when we can not be seen
3831 (net
->flags
& (AttribMaxVert
| AttribMaxHoriz
)) &&
3832 ((blackbox_attrib
.attrib
& (AttribMaxVert
| AttribMaxHoriz
)) !=
3833 (net
->attrib
& (AttribMaxVert
| AttribMaxHoriz
)))) {
3834 if (flags
.maximized
) {
3839 if ((net
->flags
& AttribMaxHoriz
) && (net
->flags
& AttribMaxVert
))
3840 button
= ((net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0);
3841 else if (net
->flags
& AttribMaxVert
)
3842 button
= ((net
->attrib
& AttribMaxVert
) ? 2 : 0);
3843 else if (net
->flags
& AttribMaxHoriz
)
3844 button
= ((net
->attrib
& AttribMaxHoriz
) ? 3 : 0);
3850 if ((net
->flags
& AttribOmnipresent
) &&
3851 ((blackbox_attrib
.attrib
& AttribOmnipresent
) !=
3852 (net
->attrib
& AttribOmnipresent
)))
3855 if ((net
->flags
& AttribWorkspace
) &&
3856 (blackbox_attrib
.workspace
!= net
->workspace
)) {
3857 screen
->reassociateWindow(this, net
->workspace
, True
);
3859 if (screen
->getCurrentWorkspaceID() != net
->workspace
) {
3863 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3867 if (net
->flags
& AttribDecoration
) {
3868 switch (net
->decoration
) {
3885 * Set the sizes of all components of the window frame
3886 * (the window decorations).
3887 * These values are based upon the current style settings and the client
3888 * window's dimensions.
3890 void BlackboxWindow::upsize(void) {
3891 frame
.bevel_w
= screen
->getBevelWidth();
3893 if (decorations
& Decor_Border
) {
3894 frame
.border_w
= screen
->getBorderWidth();
3895 if (! isTransient())
3896 frame
.mwm_border_w
= screen
->getFrameWidth();
3898 frame
.mwm_border_w
= 0;
3900 frame
.mwm_border_w
= frame
.border_w
= 0;
3903 if (decorations
& Decor_Titlebar
) {
3904 // the height of the titlebar is based upon the height of the font being
3905 // used to display the window's title
3906 WindowStyle
*style
= screen
->getWindowStyle();
3907 frame
.title_h
= style
->font
->height() + (frame
.bevel_w
* 2) + 2;
3909 frame
.label_h
= frame
.title_h
- (frame
.bevel_w
* 2);
3910 frame
.button_w
= (frame
.label_h
- 2);
3912 // set the top frame margin
3913 frame
.margin
.top
= frame
.border_w
+ frame
.title_h
+
3914 frame
.border_w
+ frame
.mwm_border_w
;
3920 // set the top frame margin
3921 frame
.margin
.top
= frame
.border_w
+ frame
.mwm_border_w
;
3924 // set the left/right frame margin
3925 frame
.margin
.left
= frame
.margin
.right
= frame
.border_w
+ frame
.mwm_border_w
;
3927 if (decorations
& Decor_Handle
) {
3928 frame
.grip_w
= frame
.button_w
* 2;
3929 frame
.handle_h
= screen
->getHandleWidth();
3931 // set the bottom frame margin
3932 frame
.margin
.bottom
= frame
.border_w
+ frame
.handle_h
+
3933 frame
.border_w
+ frame
.mwm_border_w
;
3938 // set the bottom frame margin
3939 frame
.margin
.bottom
= frame
.border_w
+ frame
.mwm_border_w
;
3943 We first get the normal dimensions and use this to define the inside_w/h
3944 then we modify the height if shading is in effect.
3945 If the shade state is not considered then frame.rect gets reset to the
3946 normal window size on a reconfigure() call resulting in improper
3947 dimensions appearing in move/resize and other events.
3950 height
= client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
,
3951 width
= client
.rect
.width() + frame
.margin
.left
+ frame
.margin
.right
;
3953 frame
.inside_w
= width
- (frame
.border_w
* 2);
3954 frame
.inside_h
= height
- (frame
.border_w
* 2);
3957 height
= frame
.title_h
+ (frame
.border_w
* 2);
3958 frame
.rect
.setSize(width
, height
);
3963 * Calculate the size of the client window and constrain it to the
3964 * size specified by the size hints of the client window.
3966 * The logical width and height are placed into pw and ph, if they
3967 * are non-zero. Logical size refers to the users perception of
3968 * the window size (for example an xterm resizes in cells, not in pixels).
3969 * pw and ph are then used to display the geometry during window moves, resize,
3972 * The physical geometry is placed into frame.changing_{x,y,width,height}.
3973 * Physical geometry refers to the geometry of the window in pixels.
3975 void BlackboxWindow::constrain(Corner anchor
,
3976 unsigned int *pw
, unsigned int *ph
) {
3977 // frame.changing represents the requested frame size, we need to
3978 // strip the frame margin off and constrain the client size
3979 frame
.changing
.setCoords(frame
.changing
.left() + frame
.margin
.left
,
3980 frame
.changing
.top() + frame
.margin
.top
,
3981 frame
.changing
.right() - frame
.margin
.right
,
3982 frame
.changing
.bottom() - frame
.margin
.bottom
);
3984 unsigned int dw
= frame
.changing
.width(), dh
= frame
.changing
.height(),
3985 base_width
= (client
.base_width
) ? client
.base_width
: client
.min_width
,
3986 base_height
= (client
.base_height
) ? client
.base_height
:
3990 if (dw
< client
.min_width
) dw
= client
.min_width
;
3991 if (dh
< client
.min_height
) dh
= client
.min_height
;
3992 if (dw
> client
.max_width
) dw
= client
.max_width
;
3993 if (dh
> client
.max_height
) dh
= client
.max_height
;
3995 assert(dw
>= base_width
&& dh
>= base_height
);
3997 if (client
.width_inc
> 1) {
3999 dw
/= client
.width_inc
;
4001 if (client
.height_inc
> 1) {
4003 dh
/= client
.height_inc
;
4012 if (client
.width_inc
> 1) {
4013 dw
*= client
.width_inc
;
4016 if (client
.height_inc
> 1) {
4017 dh
*= client
.height_inc
;
4021 frame
.changing
.setSize(dw
, dh
);
4023 // add the frame margin back onto frame.changing
4024 frame
.changing
.setCoords(frame
.changing
.left() - frame
.margin
.left
,
4025 frame
.changing
.top() - frame
.margin
.top
,
4026 frame
.changing
.right() + frame
.margin
.right
,
4027 frame
.changing
.bottom() + frame
.margin
.bottom
);
4029 // move frame.changing to the specified anchor
4037 dx
= frame
.rect
.right() - frame
.changing
.right();
4041 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
4045 dx
= frame
.rect
.right() - frame
.changing
.right();
4046 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
4050 assert(false); // unhandled corner
4052 frame
.changing
.setPos(frame
.changing
.x() + dx
, frame
.changing
.y() + dy
);
4056 void WindowStyle::doJustify(const std::string
&text
, int &start_pos
,
4057 unsigned int max_length
,
4058 unsigned int modifier
) const {
4059 size_t text_len
= text
.size();
4060 unsigned int length
;
4063 length
= font
->measureString(string(text
, 0, text_len
)) + modifier
;
4064 } while (length
> max_length
&& text_len
-- > 0);
4068 start_pos
+= max_length
- length
;
4072 start_pos
+= (max_length
- length
) / 2;
4082 BWindowGroup::BWindowGroup(Blackbox
*b
, Window _group
)
4083 : blackbox(b
), group(_group
) {
4084 XWindowAttributes wattrib
;
4085 if (! XGetWindowAttributes(blackbox
->getXDisplay(), group
, &wattrib
)) {
4086 // group window doesn't seem to exist anymore
4091 XSelectInput(blackbox
->getXDisplay(), group
,
4092 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
4094 blackbox
->saveGroupSearch(group
, this);
4098 BWindowGroup::~BWindowGroup(void) {
4099 blackbox
->removeGroupSearch(group
);
4104 BWindowGroup::find(BScreen
*screen
, bool allow_transients
) const {
4105 BlackboxWindow
*ret
= blackbox
->getFocusedWindow();
4107 // does the focus window match (or any transient_fors)?
4108 for (; ret
; ret
= ret
->getTransientFor()) {
4109 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
&&
4110 (! ret
->isTransient() || allow_transients
))
4114 if (ret
) return ret
;
4116 // the focus window didn't match, look in the group's window list
4117 BlackboxWindowList::const_iterator it
, end
= windowList
.end();
4118 for (it
= windowList
.begin(); it
!= end
; ++it
) {
4120 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
&&
4121 (! ret
->isTransient() || allow_transients
))