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
, ExposureMask
);
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
= EnterWindowMask
| LeaveWindowMask
;
479 return XCreateWindow(blackbox
->getXDisplay(), screen
->getRootWindow(),
480 0, 0, 1, 1, frame
.border_w
, screen
->getDepth(),
481 InputOutput
, screen
->getVisual(), create_mask
,
487 * Creates a child window, and optionally associates a given cursor with
490 Window
BlackboxWindow::createChildWindow(Window parent
,
491 unsigned long event_mask
,
493 XSetWindowAttributes attrib_create
;
494 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
|
497 attrib_create
.background_pixmap
= None
;
498 attrib_create
.event_mask
= event_mask
;
501 create_mask
|= CWCursor
;
502 attrib_create
.cursor
= cursor
;
505 return XCreateWindow(blackbox
->getXDisplay(), parent
, 0, 0, 1, 1, 0,
506 screen
->getDepth(), InputOutput
, screen
->getVisual(),
507 create_mask
, &attrib_create
);
511 void BlackboxWindow::associateClientWindow(void) {
512 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, 0);
516 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeInsert
);
518 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, SubstructureRedirectMask
);
521 note we used to grab around this call to XReparentWindow however the
522 server is now grabbed before this method is called
524 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
526 XSelectInput(blackbox
->getXDisplay(), client
.window
,
527 event_mask
& ~StructureNotifyMask
);
528 XReparentWindow(blackbox
->getXDisplay(), client
.window
, frame
.plate
, 0, 0);
529 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
531 XRaiseWindow(blackbox
->getXDisplay(), frame
.plate
);
532 XMapSubwindows(blackbox
->getXDisplay(), frame
.plate
);
535 if (blackbox
->hasShapeExtensions()) {
536 XShapeSelectInput(blackbox
->getXDisplay(), client
.window
,
543 XShapeQueryExtents(blackbox
->getXDisplay(), client
.window
, &shaped
,
544 &foo
, &foo
, &ufoo
, &ufoo
, &foo
, &foo
, &foo
,
546 flags
.shaped
= shaped
;
552 void BlackboxWindow::decorate(void) {
555 texture
= &(screen
->getWindowStyle()->b_focus
);
556 frame
.fbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
559 frame
.fbutton_pixel
= texture
->color().pixel();
561 texture
= &(screen
->getWindowStyle()->b_unfocus
);
562 frame
.ubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
565 frame
.ubutton_pixel
= texture
->color().pixel();
567 texture
= &(screen
->getWindowStyle()->b_pressed
);
568 frame
.pbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
571 frame
.pbutton_pixel
= texture
->color().pixel();
573 if (decorations
& Decor_Titlebar
) {
574 texture
= &(screen
->getWindowStyle()->t_focus
);
575 frame
.ftitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
578 frame
.ftitle_pixel
= texture
->color().pixel();
580 texture
= &(screen
->getWindowStyle()->t_unfocus
);
581 frame
.utitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
584 frame
.utitle_pixel
= texture
->color().pixel();
586 XSetWindowBorder(blackbox
->getXDisplay(), frame
.title
,
587 screen
->getBorderColor()->pixel());
592 if (decorations
& Decor_Border
) {
593 frame
.fborder_pixel
= screen
->getWindowStyle()->f_focus
.color().pixel();
594 frame
.uborder_pixel
= screen
->getWindowStyle()->f_unfocus
.color().pixel();
597 if (decorations
& Decor_Handle
) {
598 texture
= &(screen
->getWindowStyle()->h_focus
);
599 frame
.fhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
602 frame
.fhandle_pixel
= texture
->color().pixel();
604 texture
= &(screen
->getWindowStyle()->h_unfocus
);
605 frame
.uhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
608 frame
.uhandle_pixel
= texture
->color().pixel();
610 texture
= &(screen
->getWindowStyle()->g_focus
);
611 frame
.fgrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.fgrip
);
613 frame
.fgrip_pixel
= texture
->color().pixel();
615 texture
= &(screen
->getWindowStyle()->g_unfocus
);
616 frame
.ugrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.ugrip
);
618 frame
.ugrip_pixel
= texture
->color().pixel();
620 XSetWindowBorder(blackbox
->getXDisplay(), frame
.handle
,
621 screen
->getBorderColor()->pixel());
622 XSetWindowBorder(blackbox
->getXDisplay(), frame
.left_grip
,
623 screen
->getBorderColor()->pixel());
624 XSetWindowBorder(blackbox
->getXDisplay(), frame
.right_grip
,
625 screen
->getBorderColor()->pixel());
628 XSetWindowBorder(blackbox
->getXDisplay(), frame
.window
,
629 screen
->getBorderColor()->pixel());
633 void BlackboxWindow::decorateLabel(void) {
636 texture
= &(screen
->getWindowStyle()->l_focus
);
637 frame
.flabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.flabel
);
639 frame
.flabel_pixel
= texture
->color().pixel();
641 texture
= &(screen
->getWindowStyle()->l_unfocus
);
642 frame
.ulabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.ulabel
);
644 frame
.ulabel_pixel
= texture
->color().pixel();
648 void BlackboxWindow::createHandle(void) {
649 frame
.handle
= createChildWindow(frame
.window
,
650 ButtonPressMask
| ButtonReleaseMask
|
651 ButtonMotionMask
| ExposureMask
);
652 blackbox
->saveWindowSearch(frame
.handle
, this);
655 createChildWindow(frame
.handle
,
656 ButtonPressMask
| ButtonReleaseMask
|
657 ButtonMotionMask
| ExposureMask
,
658 blackbox
->getLowerLeftAngleCursor());
659 blackbox
->saveWindowSearch(frame
.left_grip
, this);
662 createChildWindow(frame
.handle
,
663 ButtonPressMask
| ButtonReleaseMask
|
664 ButtonMotionMask
| ExposureMask
,
665 blackbox
->getLowerRightAngleCursor());
666 blackbox
->saveWindowSearch(frame
.right_grip
, this);
670 void BlackboxWindow::destroyHandle(void) {
672 screen
->getImageControl()->removeImage(frame
.fhandle
);
675 screen
->getImageControl()->removeImage(frame
.uhandle
);
678 screen
->getImageControl()->removeImage(frame
.fgrip
);
681 screen
->getImageControl()->removeImage(frame
.ugrip
);
683 blackbox
->removeWindowSearch(frame
.left_grip
);
684 blackbox
->removeWindowSearch(frame
.right_grip
);
686 XDestroyWindow(blackbox
->getXDisplay(), frame
.left_grip
);
687 XDestroyWindow(blackbox
->getXDisplay(), frame
.right_grip
);
688 frame
.left_grip
= frame
.right_grip
= None
;
690 blackbox
->removeWindowSearch(frame
.handle
);
691 XDestroyWindow(blackbox
->getXDisplay(), frame
.handle
);
696 void BlackboxWindow::createTitlebar(void) {
697 frame
.title
= createChildWindow(frame
.window
,
698 ButtonPressMask
| ButtonReleaseMask
|
699 ButtonMotionMask
| ExposureMask
);
700 frame
.label
= createChildWindow(frame
.title
,
701 ButtonPressMask
| ButtonReleaseMask
|
702 ButtonMotionMask
| ExposureMask
);
703 blackbox
->saveWindowSearch(frame
.title
, this);
704 blackbox
->saveWindowSearch(frame
.label
, this);
706 if (decorations
& Decor_Iconify
) createIconifyButton();
707 if (decorations
& Decor_Maximize
) createMaximizeButton();
708 if (decorations
& Decor_Close
) createCloseButton();
712 void BlackboxWindow::destroyTitlebar(void) {
713 if (frame
.close_button
)
714 destroyCloseButton();
716 if (frame
.iconify_button
)
717 destroyIconifyButton();
719 if (frame
.maximize_button
)
720 destroyMaximizeButton();
723 screen
->getImageControl()->removeImage(frame
.ftitle
);
726 screen
->getImageControl()->removeImage(frame
.utitle
);
729 screen
->getImageControl()->removeImage(frame
.flabel
);
732 screen
->getImageControl()->removeImage(frame
.ulabel
);
735 screen
->getImageControl()->removeImage(frame
.fbutton
);
738 screen
->getImageControl()->removeImage(frame
.ubutton
);
741 screen
->getImageControl()->removeImage(frame
.pbutton
);
743 blackbox
->removeWindowSearch(frame
.title
);
744 blackbox
->removeWindowSearch(frame
.label
);
746 XDestroyWindow(blackbox
->getXDisplay(), frame
.label
);
747 XDestroyWindow(blackbox
->getXDisplay(), frame
.title
);
748 frame
.title
= frame
.label
= None
;
752 void BlackboxWindow::createCloseButton(void) {
753 if (frame
.title
!= None
) {
754 frame
.close_button
= createChildWindow(frame
.title
,
757 ButtonMotionMask
| ExposureMask
);
758 blackbox
->saveWindowSearch(frame
.close_button
, this);
763 void BlackboxWindow::destroyCloseButton(void) {
764 blackbox
->removeWindowSearch(frame
.close_button
);
765 XDestroyWindow(blackbox
->getXDisplay(), frame
.close_button
);
766 frame
.close_button
= None
;
770 void BlackboxWindow::createIconifyButton(void) {
771 if (frame
.title
!= None
) {
772 frame
.iconify_button
= createChildWindow(frame
.title
,
775 ButtonMotionMask
| ExposureMask
);
776 blackbox
->saveWindowSearch(frame
.iconify_button
, this);
781 void BlackboxWindow::destroyIconifyButton(void) {
782 blackbox
->removeWindowSearch(frame
.iconify_button
);
783 XDestroyWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
784 frame
.iconify_button
= None
;
788 void BlackboxWindow::createMaximizeButton(void) {
789 if (frame
.title
!= None
) {
790 frame
.maximize_button
= createChildWindow(frame
.title
,
793 ButtonMotionMask
| ExposureMask
);
794 blackbox
->saveWindowSearch(frame
.maximize_button
, this);
799 void BlackboxWindow::destroyMaximizeButton(void) {
800 blackbox
->removeWindowSearch(frame
.maximize_button
);
801 XDestroyWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
802 frame
.maximize_button
= None
;
806 void BlackboxWindow::positionButtons(bool redecorate_label
) {
807 string layout
= blackbox
->getTitlebarLayout();
810 bool hasclose
, hasiconify
, hasmaximize
, haslabel
;
811 hasclose
= hasiconify
= hasmaximize
= haslabel
= false;
813 string::const_iterator it
, end
;
814 for (it
= layout
.begin(), end
= layout
.end(); it
!= end
; ++it
) {
817 if (! hasclose
&& (decorations
& Decor_Close
)) {
823 if (! hasiconify
&& (decorations
& Decor_Iconify
)) {
829 if (! hasmaximize
&& (decorations
& Decor_Maximize
)) {
841 if (! hasclose
&& frame
.close_button
)
842 destroyCloseButton();
843 if (! hasiconify
&& frame
.iconify_button
)
844 destroyIconifyButton();
845 if (! hasmaximize
&& frame
.maximize_button
)
846 destroyMaximizeButton();
848 parsed
+= 'L'; // require that the label be in the layout
850 const unsigned int bsep
= frame
.bevel_w
+ 1; // separation between elements
851 const unsigned int by
= frame
.bevel_w
+ 1;
852 const unsigned int ty
= frame
.bevel_w
;
854 frame
.label_w
= frame
.inside_w
- bsep
* 2 -
855 (frame
.button_w
+ bsep
) * (parsed
.size() - 1);
857 unsigned int x
= bsep
;
858 for (it
= parsed
.begin(), end
= parsed
.end(); it
!= end
; ++it
) {
861 if (! frame
.close_button
) createCloseButton();
862 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.close_button
, x
, by
,
863 frame
.button_w
, frame
.button_w
);
864 x
+= frame
.button_w
+ bsep
;
867 if (! frame
.iconify_button
) createIconifyButton();
868 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.iconify_button
, x
, by
,
869 frame
.button_w
, frame
.button_w
);
870 x
+= frame
.button_w
+ bsep
;
873 if (! frame
.maximize_button
) createMaximizeButton();
874 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.maximize_button
, x
, by
,
875 frame
.button_w
, frame
.button_w
);
876 x
+= frame
.button_w
+ bsep
;
879 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.label
, x
, ty
,
880 frame
.label_w
, frame
.label_h
);
881 x
+= frame
.label_w
+ bsep
;
886 if (redecorate_label
) decorateLabel();
892 void BlackboxWindow::reconfigure(void) {
893 restoreGravity(client
.rect
);
895 applyGravity(frame
.rect
);
904 windowmenu
->move(windowmenu
->getX(), frame
.rect
.y() + frame
.title_h
);
905 windowmenu
->reconfigure();
910 void BlackboxWindow::grabButtons(void) {
911 mod_mask
= blackbox
->getMouseModMask();
913 if (! screen
->isSloppyFocus() || screen
->doClickRaise())
914 // grab button 1 for changing focus/raising
915 blackbox
->grabButton(Button1
, 0, frame
.plate
, True
, ButtonPressMask
,
916 GrabModeSync
, GrabModeSync
, frame
.plate
, None
,
917 screen
->allowScrollLock());
919 if (functions
& Func_Move
)
920 blackbox
->grabButton(Button1
, mod_mask
, frame
.window
, True
,
921 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
922 GrabModeAsync
, frame
.window
, None
,
923 screen
->allowScrollLock());
924 if (functions
& Func_Resize
)
925 blackbox
->grabButton(Button3
, mod_mask
, frame
.window
, True
,
926 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
927 GrabModeAsync
, frame
.window
, None
,
928 screen
->allowScrollLock());
929 // alt+middle lowers the window
930 blackbox
->grabButton(Button2
, mod_mask
, frame
.window
, True
,
931 ButtonReleaseMask
, GrabModeAsync
, GrabModeAsync
,
932 frame
.window
, None
, screen
->allowScrollLock());
936 void BlackboxWindow::ungrabButtons(void) {
937 blackbox
->ungrabButton(Button1
, 0, frame
.plate
);
938 blackbox
->ungrabButton(Button1
, mod_mask
, frame
.window
);
939 blackbox
->ungrabButton(Button2
, mod_mask
, frame
.window
);
940 blackbox
->ungrabButton(Button3
, mod_mask
, frame
.window
);
944 void BlackboxWindow::positionWindows(void) {
945 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.window
,
946 frame
.rect
.x(), frame
.rect
.y(), frame
.inside_w
,
947 (flags
.shaded
) ? frame
.title_h
: frame
.inside_h
);
948 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.window
,
950 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.plate
,
952 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.plate
,
953 frame
.margin
.left
- frame
.mwm_border_w
- frame
.border_w
,
954 frame
.margin
.top
- frame
.mwm_border_w
- frame
.border_w
,
955 client
.rect
.width(), client
.rect
.height());
956 XMoveResizeWindow(blackbox
->getXDisplay(), client
.window
,
957 0, 0, client
.rect
.width(), client
.rect
.height());
958 // ensure client.rect contains the real location
959 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
960 frame
.rect
.top() + frame
.margin
.top
);
962 if (decorations
& Decor_Titlebar
) {
963 if (frame
.title
== None
) createTitlebar();
965 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.title
,
967 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.title
, -frame
.border_w
,
968 -frame
.border_w
, frame
.inside_w
, frame
.title_h
);
971 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
972 XMapWindow(blackbox
->getXDisplay(), frame
.title
);
973 } else if (frame
.title
) {
976 if (decorations
& Decor_Handle
) {
977 if (frame
.handle
== None
) createHandle();
978 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.handle
,
980 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.left_grip
,
982 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.right_grip
,
985 // use client.rect here so the value is correct even if shaded
986 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.handle
,
988 client
.rect
.height() + frame
.margin
.top
+
989 frame
.mwm_border_w
- frame
.border_w
,
990 frame
.inside_w
, frame
.handle_h
);
991 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.left_grip
,
992 -frame
.border_w
, -frame
.border_w
,
993 frame
.grip_w
, frame
.handle_h
);
994 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.right_grip
,
995 frame
.inside_w
- frame
.grip_w
- frame
.border_w
,
996 -frame
.border_w
, frame
.grip_w
, frame
.handle_h
);
998 XMapSubwindows(blackbox
->getXDisplay(), frame
.handle
);
999 XMapWindow(blackbox
->getXDisplay(), frame
.handle
);
1000 } else if (frame
.handle
) {
1003 XSync(blackbox
->getXDisplay(), False
);
1007 void BlackboxWindow::updateStrut(void) {
1008 unsigned long num
= 4;
1009 unsigned long *data
;
1010 if (! xatom
->getValue(client
.window
, XAtom::net_wm_strut
, XAtom::cardinal
,
1015 client
.strut
.left
= data
[0];
1016 client
.strut
.right
= data
[1];
1017 client
.strut
.top
= data
[2];
1018 client
.strut
.bottom
= data
[3];
1020 screen
->updateAvailableArea();
1027 bool BlackboxWindow::getWindowType(void) {
1028 window_type
= (WindowType
) -1;
1031 unsigned long num
= (unsigned) -1;
1032 if (xatom
->getValue(client
.window
, XAtom::net_wm_window_type
, XAtom::atom
,
1034 for (unsigned long i
= 0; i
< num
; ++i
) {
1035 if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_desktop
))
1036 window_type
= Type_Desktop
;
1037 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_dock
))
1038 window_type
= Type_Dock
;
1039 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_toolbar
))
1040 window_type
= Type_Toolbar
;
1041 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_menu
))
1042 window_type
= Type_Menu
;
1043 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_utility
))
1044 window_type
= Type_Utility
;
1045 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_splash
))
1046 window_type
= Type_Splash
;
1047 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_dialog
))
1048 window_type
= Type_Dialog
;
1049 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_normal
))
1050 window_type
= Type_Normal
;
1052 xatom
->getAtom(XAtom::kde_net_wm_window_type_override
))
1053 mwm_decorations
= 0; // prevent this window from getting any decor
1058 if (window_type
== (WindowType
) -1) {
1060 * the window type hint was not set, which means we either classify ourself
1061 * as a normal window or a dialog, depending on if we are a transient.
1064 window_type
= Type_Dialog
;
1066 window_type
= Type_Normal
;
1075 void BlackboxWindow::getWMName(void) {
1076 if (xatom
->getValue(client
.window
, XAtom::net_wm_name
,
1077 XAtom::utf8
, client
.title
) &&
1078 !client
.title
.empty()) {
1079 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
1082 //fall through to using WM_NAME
1083 if (xatom
->getValue(client
.window
, XAtom::wm_name
, XAtom::ansi
, client
.title
)
1084 && !client
.title
.empty()) {
1085 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
1088 // fall back to an internal default
1089 client
.title
= i18n(WindowSet
, WindowUnnamed
, "Unnamed");
1090 xatom
->setValue(client
.window
, XAtom::net_wm_visible_name
, XAtom::utf8
,
1093 #define DEBUG_WITH_ID 1
1094 #ifdef DEBUG_WITH_ID
1095 // the 16 is the 8 chars of the debug text plus the number
1096 char *tmp
= new char[client
.title
.length() + 16];
1097 sprintf(tmp
, "%s; id: 0x%lx", client
.title
.c_str(), client
.window
);
1104 void BlackboxWindow::getWMIconName(void) {
1105 if (xatom
->getValue(client
.window
, XAtom::net_wm_icon_name
,
1106 XAtom::utf8
, client
.icon_title
) &&
1107 !client
.icon_title
.empty()) {
1108 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1111 //fall through to using WM_ICON_NAME
1112 if (xatom
->getValue(client
.window
, XAtom::wm_icon_name
, XAtom::ansi
,
1113 client
.icon_title
) &&
1114 !client
.icon_title
.empty()) {
1115 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1118 // fall back to using the main name
1119 client
.icon_title
= client
.title
;
1120 xatom
->setValue(client
.window
, XAtom::net_wm_visible_icon_name
, XAtom::utf8
,
1126 * Retrieve which WM Protocols are supported by the client window.
1127 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
1128 * window's decorations and allow the close behavior.
1129 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
1132 void BlackboxWindow::getWMProtocols(void) {
1136 if (XGetWMProtocols(blackbox
->getXDisplay(), client
.window
,
1137 &proto
, &num_return
)) {
1138 for (int i
= 0; i
< num_return
; ++i
) {
1139 if (proto
[i
] == xatom
->getAtom(XAtom::wm_delete_window
)) {
1140 decorations
|= Decor_Close
;
1141 functions
|= Func_Close
;
1142 } else if (proto
[i
] == xatom
->getAtom(XAtom::wm_take_focus
))
1143 flags
.send_focus_message
= True
;
1144 else if (proto
[i
] == xatom
->getAtom(XAtom::blackbox_structure_messages
))
1145 screen
->addNetizen(new Netizen(screen
, client
.window
));
1154 * Gets the value of the WM_HINTS property.
1155 * If the property is not set, then use a set of default values.
1157 void BlackboxWindow::getWMHints(void) {
1158 focus_mode
= F_Passive
;
1160 // remove from current window group
1161 if (client
.window_group
) {
1162 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1163 if (group
) group
->removeWindow(this);
1165 client
.window_group
= None
;
1167 XWMHints
*wmhint
= XGetWMHints(blackbox
->getXDisplay(), client
.window
);
1172 if (wmhint
->flags
& InputHint
) {
1173 if (wmhint
->input
== True
) {
1174 if (flags
.send_focus_message
)
1175 focus_mode
= F_LocallyActive
;
1177 if (flags
.send_focus_message
)
1178 focus_mode
= F_GloballyActive
;
1180 focus_mode
= F_NoInput
;
1184 if (wmhint
->flags
& StateHint
)
1185 current_state
= wmhint
->initial_state
;
1187 if (wmhint
->flags
& WindowGroupHint
) {
1188 client
.window_group
= wmhint
->window_group
;
1190 // add window to the appropriate group
1191 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1192 if (! group
) { // no group found, create it!
1193 new BWindowGroup(blackbox
, client
.window_group
);
1194 group
= blackbox
->searchGroup(client
.window_group
);
1197 group
->addWindow(this);
1205 * Gets the value of the WM_NORMAL_HINTS property.
1206 * If the property is not set, then use a set of default values.
1208 void BlackboxWindow::getWMNormalHints(void) {
1210 XSizeHints sizehint
;
1212 client
.min_width
= client
.min_height
=
1213 client
.width_inc
= client
.height_inc
= 1;
1214 client
.base_width
= client
.base_height
= 0;
1215 client
.win_gravity
= NorthWestGravity
;
1217 client
.min_aspect_x
= client
.min_aspect_y
=
1218 client
.max_aspect_x
= client
.max_aspect_y
= 1;
1221 // don't limit the size of a window, the default max width is the biggest
1223 client
.max_width
= (unsigned) -1;
1224 client
.max_height
= (unsigned) -1;
1227 if (! XGetWMNormalHints(blackbox
->getXDisplay(), client
.window
,
1228 &sizehint
, &icccm_mask
))
1231 client
.normal_hint_flags
= sizehint
.flags
;
1233 if (sizehint
.flags
& PMinSize
) {
1234 if (sizehint
.min_width
>= 0)
1235 client
.min_width
= sizehint
.min_width
;
1236 if (sizehint
.min_height
>= 0)
1237 client
.min_height
= sizehint
.min_height
;
1240 if (sizehint
.flags
& PMaxSize
) {
1241 if (sizehint
.max_width
> static_cast<signed>(client
.min_width
))
1242 client
.max_width
= sizehint
.max_width
;
1244 client
.max_width
= client
.min_width
;
1246 if (sizehint
.max_height
> static_cast<signed>(client
.min_height
))
1247 client
.max_height
= sizehint
.max_height
;
1249 client
.max_height
= client
.min_height
;
1252 if (sizehint
.flags
& PResizeInc
) {
1253 client
.width_inc
= sizehint
.width_inc
;
1254 client
.height_inc
= sizehint
.height_inc
;
1257 #if 0 // we do not support this at the moment
1258 if (sizehint
.flags
& PAspect
) {
1259 client
.min_aspect_x
= sizehint
.min_aspect
.x
;
1260 client
.min_aspect_y
= sizehint
.min_aspect
.y
;
1261 client
.max_aspect_x
= sizehint
.max_aspect
.x
;
1262 client
.max_aspect_y
= sizehint
.max_aspect
.y
;
1266 if (sizehint
.flags
& PBaseSize
) {
1267 client
.base_width
= sizehint
.base_width
;
1268 client
.base_height
= sizehint
.base_height
;
1271 if (sizehint
.flags
& PWinGravity
)
1272 client
.win_gravity
= sizehint
.win_gravity
;
1277 * Gets the NETWM hints for the class' contained window.
1279 void BlackboxWindow::getNetWMHints(void) {
1280 unsigned long workspace
;
1282 if (xatom
->getValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1284 if (workspace
== 0xffffffff)
1287 blackbox_attrib
.workspace
= workspace
;
1290 unsigned long *state
;
1291 unsigned long num
= (unsigned) -1;
1292 if (xatom
->getValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
1296 for (unsigned long i
= 0; i
< num
; ++i
) {
1297 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
))
1299 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_shaded
))
1300 flags
.shaded
= True
;
1301 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
))
1302 flags
.skip_taskbar
= True
;
1303 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_pager
))
1304 flags
.skip_pager
= True
;
1305 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_fullscreen
))
1306 flags
.fullscreen
= True
;
1307 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_hidden
))
1308 setState(IconicState
);
1309 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_vert
))
1311 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_horz
))
1315 flags
.maximized
= 1;
1317 flags
.maximized
= 2;
1319 flags
.maximized
= 3;
1327 * Gets the MWM hints for the class' contained window.
1328 * This is used while initializing the window to its first state, and not
1330 * Returns: true if the MWM hints are successfully retreived and applied;
1331 * false if they are not.
1333 void BlackboxWindow::getMWMHints(void) {
1337 num
= PropMwmHintsElements
;
1338 if (! xatom
->getValue(client
.window
, XAtom::motif_wm_hints
,
1339 XAtom::motif_wm_hints
, num
,
1340 (unsigned long **)&mwm_hint
))
1342 if (num
< PropMwmHintsElements
) {
1347 if (mwm_hint
->flags
& MwmHintsDecorations
) {
1348 if (mwm_hint
->decorations
& MwmDecorAll
) {
1349 mwm_decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
1350 Decor_Iconify
| Decor_Maximize
;
1352 mwm_decorations
= 0;
1354 if (mwm_hint
->decorations
& MwmDecorBorder
)
1355 mwm_decorations
|= Decor_Border
;
1356 if (mwm_hint
->decorations
& MwmDecorHandle
)
1357 mwm_decorations
|= Decor_Handle
;
1358 if (mwm_hint
->decorations
& MwmDecorTitle
)
1359 mwm_decorations
|= Decor_Titlebar
;
1360 if (mwm_hint
->decorations
& MwmDecorIconify
)
1361 mwm_decorations
|= Decor_Iconify
;
1362 if (mwm_hint
->decorations
& MwmDecorMaximize
)
1363 mwm_decorations
|= Decor_Maximize
;
1367 if (mwm_hint
->flags
& MwmHintsFunctions
) {
1368 if (mwm_hint
->functions
& MwmFuncAll
) {
1369 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
|
1374 if (mwm_hint
->functions
& MwmFuncResize
)
1375 functions
|= Func_Resize
;
1376 if (mwm_hint
->functions
& MwmFuncMove
)
1377 functions
|= Func_Move
;
1378 if (mwm_hint
->functions
& MwmFuncIconify
)
1379 functions
|= Func_Iconify
;
1380 if (mwm_hint
->functions
& MwmFuncMaximize
)
1381 functions
|= Func_Maximize
;
1382 if (mwm_hint
->functions
& MwmFuncClose
)
1383 functions
|= Func_Close
;
1391 * Gets the blackbox hints from the class' contained window.
1392 * This is used while initializing the window to its first state, and not
1394 * Returns: true if the hints are successfully retreived and applied; false if
1397 bool BlackboxWindow::getBlackboxHints(void) {
1399 BlackboxHints
*blackbox_hint
;
1401 num
= PropBlackboxHintsElements
;
1402 if (! xatom
->getValue(client
.window
, XAtom::blackbox_hints
,
1403 XAtom::blackbox_hints
, num
,
1404 (unsigned long **)&blackbox_hint
))
1406 if (num
< PropBlackboxHintsElements
) {
1407 delete [] blackbox_hint
;
1411 if (blackbox_hint
->flags
& AttribShaded
)
1412 flags
.shaded
= (blackbox_hint
->attrib
& AttribShaded
);
1414 if ((blackbox_hint
->flags
& AttribMaxHoriz
) &&
1415 (blackbox_hint
->flags
& AttribMaxVert
))
1416 flags
.maximized
= (blackbox_hint
->attrib
&
1417 (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1418 else if (blackbox_hint
->flags
& AttribMaxVert
)
1419 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxVert
) ? 2 : 0;
1420 else if (blackbox_hint
->flags
& AttribMaxHoriz
)
1421 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1423 if (blackbox_hint
->flags
& AttribOmnipresent
)
1424 flags
.stuck
= (blackbox_hint
->attrib
& AttribOmnipresent
);
1426 if (blackbox_hint
->flags
& AttribWorkspace
)
1427 blackbox_attrib
.workspace
= blackbox_hint
->workspace
;
1429 // if (blackbox_hint->flags & AttribStack)
1430 // don't yet have always on top/bottom for blackbox yet... working
1433 if (blackbox_hint
->flags
& AttribDecoration
) {
1434 switch (blackbox_hint
->decoration
) {
1436 blackbox_attrib
.decoration
= DecorNone
;
1443 // blackbox_attrib.decoration defaults to DecorNormal
1448 delete [] blackbox_hint
;
1454 void BlackboxWindow::getTransientInfo(void) {
1455 if (client
.transient_for
&&
1456 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1457 // reset transient_for in preparation of looking for a new owner
1458 client
.transient_for
->client
.transientList
.remove(this);
1461 // we have no transient_for until we find a new one
1462 client
.transient_for
= (BlackboxWindow
*) 0;
1465 if (! XGetTransientForHint(blackbox
->getXDisplay(), client
.window
,
1467 // transient_for hint not set
1471 if (trans_for
== client
.window
) {
1472 // wierd client... treat this window as a normal window
1476 if (trans_for
== None
|| trans_for
== screen
->getRootWindow()) {
1477 // this is an undocumented interpretation of the ICCCM. a transient
1478 // associated with None/Root/itself is assumed to be a modal root
1479 // transient. we don't support the concept of a global transient,
1480 // so we just associate this transient with nothing, and perhaps
1481 // we will add support later for global modality.
1482 client
.transient_for
= (BlackboxWindow
*) ~0ul;
1487 client
.transient_for
= blackbox
->searchWindow(trans_for
);
1488 if (! client
.transient_for
&&
1489 client
.window_group
&& trans_for
== client
.window_group
) {
1490 // no direct transient_for, perhaps this is a group transient?
1491 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1492 if (group
) client
.transient_for
= group
->find(screen
);
1495 if (! client
.transient_for
|| client
.transient_for
== this) {
1496 // no transient_for found, or we have a wierd client that wants to be
1497 // a transient for itself, so we treat this window as a normal window
1498 client
.transient_for
= (BlackboxWindow
*) 0;
1502 // Check for a circular transient state: this can lock up Blackbox
1503 // when it tries to find the non-transient window for a transient.
1504 BlackboxWindow
*w
= this;
1505 while(w
->client
.transient_for
&&
1506 w
->client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1507 if(w
->client
.transient_for
== this) {
1508 client
.transient_for
= (BlackboxWindow
*) 0;
1511 w
= w
->client
.transient_for
;
1514 if (client
.transient_for
&&
1515 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1516 // register ourselves with our new transient_for
1517 client
.transient_for
->client
.transientList
.push_back(this);
1518 flags
.stuck
= client
.transient_for
->flags
.stuck
;
1523 BlackboxWindow
*BlackboxWindow::getTransientFor(void) const {
1524 if (client
.transient_for
&&
1525 client
.transient_for
!= (BlackboxWindow
*) ~0ul)
1526 return client
.transient_for
;
1532 * This function is responsible for updating both the client and the frame
1534 * According to the ICCCM a client message is not sent for a resize, only a
1537 void BlackboxWindow::configure(int dx
, int dy
,
1538 unsigned int dw
, unsigned int dh
) {
1539 bool send_event
= ((frame
.rect
.x() != dx
|| frame
.rect
.y() != dy
) &&
1542 if (dw
!= frame
.rect
.width() || dh
!= frame
.rect
.height()) {
1543 frame
.rect
.setRect(dx
, dy
, dw
, dh
);
1544 frame
.inside_w
= frame
.rect
.width() - (frame
.border_w
* 2);
1545 frame
.inside_h
= frame
.rect
.height() - (frame
.border_w
* 2);
1547 if (frame
.rect
.right() <= 0 || frame
.rect
.bottom() <= 0)
1548 frame
.rect
.setPos(0, 0);
1550 client
.rect
.setCoords(frame
.rect
.left() + frame
.margin
.left
,
1551 frame
.rect
.top() + frame
.margin
.top
,
1552 frame
.rect
.right() - frame
.margin
.right
,
1553 frame
.rect
.bottom() - frame
.margin
.bottom
);
1556 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
1563 redrawWindowFrame();
1565 frame
.rect
.setPos(dx
, dy
);
1567 XMoveWindow(blackbox
->getXDisplay(), frame
.window
,
1568 frame
.rect
.x(), frame
.rect
.y());
1570 we may have been called just after an opaque window move, so even though
1571 the old coords match the new ones no ConfigureNotify has been sent yet.
1572 There are likely other times when this will be relevant as well.
1574 if (! flags
.moving
) send_event
= True
;
1578 // if moving, the update and event will occur when the move finishes
1579 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1580 frame
.rect
.top() + frame
.margin
.top
);
1583 event
.type
= ConfigureNotify
;
1585 event
.xconfigure
.display
= blackbox
->getXDisplay();
1586 event
.xconfigure
.event
= client
.window
;
1587 event
.xconfigure
.window
= client
.window
;
1588 event
.xconfigure
.x
= client
.rect
.x();
1589 event
.xconfigure
.y
= client
.rect
.y();
1590 event
.xconfigure
.width
= client
.rect
.width();
1591 event
.xconfigure
.height
= client
.rect
.height();
1592 event
.xconfigure
.border_width
= client
.old_bw
;
1593 event
.xconfigure
.above
= frame
.window
;
1594 event
.xconfigure
.override_redirect
= False
;
1596 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1597 StructureNotifyMask
, &event
);
1598 screen
->updateNetizenConfigNotify(&event
);
1599 XFlush(blackbox
->getXDisplay());
1605 void BlackboxWindow::configureShape(void) {
1606 XShapeCombineShape(blackbox
->getXDisplay(), frame
.window
, ShapeBounding
,
1607 frame
.margin
.left
- frame
.border_w
,
1608 frame
.margin
.top
- frame
.border_w
,
1609 client
.window
, ShapeBounding
, ShapeSet
);
1612 XRectangle xrect
[2];
1614 if (decorations
& Decor_Titlebar
) {
1615 xrect
[0].x
= xrect
[0].y
= -frame
.border_w
;
1616 xrect
[0].width
= frame
.rect
.width();
1617 xrect
[0].height
= frame
.title_h
+ (frame
.border_w
* 2);
1621 if (decorations
& Decor_Handle
) {
1622 xrect
[1].x
= -frame
.border_w
;
1623 xrect
[1].y
= frame
.rect
.height() - frame
.margin
.bottom
+
1624 frame
.mwm_border_w
- frame
.border_w
;
1625 xrect
[1].width
= frame
.rect
.width();
1626 xrect
[1].height
= frame
.handle_h
+ (frame
.border_w
* 2);
1630 XShapeCombineRectangles(blackbox
->getXDisplay(), frame
.window
,
1631 ShapeBounding
, 0, 0, xrect
, num
,
1632 ShapeUnion
, Unsorted
);
1637 bool BlackboxWindow::setInputFocus(void) {
1638 if (flags
.focused
) return True
;
1640 assert(flags
.stuck
|| // window must be on the current workspace or sticky
1641 blackbox_attrib
.workspace
== screen
->getCurrentWorkspaceID());
1644 We only do this check for normal windows and dialogs because other windows
1645 do this on purpose, such as kde's kicker, and we don't want to go moving
1648 if (window_type
== Type_Normal
|| window_type
== Type_Dialog
)
1649 if (! frame
.rect
.intersects(screen
->getRect())) {
1650 // client is outside the screen, move it to the center
1651 configure((screen
->getWidth() - frame
.rect
.width()) / 2,
1652 (screen
->getHeight() - frame
.rect
.height()) / 2,
1653 frame
.rect
.width(), frame
.rect
.height());
1656 if (client
.transientList
.size() > 0) {
1657 // transfer focus to any modal transients
1658 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1659 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1660 if ((*it
)->flags
.modal
) return (*it
)->setInputFocus();
1664 if (focus_mode
== F_LocallyActive
|| focus_mode
== F_Passive
) {
1665 XSetInputFocus(blackbox
->getXDisplay(), client
.window
,
1666 RevertToPointerRoot
, CurrentTime
);
1668 /* we could set the focus to none, since the window doesn't accept focus,
1669 * but we shouldn't set focus to nothing since this would surely make
1675 if (flags
.send_focus_message
) {
1677 ce
.xclient
.type
= ClientMessage
;
1678 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1679 ce
.xclient
.display
= blackbox
->getXDisplay();
1680 ce
.xclient
.window
= client
.window
;
1681 ce
.xclient
.format
= 32;
1682 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_take_focus
);
1683 ce
.xclient
.data
.l
[1] = blackbox
->getLastTime();
1684 ce
.xclient
.data
.l
[2] = 0l;
1685 ce
.xclient
.data
.l
[3] = 0l;
1686 ce
.xclient
.data
.l
[4] = 0l;
1687 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1689 XFlush(blackbox
->getXDisplay());
1696 void BlackboxWindow::iconify(void) {
1697 if (flags
.iconic
|| ! (functions
& Func_Iconify
)) return;
1699 // We don't need to worry about resizing because resizing always grabs the X
1700 // server. This should only ever happen if using opaque moving.
1704 if (windowmenu
) windowmenu
->hide();
1707 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1708 * we need to clear the event mask on client.window for a split second.
1709 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1710 * split second, leaving us with a ghost window... so, we need to do this
1711 * while the X server is grabbed
1713 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1714 StructureNotifyMask
;
1715 XGrabServer(blackbox
->getXDisplay());
1716 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1717 event_mask
& ~StructureNotifyMask
);
1718 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1719 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1720 XUngrabServer(blackbox
->getXDisplay());
1722 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1723 flags
.visible
= False
;
1724 flags
.iconic
= True
;
1726 setState(IconicState
);
1728 screen
->getWorkspace(blackbox_attrib
.workspace
)->removeWindow(this);
1730 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
1731 if (i
!= blackbox_attrib
.workspace
)
1732 screen
->getWorkspace(i
)->removeWindow(this, True
);
1735 if (isTransient()) {
1736 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1737 ! client
.transient_for
->flags
.iconic
) {
1738 // iconify our transient_for
1739 client
.transient_for
->iconify();
1743 screen
->addIcon(this);
1745 if (client
.transientList
.size() > 0) {
1746 // iconify all transients
1747 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1748 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1749 if (! (*it
)->flags
.iconic
) (*it
)->iconify();
1752 screen
->updateStackingList();
1756 void BlackboxWindow::show(void) {
1757 flags
.visible
= True
;
1758 flags
.iconic
= False
;
1760 current_state
= (flags
.shaded
) ? IconicState
: NormalState
;
1761 setState(current_state
);
1763 XMapWindow(blackbox
->getXDisplay(), client
.window
);
1764 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
1765 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
1770 XTranslateCoordinates(blackbox
->getXDisplay(), client
.window
,
1771 screen
->getRootWindow(),
1772 0, 0, &real_x
, &real_y
, &child
);
1773 fprintf(stderr
, "%s -- assumed: (%d, %d), real: (%d, %d)\n", getTitle(),
1774 client
.rect
.left(), client
.rect
.top(), real_x
, real_y
);
1775 assert(client
.rect
.left() == real_x
&& client
.rect
.top() == real_y
);
1780 void BlackboxWindow::deiconify(bool reassoc
, bool raise
) {
1781 if (flags
.iconic
|| reassoc
)
1782 screen
->reassociateWindow(this, BSENTINEL
, False
);
1783 else if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID())
1788 // reassociate and deiconify all transients
1789 if (reassoc
&& client
.transientList
.size() > 0) {
1790 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1791 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1792 (*it
)->deiconify(True
, False
);
1796 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1800 void BlackboxWindow::close(void) {
1801 if (! (functions
& Func_Close
)) return;
1804 ce
.xclient
.type
= ClientMessage
;
1805 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1806 ce
.xclient
.display
= blackbox
->getXDisplay();
1807 ce
.xclient
.window
= client
.window
;
1808 ce
.xclient
.format
= 32;
1809 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_delete_window
);
1810 ce
.xclient
.data
.l
[1] = CurrentTime
;
1811 ce
.xclient
.data
.l
[2] = 0l;
1812 ce
.xclient
.data
.l
[3] = 0l;
1813 ce
.xclient
.data
.l
[4] = 0l;
1814 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
, NoEventMask
, &ce
);
1815 XFlush(blackbox
->getXDisplay());
1819 void BlackboxWindow::withdraw(void) {
1820 // We don't need to worry about resizing because resizing always grabs the X
1821 // server. This should only ever happen if using opaque moving.
1825 flags
.visible
= False
;
1826 flags
.iconic
= False
;
1828 setState(current_state
);
1830 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1832 XGrabServer(blackbox
->getXDisplay());
1834 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1835 StructureNotifyMask
;
1836 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1837 event_mask
& ~StructureNotifyMask
);
1838 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1839 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1841 XUngrabServer(blackbox
->getXDisplay());
1843 if (windowmenu
) windowmenu
->hide();
1847 void BlackboxWindow::maximize(unsigned int button
) {
1848 if (! (functions
& Func_Maximize
)) return;
1850 // We don't need to worry about resizing because resizing always grabs the X
1851 // server. This should only ever happen if using opaque moving.
1855 // handle case where menu is open then the max button is used instead
1856 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
1858 if (flags
.maximized
) {
1859 flags
.maximized
= 0;
1861 blackbox_attrib
.flags
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1862 blackbox_attrib
.attrib
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1865 when a resize finishes, maximize(0) is called to clear any maximization
1866 flags currently set. Otherwise it still thinks it is maximized.
1867 so we do not need to call configure() because resizing will handle it
1869 if (! flags
.resizing
)
1870 configure(blackbox_attrib
.premax_x
, blackbox_attrib
.premax_y
,
1871 blackbox_attrib
.premax_w
, blackbox_attrib
.premax_h
);
1873 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
1874 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
1876 redrawAllButtons(); // in case it is not called in configure()
1877 setState(current_state
);
1881 blackbox_attrib
.premax_x
= frame
.rect
.x();
1882 blackbox_attrib
.premax_y
= frame
.rect
.y();
1883 blackbox_attrib
.premax_w
= frame
.rect
.width();
1884 // use client.rect so that clients can be restored even if shaded
1885 blackbox_attrib
.premax_h
=
1886 client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
;
1889 if (screen
->isXineramaActive() && blackbox
->doXineramaMaximizing()) {
1890 // find the area to use
1891 RectList availableAreas
= screen
->allAvailableAreas();
1892 RectList::iterator it
, end
= availableAreas
.end();
1894 for (it
= availableAreas
.begin(); it
!= end
; ++it
)
1895 if (it
->intersects(frame
.rect
)) break;
1896 if (it
== end
) // the window isn't inside an area
1897 it
= availableAreas
.begin(); // so just default to the first one
1899 frame
.changing
= *it
;
1902 frame
.changing
= screen
->availableArea();
1906 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1907 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1911 blackbox_attrib
.flags
|= AttribMaxVert
;
1912 blackbox_attrib
.attrib
|= AttribMaxVert
;
1914 frame
.changing
.setX(frame
.rect
.x());
1915 frame
.changing
.setWidth(frame
.rect
.width());
1919 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1920 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1922 frame
.changing
.setY(frame
.rect
.y());
1923 frame
.changing
.setHeight(frame
.rect
.height());
1930 blackbox_attrib
.flags
^= AttribShaded
;
1931 blackbox_attrib
.attrib
^= AttribShaded
;
1932 flags
.shaded
= False
;
1935 flags
.maximized
= button
;
1937 configure(frame
.changing
.x(), frame
.changing
.y(),
1938 frame
.changing
.width(), frame
.changing
.height());
1940 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1941 redrawAllButtons(); // in case it is not called in configure()
1942 setState(current_state
);
1946 // re-maximizes the window to take into account availableArea changes
1947 void BlackboxWindow::remaximize(void) {
1949 // we only update the window's attributes otherwise we lose the shade bit
1950 switch(flags
.maximized
) {
1952 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1953 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1957 blackbox_attrib
.flags
|= AttribMaxVert
;
1958 blackbox_attrib
.attrib
|= AttribMaxVert
;
1962 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1963 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1969 // save the original dimensions because maximize will wipe them out
1970 int premax_x
= blackbox_attrib
.premax_x
,
1971 premax_y
= blackbox_attrib
.premax_y
,
1972 premax_w
= blackbox_attrib
.premax_w
,
1973 premax_h
= blackbox_attrib
.premax_h
;
1975 unsigned int button
= flags
.maximized
;
1976 flags
.maximized
= 0; // trick maximize() into working
1979 // restore saved values
1980 blackbox_attrib
.premax_x
= premax_x
;
1981 blackbox_attrib
.premax_y
= premax_y
;
1982 blackbox_attrib
.premax_w
= premax_w
;
1983 blackbox_attrib
.premax_h
= premax_h
;
1987 void BlackboxWindow::setWorkspace(unsigned int n
) {
1988 blackbox_attrib
.flags
|= AttribWorkspace
;
1989 blackbox_attrib
.workspace
= n
;
1990 if (n
== BSENTINEL
) { // iconified window
1992 we set the workspace to 'all workspaces' so that taskbars will show the
1993 window. otherwise, it made uniconifying a window imposible without the
1994 blackbox workspace menu
1998 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
, n
);
2002 void BlackboxWindow::shade(void) {
2004 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
2005 frame
.inside_w
, frame
.inside_h
);
2006 flags
.shaded
= False
;
2007 blackbox_attrib
.flags
^= AttribShaded
;
2008 blackbox_attrib
.attrib
^= AttribShaded
;
2010 setState(NormalState
);
2012 // set the frame rect to the normal size
2013 frame
.rect
.setHeight(client
.rect
.height() + frame
.margin
.top
+
2014 frame
.margin
.bottom
);
2016 if (! (decorations
& Decor_Titlebar
))
2017 return; // can't shade it without a titlebar!
2019 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
2020 frame
.inside_w
, frame
.title_h
);
2021 flags
.shaded
= True
;
2022 blackbox_attrib
.flags
|= AttribShaded
;
2023 blackbox_attrib
.attrib
|= AttribShaded
;
2025 setState(IconicState
);
2027 // set the frame rect to the shaded size
2028 frame
.rect
.setHeight(frame
.title_h
+ (frame
.border_w
* 2));
2034 * (Un)Sticks a window and its relatives.
2036 void BlackboxWindow::stick(void) {
2038 blackbox_attrib
.flags
^= AttribOmnipresent
;
2039 blackbox_attrib
.attrib
^= AttribOmnipresent
;
2041 flags
.stuck
= False
;
2043 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
2044 if (i
!= blackbox_attrib
.workspace
)
2045 screen
->getWorkspace(i
)->removeWindow(this, True
);
2048 screen
->reassociateWindow(this, BSENTINEL
, True
);
2049 // temporary fix since sticky windows suck. set the hint to what we
2050 // actually hold in our data.
2051 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
2052 blackbox_attrib
.workspace
);
2054 setState(current_state
);
2058 blackbox_attrib
.flags
|= AttribOmnipresent
;
2059 blackbox_attrib
.attrib
|= AttribOmnipresent
;
2061 // temporary fix since sticky windows suck. set the hint to a different
2062 // value than that contained in the class' data.
2063 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
2066 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
2067 if (i
!= blackbox_attrib
.workspace
)
2068 screen
->getWorkspace(i
)->addWindow(this, False
, True
);
2070 setState(current_state
);
2073 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
2074 client
.transient_for
->isStuck() != flags
.stuck
)
2075 client
.transient_for
->stick();
2076 // go down the chain
2077 BlackboxWindowList::iterator it
;
2078 const BlackboxWindowList::iterator end
= client
.transientList
.end();
2079 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
2080 if ((*it
)->isStuck() != flags
.stuck
)
2085 void BlackboxWindow::redrawWindowFrame(void) const {
2086 if (decorations
& Decor_Titlebar
) {
2087 if (flags
.focused
) {
2089 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2090 frame
.title
, frame
.ftitle
);
2092 XSetWindowBackground(blackbox
->getXDisplay(),
2093 frame
.title
, frame
.ftitle_pixel
);
2096 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2097 frame
.title
, frame
.utitle
);
2099 XSetWindowBackground(blackbox
->getXDisplay(),
2100 frame
.title
, frame
.utitle_pixel
);
2102 XClearWindow(blackbox
->getXDisplay(), frame
.title
);
2108 if (decorations
& Decor_Handle
) {
2109 if (flags
.focused
) {
2111 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2112 frame
.handle
, frame
.fhandle
);
2114 XSetWindowBackground(blackbox
->getXDisplay(),
2115 frame
.handle
, frame
.fhandle_pixel
);
2118 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2119 frame
.left_grip
, frame
.fgrip
);
2120 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2121 frame
.right_grip
, frame
.fgrip
);
2123 XSetWindowBackground(blackbox
->getXDisplay(),
2124 frame
.left_grip
, frame
.fgrip_pixel
);
2125 XSetWindowBackground(blackbox
->getXDisplay(),
2126 frame
.right_grip
, frame
.fgrip_pixel
);
2130 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2131 frame
.handle
, frame
.uhandle
);
2133 XSetWindowBackground(blackbox
->getXDisplay(),
2134 frame
.handle
, frame
.uhandle_pixel
);
2137 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2138 frame
.left_grip
, frame
.ugrip
);
2139 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2140 frame
.right_grip
, frame
.ugrip
);
2142 XSetWindowBackground(blackbox
->getXDisplay(),
2143 frame
.left_grip
, frame
.ugrip_pixel
);
2144 XSetWindowBackground(blackbox
->getXDisplay(),
2145 frame
.right_grip
, frame
.ugrip_pixel
);
2148 XClearWindow(blackbox
->getXDisplay(), frame
.handle
);
2149 XClearWindow(blackbox
->getXDisplay(), frame
.left_grip
);
2150 XClearWindow(blackbox
->getXDisplay(), frame
.right_grip
);
2153 if (decorations
& Decor_Border
) {
2155 XSetWindowBorder(blackbox
->getXDisplay(),
2156 frame
.plate
, frame
.fborder_pixel
);
2158 XSetWindowBorder(blackbox
->getXDisplay(),
2159 frame
.plate
, frame
.uborder_pixel
);
2164 void BlackboxWindow::setFocusFlag(bool focus
) {
2165 // only focus a window if it is visible
2166 if (focus
&& ! flags
.visible
)
2169 flags
.focused
= focus
;
2171 redrawWindowFrame();
2174 blackbox
->setFocusedWindow(this);
2176 if (! flags
.iconic
) {
2177 // iconic windows arent in a workspace menu!
2179 screen
->getCurrentWorkspace()->setFocused(this, isFocused());
2181 screen
->getWorkspace(blackbox_attrib
.workspace
)->
2182 setFocused(this, flags
.focused
);
2187 void BlackboxWindow::installColormap(bool install
) {
2188 int i
= 0, ncmap
= 0;
2189 Colormap
*cmaps
= XListInstalledColormaps(blackbox
->getXDisplay(),
2190 client
.window
, &ncmap
);
2192 XWindowAttributes wattrib
;
2193 if (XGetWindowAttributes(blackbox
->getXDisplay(),
2194 client
.window
, &wattrib
)) {
2196 // install the window's colormap
2197 for (i
= 0; i
< ncmap
; i
++) {
2198 if (*(cmaps
+ i
) == wattrib
.colormap
)
2199 // this window is using an installed color map... do not install
2202 // otherwise, install the window's colormap
2204 XInstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2206 // uninstall the window's colormap
2207 for (i
= 0; i
< ncmap
; i
++) {
2208 if (*(cmaps
+ i
) == wattrib
.colormap
)
2209 // we found the colormap to uninstall
2210 XUninstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2220 void BlackboxWindow::setAllowedActions(void) {
2224 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_shade
);
2225 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_change_desktop
);
2226 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_close
);
2228 if (functions
& Func_Move
)
2229 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_move
);
2230 if (functions
& Func_Resize
)
2231 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_resize
);
2232 if (functions
& Func_Maximize
) {
2233 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_horz
);
2234 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_vert
);
2237 xatom
->setValue(client
.window
, XAtom::net_wm_allowed_actions
, XAtom::atom
,
2242 void BlackboxWindow::setState(unsigned long new_state
) {
2243 current_state
= new_state
;
2245 unsigned long state
[2];
2246 state
[0] = current_state
;
2248 xatom
->setValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
, state
, 2);
2250 xatom
->setValue(client
.window
, XAtom::blackbox_attributes
,
2251 XAtom::blackbox_attributes
, (unsigned long *)&blackbox_attrib
,
2252 PropBlackboxAttributesElements
);
2257 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_modal
);
2259 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_shaded
);
2261 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_hidden
);
2262 if (flags
.skip_taskbar
)
2263 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
);
2264 if (flags
.skip_pager
)
2265 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_pager
);
2266 if (flags
.fullscreen
)
2267 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_fullscreen
);
2268 if (flags
.maximized
== 1 || flags
.maximized
== 2)
2269 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_vert
);
2270 if (flags
.maximized
== 1 || flags
.maximized
== 3)
2271 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_horz
);
2272 xatom
->setValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
2277 bool BlackboxWindow::getState(void) {
2278 bool ret
= xatom
->getValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
,
2280 if (! ret
) current_state
= 0;
2285 void BlackboxWindow::restoreAttributes(void) {
2286 unsigned long num
= PropBlackboxAttributesElements
;
2287 BlackboxAttributes
*net
;
2288 if (! xatom
->getValue(client
.window
, XAtom::blackbox_attributes
,
2289 XAtom::blackbox_attributes
, num
,
2290 (unsigned long **)&net
))
2292 if (num
< PropBlackboxAttributesElements
) {
2297 if (net
->flags
& AttribShaded
&& net
->attrib
& AttribShaded
) {
2298 flags
.shaded
= False
;
2299 unsigned long orig_state
= current_state
;
2303 At this point in the life of a window, current_state should only be set
2304 to IconicState if the window was an *icon*, not if it was shaded.
2306 if (orig_state
!= IconicState
)
2307 current_state
= WithdrawnState
;
2310 if (net
->workspace
!= screen
->getCurrentWorkspaceID() &&
2311 net
->workspace
< screen
->getWorkspaceCount())
2312 screen
->reassociateWindow(this, net
->workspace
, True
);
2314 if ((blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID()) &&
2315 (blackbox_attrib
.workspace
< screen
->getWorkspaceCount())) {
2316 // set to WithdrawnState so it will be mapped on the new workspace
2317 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2318 } else if (current_state
== WithdrawnState
) {
2319 // the window is on this workspace and is Withdrawn, so it is waiting to
2321 current_state
= NormalState
;
2324 if (net
->flags
& AttribOmnipresent
&& net
->attrib
& AttribOmnipresent
&&
2328 // if the window was on another workspace, it was going to be hidden. this
2329 // specifies that the window should be mapped since it is sticky.
2330 if (current_state
== WithdrawnState
) current_state
= NormalState
;
2333 if (net
->flags
& AttribMaxHoriz
|| net
->flags
& AttribMaxVert
) {
2334 int x
= net
->premax_x
, y
= net
->premax_y
;
2335 unsigned int w
= net
->premax_w
, h
= net
->premax_h
;
2336 flags
.maximized
= 0;
2339 if ((net
->flags
& AttribMaxHoriz
) &&
2340 (net
->flags
& AttribMaxVert
))
2341 m
= (net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
2342 else if (net
->flags
& AttribMaxVert
)
2343 m
= (net
->attrib
& AttribMaxVert
) ? 2 : 0;
2344 else if (net
->flags
& AttribMaxHoriz
)
2345 m
= (net
->attrib
& AttribMaxHoriz
) ? 3 : 0;
2349 blackbox_attrib
.premax_x
= x
;
2350 blackbox_attrib
.premax_y
= y
;
2351 blackbox_attrib
.premax_w
= w
;
2352 blackbox_attrib
.premax_h
= h
;
2355 if (net
->flags
& AttribDecoration
) {
2356 switch (net
->decoration
) {
2361 /* since tools only let you toggle this anyways, we'll just make that all
2362 it supports for now.
2373 // with the state set it will then be the map event's job to read the
2374 // window's state and behave accordingly
2381 * Positions the Rect r according the the client window position and
2384 void BlackboxWindow::applyGravity(Rect
&r
) {
2385 // apply horizontal window gravity
2386 switch (client
.win_gravity
) {
2388 case NorthWestGravity
:
2389 case SouthWestGravity
:
2391 r
.setX(client
.rect
.x());
2397 r
.setX(client
.rect
.x() - (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2400 case NorthEastGravity
:
2401 case SouthEastGravity
:
2403 r
.setX(client
.rect
.x() - frame
.margin
.left
- frame
.margin
.right
+ 2);
2408 r
.setX(client
.rect
.x() - frame
.margin
.left
);
2412 // apply vertical window gravity
2413 switch (client
.win_gravity
) {
2415 case NorthWestGravity
:
2416 case NorthEastGravity
:
2418 r
.setY(client
.rect
.y());
2424 r
.setY(client
.rect
.y() - (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2427 case SouthWestGravity
:
2428 case SouthEastGravity
:
2430 r
.setY(client
.rect
.y() - frame
.margin
.top
- frame
.margin
.bottom
+ 2);
2435 r
.setY(client
.rect
.y() - frame
.margin
.top
);
2442 * The reverse of the applyGravity function.
2444 * Positions the Rect r according to the frame window position and
2447 void BlackboxWindow::restoreGravity(Rect
&r
) {
2448 // restore horizontal window gravity
2449 switch (client
.win_gravity
) {
2451 case NorthWestGravity
:
2452 case SouthWestGravity
:
2454 r
.setX(frame
.rect
.x());
2460 r
.setX(frame
.rect
.x() + (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2463 case NorthEastGravity
:
2464 case SouthEastGravity
:
2466 r
.setX(frame
.rect
.x() + frame
.margin
.left
+ frame
.margin
.right
- 2);
2471 r
.setX(frame
.rect
.x() + frame
.margin
.left
);
2475 // restore vertical window gravity
2476 switch (client
.win_gravity
) {
2478 case NorthWestGravity
:
2479 case NorthEastGravity
:
2481 r
.setY(frame
.rect
.y());
2487 r
.setY(frame
.rect
.y() + (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2490 case SouthWestGravity
:
2491 case SouthEastGravity
:
2493 r
.setY(frame
.rect
.y() + frame
.margin
.top
+ frame
.margin
.bottom
- 2);
2498 r
.setY(frame
.rect
.y() + frame
.margin
.top
);
2504 void BlackboxWindow::redrawLabel(void) const {
2505 if (flags
.focused
) {
2507 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2508 frame
.label
, frame
.flabel
);
2510 XSetWindowBackground(blackbox
->getXDisplay(),
2511 frame
.label
, frame
.flabel_pixel
);
2514 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2515 frame
.label
, frame
.ulabel
);
2517 XSetWindowBackground(blackbox
->getXDisplay(),
2518 frame
.label
, frame
.ulabel_pixel
);
2520 XClearWindow(blackbox
->getXDisplay(), frame
.label
);
2522 WindowStyle
*style
= screen
->getWindowStyle();
2524 int pos
= frame
.bevel_w
* 2;
2525 style
->doJustify(client
.title
.c_str(), pos
, frame
.label_w
, frame
.bevel_w
* 4);
2526 style
->font
->drawString(frame
.label
, pos
, 1,
2527 (flags
.focused
? style
->l_text_focus
:
2528 style
->l_text_unfocus
),
2533 void BlackboxWindow::redrawAllButtons(void) const {
2534 if (frame
.iconify_button
) redrawIconifyButton(False
);
2535 if (frame
.maximize_button
) redrawMaximizeButton(flags
.maximized
);
2536 if (frame
.close_button
) redrawCloseButton(False
);
2540 void BlackboxWindow::redrawIconifyButton(bool pressed
) const {
2542 if (flags
.focused
) {
2544 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2545 frame
.iconify_button
, frame
.fbutton
);
2547 XSetWindowBackground(blackbox
->getXDisplay(),
2548 frame
.iconify_button
, frame
.fbutton_pixel
);
2551 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2552 frame
.iconify_button
, frame
.ubutton
);
2554 XSetWindowBackground(blackbox
->getXDisplay(), frame
.iconify_button
,
2555 frame
.ubutton_pixel
);
2559 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2560 frame
.iconify_button
, frame
.pbutton
);
2562 XSetWindowBackground(blackbox
->getXDisplay(),
2563 frame
.iconify_button
, frame
.pbutton_pixel
);
2565 XClearWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
2567 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2568 screen
->getWindowStyle()->b_pic_unfocus
);
2569 XDrawRectangle(blackbox
->getXDisplay(), frame
.iconify_button
, pen
.gc(),
2570 2, (frame
.button_w
- 5), (frame
.button_w
- 5), 2);
2574 void BlackboxWindow::redrawMaximizeButton(bool pressed
) const {
2576 if (flags
.focused
) {
2578 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2579 frame
.maximize_button
, frame
.fbutton
);
2581 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2582 frame
.fbutton_pixel
);
2585 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2586 frame
.maximize_button
, frame
.ubutton
);
2588 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2589 frame
.ubutton_pixel
);
2593 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2594 frame
.maximize_button
, frame
.pbutton
);
2596 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2597 frame
.pbutton_pixel
);
2599 XClearWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
2601 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2602 screen
->getWindowStyle()->b_pic_unfocus
);
2603 XDrawRectangle(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2604 2, 2, (frame
.button_w
- 5), (frame
.button_w
- 5));
2605 XDrawLine(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2606 2, 3, (frame
.button_w
- 3), 3);
2610 void BlackboxWindow::redrawCloseButton(bool pressed
) const {
2612 if (flags
.focused
) {
2614 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2617 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2618 frame
.fbutton_pixel
);
2621 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2624 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2625 frame
.ubutton_pixel
);
2629 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2630 frame
.close_button
, frame
.pbutton
);
2632 XSetWindowBackground(blackbox
->getXDisplay(),
2633 frame
.close_button
, frame
.pbutton_pixel
);
2635 XClearWindow(blackbox
->getXDisplay(), frame
.close_button
);
2637 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2638 screen
->getWindowStyle()->b_pic_unfocus
);
2639 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2640 2, 2, (frame
.button_w
- 3), (frame
.button_w
- 3));
2641 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2642 2, (frame
.button_w
- 3), (frame
.button_w
- 3), 2);
2646 void BlackboxWindow::mapRequestEvent(const XMapRequestEvent
*re
) {
2647 if (re
->window
!= client
.window
)
2651 fprintf(stderr
, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2656 Even though the window wants to be shown, if it is not on the current
2657 workspace, then it isn't going to be shown right now.
2659 if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID() &&
2660 blackbox_attrib
.workspace
< screen
->getWorkspaceCount())
2661 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2663 switch (current_state
) {
2668 case WithdrawnState
:
2677 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2679 if (! blackbox
->isStartup()) {
2680 XSync(blackbox
->getXDisplay(), False
); // make sure the frame is mapped
2681 if (screen
->doFocusNew() || (isTransient() && getTransientFor() &&
2682 getTransientFor()->isFocused())) {
2685 if (screen
->getPlacementPolicy() == BScreen::ClickMousePlacement
) {
2689 XQueryPointer(blackbox
->getXDisplay(), screen
->getRootWindow(),
2690 &r
, &c
, &rx
, &ry
, &x
, &y
, &m
);
2700 void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent
*ue
) {
2701 if (ue
->window
!= client
.window
)
2705 fprintf(stderr
, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2709 screen
->unmanageWindow(this, False
);
2713 void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent
*de
) {
2714 if (de
->window
!= client
.window
)
2718 fprintf(stderr
, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2722 screen
->unmanageWindow(this, False
);
2726 void BlackboxWindow::reparentNotifyEvent(const XReparentEvent
*re
) {
2727 if (re
->window
!= client
.window
|| re
->parent
== frame
.plate
)
2731 fprintf(stderr
, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2732 "0x%lx.\n", client
.window
, re
->parent
);
2737 XPutBackEvent(blackbox
->getXDisplay(), &ev
);
2738 screen
->unmanageWindow(this, True
);
2742 void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent
*pe
) {
2743 if (pe
->state
== PropertyDelete
|| ! validateClient())
2747 fprintf(stderr
, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n",
2753 case XA_WM_CLIENT_MACHINE
:
2757 case XA_WM_TRANSIENT_FOR
: {
2758 bool s
= flags
.stuck
;
2760 // determine if this is a transient window
2763 if (flags
.stuck
!= s
) stick();
2765 // adjust the window decorations based on transience
2766 if (isTransient()) {
2767 functions
&= ~Func_Maximize
;
2768 setAllowedActions();
2780 case XA_WM_ICON_NAME
:
2782 if (flags
.iconic
) screen
->propagateWindowName(this);
2785 case XAtom::net_wm_name
:
2789 if (decorations
& Decor_Titlebar
)
2792 screen
->propagateWindowName(this);
2795 case XA_WM_NORMAL_HINTS
: {
2798 if ((client
.normal_hint_flags
& PMinSize
) &&
2799 (client
.normal_hint_flags
& PMaxSize
)) {
2800 // the window now can/can't resize itself, so the buttons need to be
2803 if (client
.max_width
<= client
.min_width
&&
2804 client
.max_height
<= client
.min_height
) {
2805 functions
&= ~(Func_Resize
| Func_Maximize
);
2807 if (! isTransient())
2808 functions
|= Func_Maximize
;
2809 functions
|= Func_Resize
;
2812 setAllowedActions();
2816 Rect old_rect
= frame
.rect
;
2820 if (old_rect
!= frame
.rect
)
2827 if (pe
->atom
== xatom
->getAtom(XAtom::wm_protocols
)) {
2830 if ((decorations
& Decor_Close
) && (! frame
.close_button
)) {
2831 createCloseButton();
2832 if (decorations
& Decor_Titlebar
) {
2833 positionButtons(True
);
2834 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
2836 if (windowmenu
) windowmenu
->reconfigure();
2838 } else if (pe
->atom
== xatom
->getAtom(XAtom::net_wm_strut
)) {
2847 void BlackboxWindow::exposeEvent(const XExposeEvent
*ee
) {
2849 fprintf(stderr
, "BlackboxWindow::exposeEvent() for 0x%lx\n", client
.window
);
2852 if (frame
.label
== ee
->window
&& (decorations
& Decor_Titlebar
))
2854 else if (frame
.close_button
== ee
->window
)
2855 redrawCloseButton(False
);
2856 else if (frame
.maximize_button
== ee
->window
)
2857 redrawMaximizeButton(flags
.maximized
);
2858 else if (frame
.iconify_button
== ee
->window
)
2859 redrawIconifyButton(False
);
2863 void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent
*cr
) {
2864 if (cr
->window
!= client
.window
|| flags
.iconic
)
2867 if (cr
->value_mask
& CWBorderWidth
)
2868 client
.old_bw
= cr
->border_width
;
2870 if (cr
->value_mask
& (CWX
| CWY
| CWWidth
| CWHeight
)) {
2871 frame
.changing
= frame
.rect
;
2873 if (cr
->value_mask
& (CWX
| CWY
)) {
2874 if (cr
->value_mask
& CWX
)
2875 client
.rect
.setX(cr
->x
);
2876 if (cr
->value_mask
& CWY
)
2877 client
.rect
.setY(cr
->y
);
2879 applyGravity(frame
.changing
);
2882 if (cr
->value_mask
& (CWWidth
| CWHeight
)) {
2883 if (cr
->value_mask
& CWWidth
)
2884 frame
.changing
.setWidth(cr
->width
+
2885 frame
.margin
.left
+ frame
.margin
.right
);
2887 if (cr
->value_mask
& CWHeight
)
2888 frame
.changing
.setHeight(cr
->height
+
2889 frame
.margin
.top
+ frame
.margin
.bottom
);
2892 if a position change ha been specified, then that position will be used
2893 instead of determining a position based on the window's gravity.
2895 if (cr
->value_mask
& (CWX
| CWY
)) {
2897 switch (client
.win_gravity
) {
2898 case NorthEastGravity
:
2902 case SouthWestGravity
:
2904 corner
= BottomLeft
;
2906 case SouthEastGravity
:
2907 corner
= BottomRight
;
2909 default: // NorthWest, Static, etc
2916 configure(frame
.changing
.x(), frame
.changing
.y(),
2917 frame
.changing
.width(), frame
.changing
.height());
2920 if (cr
->value_mask
& CWStackMode
&& !isDesktop()) {
2921 switch (cr
->detail
) {
2924 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2930 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2937 void BlackboxWindow::buttonPressEvent(const XButtonEvent
*be
) {
2939 fprintf(stderr
, "BlackboxWindow::buttonPressEvent() for 0x%lx\n",
2943 if (frame
.maximize_button
== be
->window
&& be
->button
<= 3) {
2944 redrawMaximizeButton(True
);
2945 } else if (be
->button
== 1 || (be
->button
== 3 && be
->state
== mod_mask
)) {
2946 if (! flags
.focused
)
2949 if (frame
.iconify_button
== be
->window
) {
2950 redrawIconifyButton(True
);
2951 } else if (frame
.close_button
== be
->window
) {
2952 redrawCloseButton(True
);
2953 } else if (frame
.plate
== be
->window
) {
2954 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2956 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2958 XAllowEvents(blackbox
->getXDisplay(), ReplayPointer
, be
->time
);
2960 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
2961 if (((be
->time
- lastButtonPressTime
) <=
2962 blackbox
->getDoubleClickInterval()) ||
2963 (be
->state
== ControlMask
)) {
2964 lastButtonPressTime
= 0;
2967 lastButtonPressTime
= be
->time
;
2971 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2973 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2975 } else if (be
->button
== 2 && (be
->window
!= frame
.iconify_button
) &&
2976 (be
->window
!= frame
.close_button
)) {
2977 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2978 } else if (windowmenu
&& be
->button
== 3 &&
2979 (frame
.title
== be
->window
|| frame
.label
== be
->window
||
2980 frame
.handle
== be
->window
|| frame
.window
== be
->window
)) {
2981 if (windowmenu
->isVisible()) {
2984 int mx
= be
->x_root
- windowmenu
->getWidth() / 2,
2985 my
= be
->y_root
- windowmenu
->getHeight() / 2;
2987 // snap the window menu into a corner/side if necessary
2988 int left_edge
, right_edge
, top_edge
, bottom_edge
;
2991 the " + (frame.border_w * 2) - 1" bits are to get the proper width
2992 and height of the menu, as the sizes returned by it do not include
2995 left_edge
= frame
.rect
.x();
2996 right_edge
= frame
.rect
.right() -
2997 (windowmenu
->getWidth() + (frame
.border_w
* 2) - 1);
2998 top_edge
= client
.rect
.top() - (frame
.border_w
+ frame
.mwm_border_w
);
2999 bottom_edge
= client
.rect
.bottom() -
3000 (windowmenu
->getHeight() + (frame
.border_w
* 2) - 1) +
3001 (frame
.border_w
+ frame
.mwm_border_w
);
3005 if (mx
> right_edge
)
3009 if (my
> bottom_edge
)
3012 windowmenu
->move(mx
, my
);
3014 XRaiseWindow(blackbox
->getXDisplay(), windowmenu
->getWindowID());
3015 XRaiseWindow(blackbox
->getXDisplay(),
3016 windowmenu
->getSendToMenu()->getWindowID());
3019 } else if (be
->button
== 4) {
3020 if ((be
->window
== frame
.label
||
3021 be
->window
== frame
.title
||
3022 be
->window
== frame
.maximize_button
||
3023 be
->window
== frame
.iconify_button
||
3024 be
->window
== frame
.close_button
) &&
3028 } else if (be
->button
== 5) {
3029 if ((be
->window
== frame
.label
||
3030 be
->window
== frame
.title
||
3031 be
->window
== frame
.maximize_button
||
3032 be
->window
== frame
.iconify_button
||
3033 be
->window
== frame
.close_button
) &&
3040 void BlackboxWindow::buttonReleaseEvent(const XButtonEvent
*re
) {
3042 fprintf(stderr
, "BlackboxWindow::buttonReleaseEvent() for 0x%lx\n",
3046 if (re
->window
== frame
.maximize_button
&&
3047 re
->button
>= 1 && re
->button
<= 3) {
3048 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3049 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
3050 maximize(re
->button
);
3052 redrawMaximizeButton(flags
.maximized
);
3054 } else if (re
->window
== frame
.iconify_button
&& re
->button
== 1) {
3055 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3056 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
3059 redrawIconifyButton(False
);
3061 } else if (re
->window
== frame
.close_button
& re
->button
== 1) {
3062 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3063 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
)))
3065 redrawCloseButton(False
);
3066 } else if (flags
.moving
) {
3068 } else if (flags
.resizing
) {
3070 } else if (re
->window
== frame
.window
) {
3071 if (re
->button
== 2 && re
->state
== mod_mask
)
3072 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3078 void BlackboxWindow::beginMove(int x_root
, int y_root
) {
3079 if (! (functions
& Func_Move
)) return;
3081 assert(! (flags
.resizing
|| flags
.moving
));
3084 Only one window can be moved/resized at a time. If another window is already
3085 being moved or resized, then stop it before whating to work with this one.
3087 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3088 if (changing
&& changing
!= this) {
3089 if (changing
->flags
.moving
)
3090 changing
->endMove();
3091 else // if (changing->flags.resizing)
3092 changing
->endResize();
3095 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3096 PointerMotionMask
| ButtonReleaseMask
,
3097 GrabModeAsync
, GrabModeAsync
,
3098 None
, blackbox
->getMoveCursor(), CurrentTime
);
3100 if (windowmenu
&& windowmenu
->isVisible())
3103 flags
.moving
= True
;
3104 blackbox
->setChangingWindow(this);
3106 if (! screen
->doOpaqueMove()) {
3107 XGrabServer(blackbox
->getXDisplay());
3109 frame
.changing
= frame
.rect
;
3110 screen
->showPosition(frame
.changing
.x(), frame
.changing
.y());
3112 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3116 frame
.changing
.width() - 1,
3117 frame
.changing
.height() - 1);
3120 frame
.grab_x
= x_root
- frame
.rect
.x() - frame
.border_w
;
3121 frame
.grab_y
= y_root
- frame
.rect
.y() - frame
.border_w
;
3125 void BlackboxWindow::doMove(int x_root
, int y_root
) {
3126 assert(flags
.moving
);
3127 assert(blackbox
->getChangingWindow() == this);
3129 int dx
= x_root
- frame
.grab_x
, dy
= y_root
- frame
.grab_y
;
3130 dx
-= frame
.border_w
;
3131 dy
-= frame
.border_w
;
3133 doWindowSnapping(dx
, dy
);
3135 if (screen
->doOpaqueMove()) {
3136 if (screen
->doWorkspaceWarping())
3137 doWorkspaceWarping(x_root
, y_root
, dx
);
3139 configure(dx
, dy
, frame
.rect
.width(), frame
.rect
.height());
3141 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3145 frame
.changing
.width() - 1,
3146 frame
.changing
.height() - 1);
3148 if (screen
->doWorkspaceWarping())
3149 doWorkspaceWarping(x_root
, y_root
, dx
);
3151 frame
.changing
.setPos(dx
, dy
);
3153 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3157 frame
.changing
.width() - 1,
3158 frame
.changing
.height() - 1);
3161 screen
->showPosition(dx
, dy
);
3165 void BlackboxWindow::doWorkspaceWarping(int x_root
, int y_root
, int &dx
) {
3166 // workspace warping
3168 unsigned int dest
= screen
->getCurrentWorkspaceID();
3172 if (dest
> 0) dest
--;
3173 else dest
= screen
->getNumberOfWorkspaces() - 1;
3175 } else if (x_root
>= screen
->getRect().right()) {
3178 if (dest
< screen
->getNumberOfWorkspaces() - 1) dest
++;
3184 bool focus
= flags
.focused
; // had focus while moving?
3186 int dest_x
= x_root
;
3188 dest_x
+= screen
->getRect().width() - 1;
3189 dx
+= screen
->getRect().width() - 1;
3191 dest_x
-= screen
->getRect().width() - 1;
3192 dx
-= screen
->getRect().width() - 1;
3196 screen
->reassociateWindow(this, dest
, False
);
3197 screen
->changeWorkspaceID(dest
);
3199 if (screen
->doOpaqueMove())
3200 XGrabServer(blackbox
->getXDisplay());
3202 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3203 XWarpPointer(blackbox
->getXDisplay(), None
,
3204 screen
->getRootWindow(), 0, 0, 0, 0,
3206 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3207 PointerMotionMask
| ButtonReleaseMask
,
3208 GrabModeAsync
, GrabModeAsync
,
3209 None
, blackbox
->getMoveCursor(), CurrentTime
);
3211 if (screen
->doOpaqueMove())
3212 XUngrabServer(blackbox
->getXDisplay());
3220 void BlackboxWindow::doWindowSnapping(int &dx
, int &dy
) {
3221 // how much resistance to edges to provide
3222 const int resistance_size
= screen
->getResistanceSize();
3224 // how far away to snap
3225 const int snap_distance
= screen
->getSnapThreshold();
3227 // how to snap windows
3228 const int snap_to_windows
= screen
->getWindowToWindowSnap();
3229 const int snap_to_edges
= screen
->getWindowToEdgeSnap();
3230 // the amount of space away from the edge to provide resistance/snap
3231 const int snap_offset
= screen
->getSnapOffset();
3233 // find the geomeetery where the moving window currently is
3234 const Rect
&moving
= screen
->doOpaqueMove() ? frame
.rect
: frame
.changing
;
3237 const int wleft
= dx
,
3238 wright
= dx
+ frame
.rect
.width() - 1,
3240 wbottom
= dy
+ frame
.rect
.height() - 1;
3242 if (snap_to_windows
) {
3245 Workspace
*w
= screen
->getWorkspace(getWorkspaceNumber());
3248 // add windows on the workspace to the rect list
3249 const BlackboxWindowList
& stack_list
= w
->getStackingList();
3250 BlackboxWindowList::const_iterator st_it
, st_end
= stack_list
.end();
3251 for (st_it
= stack_list
.begin(); st_it
!= st_end
; ++st_it
)
3252 if (*st_it
!= this) // don't snap to ourself
3253 rectlist
.push_back( (*st_it
)->frameRect() );
3255 // add the toolbar and the slit to the rect list.
3256 // (only if they are not hidden)
3257 Toolbar
*tbar
= screen
->getToolbar();
3258 Slit
*slit
= screen
->getSlit();
3259 Rect tbar_rect
, slit_rect
;
3260 unsigned int bwidth
= screen
->getBorderWidth() * 2;
3262 if (! (screen
->doHideToolbar() || tbar
->isHidden())) {
3263 tbar_rect
.setRect(tbar
->getX(), tbar
->getY(), tbar
->getWidth() + bwidth
,
3264 tbar
->getHeight() + bwidth
);
3265 rectlist
.push_back(tbar_rect
);
3268 if (! slit
->isHidden()) {
3269 slit_rect
.setRect(slit
->getX(), slit
->getY(), slit
->getWidth() + bwidth
,
3270 slit
->getHeight() + bwidth
);
3271 rectlist
.push_back(slit_rect
);
3274 RectList::const_iterator it
, end
= rectlist
.end();
3275 for (it
= rectlist
.begin(); it
!= end
; ++it
) {
3276 bool snapped
= False
;
3277 const Rect
&winrect
= *it
;
3279 offsetrect
.setCoords(winrect
.left() - snap_offset
,
3280 winrect
.top() - snap_offset
,
3281 winrect
.right() + snap_offset
,
3282 winrect
.bottom() + snap_offset
);
3284 if (snap_to_windows
== BScreen::WindowResistance
)
3285 // if the window is already over top of this snap target, then
3286 // resistance is futile, so just ignore it
3287 if (winrect
.intersects(moving
))
3290 int dleft
, dright
, dtop
, dbottom
;
3292 // if the windows are in the same plane vertically
3293 if (wtop
>= (signed)(winrect
.y() - frame
.rect
.height() + 1) &&
3294 wtop
< (signed)(winrect
.y() + winrect
.height() - 1)) {
3296 if (snap_to_windows
== BScreen::WindowResistance
) {
3297 dleft
= wright
- offsetrect
.left();
3298 dright
= offsetrect
.right() - wleft
;
3300 // snap left of other window?
3301 if (dleft
>= 0 && dleft
< resistance_size
&&
3302 dleft
< (wright
- wleft
)) {
3303 dx
= offsetrect
.left() - frame
.rect
.width();
3306 // snap right of other window?
3307 else if (dright
>= 0 && dright
< resistance_size
&&
3308 dright
< (wright
- wleft
)) {
3309 dx
= offsetrect
.right() + 1;
3312 } else { // BScreen::WindowSnap
3313 dleft
= abs(wright
- offsetrect
.left());
3314 dright
= abs(wleft
- offsetrect
.right());
3316 // snap left of other window?
3317 if (dleft
< snap_distance
&& dleft
<= dright
) {
3318 dx
= offsetrect
.left() - frame
.rect
.width();
3321 // snap right of other window?
3322 else if (dright
< snap_distance
) {
3323 dx
= offsetrect
.right() + 1;
3329 if (screen
->getWindowCornerSnap()) {
3330 // try corner-snap to its other sides
3331 if (snap_to_windows
== BScreen::WindowResistance
) {
3332 dtop
= winrect
.top() - wtop
;
3333 dbottom
= wbottom
- winrect
.bottom();
3334 if (dtop
> 0 && dtop
< resistance_size
) {
3335 // if we're already past the top edge, then don't provide
3337 if (moving
.top() >= winrect
.top())
3339 } else if (dbottom
> 0 && dbottom
< resistance_size
) {
3340 // if we're already past the bottom edge, then don't provide
3342 if (moving
.bottom() <= winrect
.bottom())
3343 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
3345 } else { // BScreen::WindowSnap
3346 dtop
= abs(wtop
- winrect
.top());
3347 dbottom
= abs(wbottom
- winrect
.bottom());
3348 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3350 else if (dbottom
< snap_distance
)
3351 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
3359 // if the windows are on the same plane horizontally
3360 if (wleft
>= (signed)(winrect
.x() - frame
.rect
.width() + 1) &&
3361 wleft
< (signed)(winrect
.x() + winrect
.width() - 1)) {
3363 if (snap_to_windows
== BScreen::WindowResistance
) {
3364 dtop
= wbottom
- offsetrect
.top();
3365 dbottom
= offsetrect
.bottom() - wtop
;
3367 // snap top of other window?
3368 if (dtop
>= 0 && dtop
< resistance_size
&& dtop
< (wbottom
- wtop
)) {
3369 dy
= offsetrect
.top() - frame
.rect
.height();
3372 // snap bottom of other window?
3373 else if (dbottom
>= 0 && dbottom
< resistance_size
&&
3374 dbottom
< (wbottom
- wtop
)) {
3375 dy
= offsetrect
.bottom() + 1;
3378 } else { // BScreen::WindowSnap
3379 dtop
= abs(wbottom
- offsetrect
.top());
3380 dbottom
= abs(wtop
- offsetrect
.bottom());
3382 // snap top of other window?
3383 if (dtop
< snap_distance
&& dtop
<= dbottom
) {
3384 dy
= offsetrect
.top() - frame
.rect
.height();
3387 // snap bottom of other window?
3388 else if (dbottom
< snap_distance
) {
3389 dy
= offsetrect
.bottom() + 1;
3396 if (screen
->getWindowCornerSnap()) {
3397 // try corner-snap to its other sides
3398 if (snap_to_windows
== BScreen::WindowResistance
) {
3399 dleft
= winrect
.left() - wleft
;
3400 dright
= wright
- winrect
.right();
3401 if (dleft
> 0 && dleft
< resistance_size
) {
3402 // if we're already past the left edge, then don't provide
3404 if (moving
.left() >= winrect
.left())
3405 dx
= winrect
.left();
3406 } else if (dright
> 0 && dright
< resistance_size
) {
3407 // if we're already past the right edge, then don't provide
3409 if (moving
.right() <= winrect
.right())
3410 dx
= winrect
.right() - frame
.rect
.width() + 1;
3412 } else { // BScreen::WindowSnap
3413 dleft
= abs(wleft
- winrect
.left());
3414 dright
= abs(wright
- winrect
.right());
3415 if (dleft
< snap_distance
&& dleft
<= dright
)
3416 dx
= winrect
.left();
3417 else if (dright
< snap_distance
)
3418 dx
= winrect
.right() - frame
.rect
.width() + 1;
3428 if (snap_to_edges
) {
3431 // snap to the screen edges (and screen boundaries for xinerama)
3433 if (screen
->isXineramaActive() && blackbox
->doXineramaSnapping()) {
3434 rectlist
.insert(rectlist
.begin(),
3435 screen
->getXineramaAreas().begin(),
3436 screen
->getXineramaAreas().end());
3439 rectlist
.push_back(screen
->getRect());
3441 RectList::const_iterator it
, end
= rectlist
.end();
3442 for (it
= rectlist
.begin(); it
!= end
; ++it
) {
3443 const Rect
&srect
= *it
;
3445 offsetrect
.setCoords(srect
.left() + snap_offset
,
3446 srect
.top() + snap_offset
,
3447 srect
.right() - snap_offset
,
3448 srect
.bottom() - snap_offset
);
3450 if (snap_to_edges
== BScreen::WindowResistance
) {
3451 // if we're not in the rectangle then don't snap to it.
3452 if (! srect
.contains(moving
))
3454 } else { // BScreen::WindowSnap
3455 // if we're not in the rectangle then don't snap to it.
3456 if (! srect
.intersects(Rect(wleft
, wtop
, frame
.rect
.width(),
3457 frame
.rect
.height())))
3461 if (snap_to_edges
== BScreen::WindowResistance
) {
3462 int dleft
= offsetrect
.left() - wleft
,
3463 dright
= wright
- offsetrect
.right(),
3464 dtop
= offsetrect
.top() - wtop
,
3465 dbottom
= wbottom
- offsetrect
.bottom();
3468 if (dleft
> 0 && dleft
< resistance_size
)
3469 dx
= offsetrect
.left();
3471 else if (dright
> 0 && dright
< resistance_size
)
3472 dx
= offsetrect
.right() - frame
.rect
.width() + 1;
3475 if (dtop
> 0 && dtop
< resistance_size
)
3476 dy
= offsetrect
.top();
3478 else if (dbottom
> 0 && dbottom
< resistance_size
)
3479 dy
= offsetrect
.bottom() - frame
.rect
.height() + 1;
3480 } else { // BScreen::WindowSnap
3481 int dleft
= abs(wleft
- offsetrect
.left()),
3482 dright
= abs(wright
- offsetrect
.right()),
3483 dtop
= abs(wtop
- offsetrect
.top()),
3484 dbottom
= abs(wbottom
- offsetrect
.bottom());
3487 if (dleft
< snap_distance
&& dleft
<= dright
)
3488 dx
= offsetrect
.left();
3490 else if (dright
< snap_distance
)
3491 dx
= offsetrect
.right() - frame
.rect
.width() + 1;
3494 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3495 dy
= offsetrect
.top();
3497 else if (dbottom
< snap_distance
)
3498 dy
= offsetrect
.bottom() - frame
.rect
.height() + 1;
3505 void BlackboxWindow::endMove(void) {
3506 assert(flags
.moving
);
3507 assert(blackbox
->getChangingWindow() == this);
3509 flags
.moving
= False
;
3510 blackbox
->setChangingWindow(0);
3512 if (! screen
->doOpaqueMove()) {
3513 /* when drawing the rubber band, we need to make sure we only draw inside
3514 * the frame... frame.changing_* contain the new coords for the window,
3515 * so we need to subtract 1 from changing_w/changing_h every where we
3516 * draw the rubber band (for both moving and resizing)
3518 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3519 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3520 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3521 XUngrabServer(blackbox
->getXDisplay());
3523 configure(frame
.changing
.x(), frame
.changing
.y(),
3524 frame
.changing
.width(), frame
.changing
.height());
3526 configure(frame
.rect
.x(), frame
.rect
.y(),
3527 frame
.rect
.width(), frame
.rect
.height());
3529 screen
->hideGeometry();
3531 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3533 // if there are any left over motions from the move, drop them now
3534 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3536 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3541 void BlackboxWindow::beginResize(int x_root
, int y_root
, Corner dir
) {
3542 if (! (functions
& Func_Resize
)) return;
3544 assert(! (flags
.resizing
|| flags
.moving
));
3547 Only one window can be moved/resized at a time. If another window is
3548 already being moved or resized, then stop it before whating to work with
3551 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3552 if (changing
&& changing
!= this) {
3553 if (changing
->flags
.moving
)
3554 changing
->endMove();
3555 else // if (changing->flags.resizing)
3556 changing
->endResize();
3564 switch (resize_dir
) {
3567 cursor
= blackbox
->getLowerLeftAngleCursor();
3572 cursor
= blackbox
->getLowerRightAngleCursor();
3576 anchor
= BottomRight
;
3577 cursor
= blackbox
->getUpperLeftAngleCursor();
3581 anchor
= BottomLeft
;
3582 cursor
= blackbox
->getUpperRightAngleCursor();
3586 assert(false); // unhandled Corner
3587 return; // unreachable, for the compiler
3590 XGrabServer(blackbox
->getXDisplay());
3591 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3592 PointerMotionMask
| ButtonReleaseMask
,
3593 GrabModeAsync
, GrabModeAsync
, None
, cursor
, CurrentTime
);
3595 flags
.resizing
= True
;
3596 blackbox
->setChangingWindow(this);
3598 unsigned int gw
, gh
;
3599 frame
.changing
= frame
.rect
;
3601 constrain(anchor
, &gw
, &gh
);
3603 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3604 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3605 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3607 screen
->showGeometry(gw
, gh
);
3609 frame
.grab_x
= x_root
;
3610 frame
.grab_y
= y_root
;
3614 void BlackboxWindow::doResize(int x_root
, int y_root
) {
3615 assert(flags
.resizing
);
3616 assert(blackbox
->getChangingWindow() == this);
3618 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3619 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3620 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3622 unsigned int gw
, gh
;
3624 int dx
, dy
; // the amount of change in the size of the window
3626 switch (resize_dir
) {
3629 dx
= - (x_root
- frame
.grab_x
);
3630 dy
= + (y_root
- frame
.grab_y
);
3634 dx
= + (x_root
- frame
.grab_x
);
3635 dy
= + (y_root
- frame
.grab_y
);
3638 anchor
= BottomRight
;
3639 dx
= - (x_root
- frame
.grab_x
);
3640 dy
= - (y_root
- frame
.grab_y
);
3643 anchor
= BottomLeft
;
3644 dx
= + (x_root
- frame
.grab_x
);
3645 dy
= - (y_root
- frame
.grab_y
);
3649 assert(false); // unhandled Corner
3650 return; // unreachable, for the compiler
3653 // make sure the user cant resize the window smaller than 0, which makes it
3654 // wrap around and become huge
3655 if (dx
< -(signed)client
.rect
.width()) dx
= -(signed)client
.rect
.width();
3656 if (dy
< -(signed)client
.rect
.height()) dy
= -(signed)client
.rect
.height();
3658 frame
.changing
.setSize(frame
.rect
.width() + dx
, frame
.rect
.height() + dy
);
3660 constrain(anchor
, &gw
, &gh
);
3662 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3663 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3664 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3666 screen
->showGeometry(gw
, gh
);
3670 void BlackboxWindow::endResize(void) {
3671 assert(flags
.resizing
);
3672 assert(blackbox
->getChangingWindow() == this);
3674 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3675 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3676 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3677 XUngrabServer(blackbox
->getXDisplay());
3679 // unset maximized state after resized when fully maximized
3680 if (flags
.maximized
== 1)
3683 flags
.resizing
= False
;
3684 blackbox
->setChangingWindow(0);
3686 configure(frame
.changing
.x(), frame
.changing
.y(),
3687 frame
.changing
.width(), frame
.changing
.height());
3688 screen
->hideGeometry();
3690 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3692 // if there are any left over motions from the resize, drop them now
3693 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3695 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3700 void BlackboxWindow::motionNotifyEvent(const XMotionEvent
*me
) {
3702 fprintf(stderr
, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n",
3707 doMove(me
->x_root
, me
->y_root
);
3708 } else if (flags
.resizing
) {
3709 doResize(me
->x_root
, me
->y_root
);
3711 if ((functions
& Func_Move
) &&
3712 (me
->state
& Button1Mask
) &&
3713 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3714 frame
.handle
== me
->window
|| frame
.window
== me
->window
)) {
3715 beginMove(me
->x_root
, me
->y_root
);
3716 } else if ((functions
& Func_Resize
) &&
3717 ((me
->state
& Button1Mask
) && (me
->window
== frame
.right_grip
||
3718 me
->window
== frame
.left_grip
)) ||
3719 ((me
->state
& Button3Mask
) && (me
->state
& mod_mask
) &&
3720 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3721 frame
.handle
== me
->window
|| frame
.window
== me
->window
))) {
3722 unsigned int zones
= screen
->getResizeZones();
3725 if (me
->window
== frame
.left_grip
) {
3726 corner
= BottomLeft
;
3727 } else if (me
->window
== frame
.right_grip
|| zones
== 1) {
3728 corner
= BottomRight
;
3731 bool left
= (me
->x_root
- frame
.rect
.x() <=
3732 static_cast<signed>(frame
.rect
.width() / 2));
3735 else // (zones == 4)
3736 top
= (me
->y_root
- frame
.rect
.y() <=
3737 static_cast<signed>(frame
.rect
.height() / 2));
3738 corner
= (top
? (left
? TopLeft
: TopRight
) :
3739 (left
? BottomLeft
: BottomRight
));
3742 beginResize(me
->x_root
, me
->y_root
, corner
);
3748 void BlackboxWindow::enterNotifyEvent(const XCrossingEvent
* ce
) {
3749 if (! (screen
->isSloppyFocus() && isVisible() && isNormal()))
3753 bool leave
= False
, inferior
= False
;
3755 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), ce
->window
,
3757 if (e
.type
== LeaveNotify
&& e
.xcrossing
.mode
== NotifyNormal
) {
3759 inferior
= (e
.xcrossing
.detail
== NotifyInferior
);
3763 if (! leave
|| inferior
) {
3764 if (! isFocused()) {
3765 bool success
= setInputFocus();
3766 if (success
) // if focus succeeded install the colormap
3767 installColormap(True
); // XXX: shouldnt we honour no install?
3770 if (screen
->doAutoRaise())
3776 void BlackboxWindow::leaveNotifyEvent(const XCrossingEvent
*) {
3777 if (! (screen
->isSloppyFocus() && screen
->doAutoRaise() && isNormal()))
3780 installColormap(False
);
3782 if (timer
->isTiming())
3788 void BlackboxWindow::shapeEvent(XShapeEvent
*) {
3789 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
3796 bool BlackboxWindow::validateClient(void) const {
3797 XSync(blackbox
->getXDisplay(), False
);
3800 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3801 DestroyNotify
, &e
) ||
3802 XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3804 XPutBackEvent(blackbox
->getXDisplay(), &e
);
3813 void BlackboxWindow::restore(bool remap
) {
3814 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeDelete
);
3815 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
3816 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, NoEventMask
);
3818 // do not leave a shaded window as an icon unless it was an icon
3819 if (flags
.shaded
&& ! flags
.iconic
)
3820 setState(NormalState
);
3822 // erase the netwm stuff that we read when a window maps, so that it
3823 // doesn't persist between mappings.
3824 // (these are the ones read in getNetWMFlags().)
3825 xatom
->eraseValue(client
.window
, XAtom::net_wm_desktop
);
3826 xatom
->eraseValue(client
.window
, XAtom::net_wm_state
);
3828 restoreGravity(client
.rect
);
3830 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
3831 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
3833 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, client
.old_bw
);
3836 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3837 ReparentNotify
, &ev
)) {
3840 // according to the ICCCM - if the client doesn't reparent to
3841 // root, then we have to do it for them
3842 XReparentWindow(blackbox
->getXDisplay(), client
.window
,
3843 screen
->getRootWindow(),
3844 client
.rect
.x(), client
.rect
.y());
3847 if (remap
) XMapWindow(blackbox
->getXDisplay(), client
.window
);
3851 // timer for autoraise
3852 void BlackboxWindow::timeout(void) {
3853 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3857 void BlackboxWindow::changeBlackboxHints(const BlackboxHints
*net
) {
3858 if ((net
->flags
& AttribShaded
) &&
3859 ((blackbox_attrib
.attrib
& AttribShaded
) !=
3860 (net
->attrib
& AttribShaded
)))
3863 if (flags
.visible
&& // watch out for requests when we can not be seen
3864 (net
->flags
& (AttribMaxVert
| AttribMaxHoriz
)) &&
3865 ((blackbox_attrib
.attrib
& (AttribMaxVert
| AttribMaxHoriz
)) !=
3866 (net
->attrib
& (AttribMaxVert
| AttribMaxHoriz
)))) {
3867 if (flags
.maximized
) {
3872 if ((net
->flags
& AttribMaxHoriz
) && (net
->flags
& AttribMaxVert
))
3873 button
= ((net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0);
3874 else if (net
->flags
& AttribMaxVert
)
3875 button
= ((net
->attrib
& AttribMaxVert
) ? 2 : 0);
3876 else if (net
->flags
& AttribMaxHoriz
)
3877 button
= ((net
->attrib
& AttribMaxHoriz
) ? 3 : 0);
3883 if ((net
->flags
& AttribOmnipresent
) &&
3884 ((blackbox_attrib
.attrib
& AttribOmnipresent
) !=
3885 (net
->attrib
& AttribOmnipresent
)))
3888 if ((net
->flags
& AttribWorkspace
) &&
3889 (blackbox_attrib
.workspace
!= net
->workspace
)) {
3890 screen
->reassociateWindow(this, net
->workspace
, True
);
3892 if (screen
->getCurrentWorkspaceID() != net
->workspace
) {
3896 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3900 if (net
->flags
& AttribDecoration
) {
3901 switch (net
->decoration
) {
3918 * Set the sizes of all components of the window frame
3919 * (the window decorations).
3920 * These values are based upon the current style settings and the client
3921 * window's dimensions.
3923 void BlackboxWindow::upsize(void) {
3924 frame
.bevel_w
= screen
->getBevelWidth();
3926 if (decorations
& Decor_Border
) {
3927 frame
.border_w
= screen
->getBorderWidth();
3928 if (! isTransient())
3929 frame
.mwm_border_w
= screen
->getFrameWidth();
3931 frame
.mwm_border_w
= 0;
3933 frame
.mwm_border_w
= frame
.border_w
= 0;
3936 if (decorations
& Decor_Titlebar
) {
3937 // the height of the titlebar is based upon the height of the font being
3938 // used to display the window's title
3939 WindowStyle
*style
= screen
->getWindowStyle();
3940 frame
.title_h
= style
->font
->height() + (frame
.bevel_w
* 2) + 2;
3942 frame
.label_h
= frame
.title_h
- (frame
.bevel_w
* 2);
3943 frame
.button_w
= (frame
.label_h
- 2);
3945 // set the top frame margin
3946 frame
.margin
.top
= frame
.border_w
+ frame
.title_h
+
3947 frame
.border_w
+ frame
.mwm_border_w
;
3953 // set the top frame margin
3954 frame
.margin
.top
= frame
.border_w
+ frame
.mwm_border_w
;
3957 // set the left/right frame margin
3958 frame
.margin
.left
= frame
.margin
.right
= frame
.border_w
+ frame
.mwm_border_w
;
3960 if (decorations
& Decor_Handle
) {
3961 frame
.grip_w
= frame
.button_w
* 2;
3962 frame
.handle_h
= screen
->getHandleWidth();
3964 // set the bottom frame margin
3965 frame
.margin
.bottom
= frame
.border_w
+ frame
.handle_h
+
3966 frame
.border_w
+ frame
.mwm_border_w
;
3971 // set the bottom frame margin
3972 frame
.margin
.bottom
= frame
.border_w
+ frame
.mwm_border_w
;
3976 We first get the normal dimensions and use this to define the inside_w/h
3977 then we modify the height if shading is in effect.
3978 If the shade state is not considered then frame.rect gets reset to the
3979 normal window size on a reconfigure() call resulting in improper
3980 dimensions appearing in move/resize and other events.
3983 height
= client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
,
3984 width
= client
.rect
.width() + frame
.margin
.left
+ frame
.margin
.right
;
3986 frame
.inside_w
= width
- (frame
.border_w
* 2);
3987 frame
.inside_h
= height
- (frame
.border_w
* 2);
3990 height
= frame
.title_h
+ (frame
.border_w
* 2);
3991 frame
.rect
.setSize(width
, height
);
3996 * Calculate the size of the client window and constrain it to the
3997 * size specified by the size hints of the client window.
3999 * The logical width and height are placed into pw and ph, if they
4000 * are non-zero. Logical size refers to the users perception of
4001 * the window size (for example an xterm resizes in cells, not in pixels).
4002 * pw and ph are then used to display the geometry during window moves, resize,
4005 * The physical geometry is placed into frame.changing_{x,y,width,height}.
4006 * Physical geometry refers to the geometry of the window in pixels.
4008 void BlackboxWindow::constrain(Corner anchor
,
4009 unsigned int *pw
, unsigned int *ph
) {
4010 // frame.changing represents the requested frame size, we need to
4011 // strip the frame margin off and constrain the client size
4012 frame
.changing
.setCoords(frame
.changing
.left() + frame
.margin
.left
,
4013 frame
.changing
.top() + frame
.margin
.top
,
4014 frame
.changing
.right() - frame
.margin
.right
,
4015 frame
.changing
.bottom() - frame
.margin
.bottom
);
4017 unsigned int dw
= frame
.changing
.width(), dh
= frame
.changing
.height(),
4018 base_width
= (client
.base_width
) ? client
.base_width
: client
.min_width
,
4019 base_height
= (client
.base_height
) ? client
.base_height
:
4023 if (dw
< client
.min_width
) dw
= client
.min_width
;
4024 if (dh
< client
.min_height
) dh
= client
.min_height
;
4025 if (dw
> client
.max_width
) dw
= client
.max_width
;
4026 if (dh
> client
.max_height
) dh
= client
.max_height
;
4028 assert(dw
>= base_width
&& dh
>= base_height
);
4030 if (client
.width_inc
> 1) {
4032 dw
/= client
.width_inc
;
4034 if (client
.height_inc
> 1) {
4036 dh
/= client
.height_inc
;
4045 if (client
.width_inc
> 1) {
4046 dw
*= client
.width_inc
;
4049 if (client
.height_inc
> 1) {
4050 dh
*= client
.height_inc
;
4054 frame
.changing
.setSize(dw
, dh
);
4056 // add the frame margin back onto frame.changing
4057 frame
.changing
.setCoords(frame
.changing
.left() - frame
.margin
.left
,
4058 frame
.changing
.top() - frame
.margin
.top
,
4059 frame
.changing
.right() + frame
.margin
.right
,
4060 frame
.changing
.bottom() + frame
.margin
.bottom
);
4062 // move frame.changing to the specified anchor
4070 dx
= frame
.rect
.right() - frame
.changing
.right();
4074 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
4078 dx
= frame
.rect
.right() - frame
.changing
.right();
4079 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
4083 assert(false); // unhandled corner
4085 frame
.changing
.setPos(frame
.changing
.x() + dx
, frame
.changing
.y() + dy
);
4089 void WindowStyle::doJustify(const std::string
&text
, int &start_pos
,
4090 unsigned int max_length
,
4091 unsigned int modifier
) const {
4092 size_t text_len
= text
.size();
4093 unsigned int length
;
4096 length
= font
->measureString(string(text
, 0, text_len
)) + modifier
;
4097 } while (length
> max_length
&& text_len
-- > 0);
4101 start_pos
+= max_length
- length
;
4105 start_pos
+= (max_length
- length
) / 2;
4115 BWindowGroup::BWindowGroup(Blackbox
*b
, Window _group
)
4116 : blackbox(b
), group(_group
) {
4117 XWindowAttributes wattrib
;
4118 if (! XGetWindowAttributes(blackbox
->getXDisplay(), group
, &wattrib
)) {
4119 // group window doesn't seem to exist anymore
4124 XSelectInput(blackbox
->getXDisplay(), group
,
4125 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
4127 blackbox
->saveGroupSearch(group
, this);
4131 BWindowGroup::~BWindowGroup(void) {
4132 blackbox
->removeGroupSearch(group
);
4137 BWindowGroup::find(BScreen
*screen
, bool allow_transients
) const {
4138 BlackboxWindow
*ret
= blackbox
->getFocusedWindow();
4140 // does the focus window match (or any transient_fors)?
4141 for (; ret
; ret
= ret
->getTransientFor()) {
4142 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
&&
4143 (! ret
->isTransient() || allow_transients
))
4147 if (ret
) return ret
;
4149 // the focus window didn't match, look in the group's window list
4150 BlackboxWindowList::const_iterator it
, end
= windowList
.end();
4151 for (it
= windowList
.begin(); it
!= end
; ++it
) {
4153 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
&&
4154 (! ret
->isTransient() || allow_transients
))