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
);
1636 void BlackboxWindow::clearShape(void) {
1637 XShapeCombineMask(blackbox
->getXDisplay(), frame
.window
, ShapeBounding
,
1638 frame
.margin
.left
- frame
.border_w
,
1639 frame
.margin
.top
- frame
.border_w
,
1645 bool BlackboxWindow::setInputFocus(void) {
1646 if (flags
.focused
) return True
;
1648 assert(flags
.stuck
|| // window must be on the current workspace or sticky
1649 blackbox_attrib
.workspace
== screen
->getCurrentWorkspaceID());
1652 We only do this check for normal windows and dialogs because other windows
1653 do this on purpose, such as kde's kicker, and we don't want to go moving
1656 if (window_type
== Type_Normal
|| window_type
== Type_Dialog
)
1657 if (! frame
.rect
.intersects(screen
->getRect())) {
1658 // client is outside the screen, move it to the center
1659 configure((screen
->getWidth() - frame
.rect
.width()) / 2,
1660 (screen
->getHeight() - frame
.rect
.height()) / 2,
1661 frame
.rect
.width(), frame
.rect
.height());
1664 if (client
.transientList
.size() > 0) {
1665 // transfer focus to any modal transients
1666 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1667 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1668 if ((*it
)->flags
.modal
) return (*it
)->setInputFocus();
1672 if (focus_mode
== F_LocallyActive
|| focus_mode
== F_Passive
) {
1673 XSetInputFocus(blackbox
->getXDisplay(), client
.window
,
1674 RevertToPointerRoot
, CurrentTime
);
1676 /* we could set the focus to none, since the window doesn't accept focus,
1677 * but we shouldn't set focus to nothing since this would surely make
1683 if (flags
.send_focus_message
) {
1685 ce
.xclient
.type
= ClientMessage
;
1686 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1687 ce
.xclient
.display
= blackbox
->getXDisplay();
1688 ce
.xclient
.window
= client
.window
;
1689 ce
.xclient
.format
= 32;
1690 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_take_focus
);
1691 ce
.xclient
.data
.l
[1] = blackbox
->getLastTime();
1692 ce
.xclient
.data
.l
[2] = 0l;
1693 ce
.xclient
.data
.l
[3] = 0l;
1694 ce
.xclient
.data
.l
[4] = 0l;
1695 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1697 XFlush(blackbox
->getXDisplay());
1704 void BlackboxWindow::iconify(void) {
1705 if (flags
.iconic
|| ! (functions
& Func_Iconify
)) return;
1707 // We don't need to worry about resizing because resizing always grabs the X
1708 // server. This should only ever happen if using opaque moving.
1712 if (windowmenu
) windowmenu
->hide();
1715 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1716 * we need to clear the event mask on client.window for a split second.
1717 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1718 * split second, leaving us with a ghost window... so, we need to do this
1719 * while the X server is grabbed
1721 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1722 StructureNotifyMask
;
1723 XGrabServer(blackbox
->getXDisplay());
1724 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1725 event_mask
& ~StructureNotifyMask
);
1726 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1727 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1728 XUngrabServer(blackbox
->getXDisplay());
1730 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1731 flags
.visible
= False
;
1732 flags
.iconic
= True
;
1734 setState(IconicState
);
1736 screen
->getWorkspace(blackbox_attrib
.workspace
)->removeWindow(this);
1738 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
1739 if (i
!= blackbox_attrib
.workspace
)
1740 screen
->getWorkspace(i
)->removeWindow(this, True
);
1743 if (isTransient()) {
1744 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1745 ! client
.transient_for
->flags
.iconic
) {
1746 // iconify our transient_for
1747 client
.transient_for
->iconify();
1751 screen
->addIcon(this);
1753 if (client
.transientList
.size() > 0) {
1754 // iconify all transients
1755 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1756 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1757 if (! (*it
)->flags
.iconic
) (*it
)->iconify();
1760 screen
->updateStackingList();
1764 void BlackboxWindow::show(void) {
1765 flags
.visible
= True
;
1766 flags
.iconic
= False
;
1768 current_state
= (flags
.shaded
) ? IconicState
: NormalState
;
1769 setState(current_state
);
1771 XMapWindow(blackbox
->getXDisplay(), client
.window
);
1772 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
1773 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
1778 XTranslateCoordinates(blackbox
->getXDisplay(), client
.window
,
1779 screen
->getRootWindow(),
1780 0, 0, &real_x
, &real_y
, &child
);
1781 fprintf(stderr
, "%s -- assumed: (%d, %d), real: (%d, %d)\n", getTitle(),
1782 client
.rect
.left(), client
.rect
.top(), real_x
, real_y
);
1783 assert(client
.rect
.left() == real_x
&& client
.rect
.top() == real_y
);
1788 void BlackboxWindow::deiconify(bool reassoc
, bool raise
) {
1789 if (flags
.iconic
|| reassoc
)
1790 screen
->reassociateWindow(this, BSENTINEL
, False
);
1791 else if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID())
1796 // reassociate and deiconify all transients
1797 if (reassoc
&& client
.transientList
.size() > 0) {
1798 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1799 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1800 (*it
)->deiconify(True
, False
);
1804 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1808 void BlackboxWindow::close(void) {
1809 if (! (functions
& Func_Close
)) return;
1812 ce
.xclient
.type
= ClientMessage
;
1813 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1814 ce
.xclient
.display
= blackbox
->getXDisplay();
1815 ce
.xclient
.window
= client
.window
;
1816 ce
.xclient
.format
= 32;
1817 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_delete_window
);
1818 ce
.xclient
.data
.l
[1] = CurrentTime
;
1819 ce
.xclient
.data
.l
[2] = 0l;
1820 ce
.xclient
.data
.l
[3] = 0l;
1821 ce
.xclient
.data
.l
[4] = 0l;
1822 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
, NoEventMask
, &ce
);
1823 XFlush(blackbox
->getXDisplay());
1827 void BlackboxWindow::withdraw(void) {
1828 // We don't need to worry about resizing because resizing always grabs the X
1829 // server. This should only ever happen if using opaque moving.
1833 flags
.visible
= False
;
1834 flags
.iconic
= False
;
1836 setState(current_state
);
1838 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1840 XGrabServer(blackbox
->getXDisplay());
1842 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1843 StructureNotifyMask
;
1844 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1845 event_mask
& ~StructureNotifyMask
);
1846 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1847 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1849 XUngrabServer(blackbox
->getXDisplay());
1851 if (windowmenu
) windowmenu
->hide();
1855 void BlackboxWindow::maximize(unsigned int button
) {
1856 if (! (functions
& Func_Maximize
)) return;
1858 // We don't need to worry about resizing because resizing always grabs the X
1859 // server. This should only ever happen if using opaque moving.
1863 // handle case where menu is open then the max button is used instead
1864 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
1866 if (flags
.maximized
) {
1867 flags
.maximized
= 0;
1869 blackbox_attrib
.flags
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1870 blackbox_attrib
.attrib
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1873 when a resize finishes, maximize(0) is called to clear any maximization
1874 flags currently set. Otherwise it still thinks it is maximized.
1875 so we do not need to call configure() because resizing will handle it
1877 if (! flags
.resizing
)
1878 configure(blackbox_attrib
.premax_x
, blackbox_attrib
.premax_y
,
1879 blackbox_attrib
.premax_w
, blackbox_attrib
.premax_h
);
1881 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
1882 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
1884 redrawAllButtons(); // in case it is not called in configure()
1885 setState(current_state
);
1889 blackbox_attrib
.premax_x
= frame
.rect
.x();
1890 blackbox_attrib
.premax_y
= frame
.rect
.y();
1891 blackbox_attrib
.premax_w
= frame
.rect
.width();
1892 // use client.rect so that clients can be restored even if shaded
1893 blackbox_attrib
.premax_h
=
1894 client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
;
1897 if (screen
->isXineramaActive() && blackbox
->doXineramaMaximizing()) {
1898 // find the area to use
1899 RectList availableAreas
= screen
->allAvailableAreas();
1900 RectList::iterator it
, end
= availableAreas
.end();
1902 for (it
= availableAreas
.begin(); it
!= end
; ++it
)
1903 if (it
->intersects(frame
.rect
)) break;
1904 if (it
== end
) // the window isn't inside an area
1905 it
= availableAreas
.begin(); // so just default to the first one
1907 frame
.changing
= *it
;
1910 frame
.changing
= screen
->availableArea();
1914 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1915 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1919 blackbox_attrib
.flags
|= AttribMaxVert
;
1920 blackbox_attrib
.attrib
|= AttribMaxVert
;
1922 frame
.changing
.setX(frame
.rect
.x());
1923 frame
.changing
.setWidth(frame
.rect
.width());
1927 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1928 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1930 frame
.changing
.setY(frame
.rect
.y());
1931 frame
.changing
.setHeight(frame
.rect
.height());
1938 blackbox_attrib
.flags
^= AttribShaded
;
1939 blackbox_attrib
.attrib
^= AttribShaded
;
1940 flags
.shaded
= False
;
1943 flags
.maximized
= button
;
1945 configure(frame
.changing
.x(), frame
.changing
.y(),
1946 frame
.changing
.width(), frame
.changing
.height());
1948 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1949 redrawAllButtons(); // in case it is not called in configure()
1950 setState(current_state
);
1954 // re-maximizes the window to take into account availableArea changes
1955 void BlackboxWindow::remaximize(void) {
1957 // we only update the window's attributes otherwise we lose the shade bit
1958 switch(flags
.maximized
) {
1960 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1961 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1965 blackbox_attrib
.flags
|= AttribMaxVert
;
1966 blackbox_attrib
.attrib
|= AttribMaxVert
;
1970 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1971 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1977 // save the original dimensions because maximize will wipe them out
1978 int premax_x
= blackbox_attrib
.premax_x
,
1979 premax_y
= blackbox_attrib
.premax_y
,
1980 premax_w
= blackbox_attrib
.premax_w
,
1981 premax_h
= blackbox_attrib
.premax_h
;
1983 unsigned int button
= flags
.maximized
;
1984 flags
.maximized
= 0; // trick maximize() into working
1987 // restore saved values
1988 blackbox_attrib
.premax_x
= premax_x
;
1989 blackbox_attrib
.premax_y
= premax_y
;
1990 blackbox_attrib
.premax_w
= premax_w
;
1991 blackbox_attrib
.premax_h
= premax_h
;
1995 void BlackboxWindow::setWorkspace(unsigned int n
) {
1996 blackbox_attrib
.flags
|= AttribWorkspace
;
1997 blackbox_attrib
.workspace
= n
;
1998 if (n
== BSENTINEL
) { // iconified window
2000 we set the workspace to 'all workspaces' so that taskbars will show the
2001 window. otherwise, it made uniconifying a window imposible without the
2002 blackbox workspace menu
2006 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
, n
);
2010 void BlackboxWindow::shade(void) {
2012 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
2013 frame
.inside_w
, frame
.inside_h
);
2014 flags
.shaded
= False
;
2015 blackbox_attrib
.flags
^= AttribShaded
;
2016 blackbox_attrib
.attrib
^= AttribShaded
;
2018 setState(NormalState
);
2020 // set the frame rect to the normal size
2021 frame
.rect
.setHeight(client
.rect
.height() + frame
.margin
.top
+
2022 frame
.margin
.bottom
);
2024 if (! (decorations
& Decor_Titlebar
))
2025 return; // can't shade it without a titlebar!
2027 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
2028 frame
.inside_w
, frame
.title_h
);
2029 flags
.shaded
= True
;
2030 blackbox_attrib
.flags
|= AttribShaded
;
2031 blackbox_attrib
.attrib
|= AttribShaded
;
2033 setState(IconicState
);
2035 // set the frame rect to the shaded size
2036 frame
.rect
.setHeight(frame
.title_h
+ (frame
.border_w
* 2));
2042 * (Un)Sticks a window and its relatives.
2044 void BlackboxWindow::stick(void) {
2046 blackbox_attrib
.flags
^= AttribOmnipresent
;
2047 blackbox_attrib
.attrib
^= AttribOmnipresent
;
2049 flags
.stuck
= False
;
2051 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
2052 if (i
!= blackbox_attrib
.workspace
)
2053 screen
->getWorkspace(i
)->removeWindow(this, True
);
2056 screen
->reassociateWindow(this, BSENTINEL
, True
);
2057 // temporary fix since sticky windows suck. set the hint to what we
2058 // actually hold in our data.
2059 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
2060 blackbox_attrib
.workspace
);
2062 setState(current_state
);
2066 blackbox_attrib
.flags
|= AttribOmnipresent
;
2067 blackbox_attrib
.attrib
|= AttribOmnipresent
;
2069 // temporary fix since sticky windows suck. set the hint to a different
2070 // value than that contained in the class' data.
2071 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
2074 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
2075 if (i
!= blackbox_attrib
.workspace
)
2076 screen
->getWorkspace(i
)->addWindow(this, False
, True
);
2078 setState(current_state
);
2081 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
2082 client
.transient_for
->isStuck() != flags
.stuck
)
2083 client
.transient_for
->stick();
2084 // go down the chain
2085 BlackboxWindowList::iterator it
;
2086 const BlackboxWindowList::iterator end
= client
.transientList
.end();
2087 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
2088 if ((*it
)->isStuck() != flags
.stuck
)
2093 void BlackboxWindow::redrawWindowFrame(void) const {
2094 if (decorations
& Decor_Titlebar
) {
2095 if (flags
.focused
) {
2097 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2098 frame
.title
, frame
.ftitle
);
2100 XSetWindowBackground(blackbox
->getXDisplay(),
2101 frame
.title
, frame
.ftitle_pixel
);
2104 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2105 frame
.title
, frame
.utitle
);
2107 XSetWindowBackground(blackbox
->getXDisplay(),
2108 frame
.title
, frame
.utitle_pixel
);
2110 XClearWindow(blackbox
->getXDisplay(), frame
.title
);
2116 if (decorations
& Decor_Handle
) {
2117 if (flags
.focused
) {
2119 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2120 frame
.handle
, frame
.fhandle
);
2122 XSetWindowBackground(blackbox
->getXDisplay(),
2123 frame
.handle
, frame
.fhandle_pixel
);
2126 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2127 frame
.left_grip
, frame
.fgrip
);
2128 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2129 frame
.right_grip
, frame
.fgrip
);
2131 XSetWindowBackground(blackbox
->getXDisplay(),
2132 frame
.left_grip
, frame
.fgrip_pixel
);
2133 XSetWindowBackground(blackbox
->getXDisplay(),
2134 frame
.right_grip
, frame
.fgrip_pixel
);
2138 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2139 frame
.handle
, frame
.uhandle
);
2141 XSetWindowBackground(blackbox
->getXDisplay(),
2142 frame
.handle
, frame
.uhandle_pixel
);
2145 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2146 frame
.left_grip
, frame
.ugrip
);
2147 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2148 frame
.right_grip
, frame
.ugrip
);
2150 XSetWindowBackground(blackbox
->getXDisplay(),
2151 frame
.left_grip
, frame
.ugrip_pixel
);
2152 XSetWindowBackground(blackbox
->getXDisplay(),
2153 frame
.right_grip
, frame
.ugrip_pixel
);
2156 XClearWindow(blackbox
->getXDisplay(), frame
.handle
);
2157 XClearWindow(blackbox
->getXDisplay(), frame
.left_grip
);
2158 XClearWindow(blackbox
->getXDisplay(), frame
.right_grip
);
2161 if (decorations
& Decor_Border
) {
2163 XSetWindowBorder(blackbox
->getXDisplay(),
2164 frame
.plate
, frame
.fborder_pixel
);
2166 XSetWindowBorder(blackbox
->getXDisplay(),
2167 frame
.plate
, frame
.uborder_pixel
);
2172 void BlackboxWindow::setFocusFlag(bool focus
) {
2173 // only focus a window if it is visible
2174 if (focus
&& ! flags
.visible
)
2177 flags
.focused
= focus
;
2179 redrawWindowFrame();
2182 blackbox
->setFocusedWindow(this);
2184 if (! flags
.iconic
) {
2185 // iconic windows arent in a workspace menu!
2187 screen
->getCurrentWorkspace()->setFocused(this, isFocused());
2189 screen
->getWorkspace(blackbox_attrib
.workspace
)->
2190 setFocused(this, flags
.focused
);
2195 void BlackboxWindow::installColormap(bool install
) {
2196 int i
= 0, ncmap
= 0;
2197 Colormap
*cmaps
= XListInstalledColormaps(blackbox
->getXDisplay(),
2198 client
.window
, &ncmap
);
2200 XWindowAttributes wattrib
;
2201 if (XGetWindowAttributes(blackbox
->getXDisplay(),
2202 client
.window
, &wattrib
)) {
2204 // install the window's colormap
2205 for (i
= 0; i
< ncmap
; i
++) {
2206 if (*(cmaps
+ i
) == wattrib
.colormap
)
2207 // this window is using an installed color map... do not install
2210 // otherwise, install the window's colormap
2212 XInstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2214 // uninstall the window's colormap
2215 for (i
= 0; i
< ncmap
; i
++) {
2216 if (*(cmaps
+ i
) == wattrib
.colormap
)
2217 // we found the colormap to uninstall
2218 XUninstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2228 void BlackboxWindow::setAllowedActions(void) {
2232 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_shade
);
2233 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_change_desktop
);
2234 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_close
);
2236 if (functions
& Func_Move
)
2237 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_move
);
2238 if (functions
& Func_Resize
)
2239 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_resize
);
2240 if (functions
& Func_Maximize
) {
2241 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_horz
);
2242 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_vert
);
2245 xatom
->setValue(client
.window
, XAtom::net_wm_allowed_actions
, XAtom::atom
,
2250 void BlackboxWindow::setState(unsigned long new_state
) {
2251 current_state
= new_state
;
2253 unsigned long state
[2];
2254 state
[0] = current_state
;
2256 xatom
->setValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
, state
, 2);
2258 xatom
->setValue(client
.window
, XAtom::blackbox_attributes
,
2259 XAtom::blackbox_attributes
, (unsigned long *)&blackbox_attrib
,
2260 PropBlackboxAttributesElements
);
2265 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_modal
);
2267 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_shaded
);
2269 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_hidden
);
2270 if (flags
.skip_taskbar
)
2271 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
);
2272 if (flags
.skip_pager
)
2273 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_pager
);
2274 if (flags
.fullscreen
)
2275 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_fullscreen
);
2276 if (flags
.maximized
== 1 || flags
.maximized
== 2)
2277 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_vert
);
2278 if (flags
.maximized
== 1 || flags
.maximized
== 3)
2279 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_horz
);
2280 xatom
->setValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
2285 bool BlackboxWindow::getState(void) {
2286 bool ret
= xatom
->getValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
,
2288 if (! ret
) current_state
= 0;
2293 void BlackboxWindow::restoreAttributes(void) {
2294 unsigned long num
= PropBlackboxAttributesElements
;
2295 BlackboxAttributes
*net
;
2296 if (! xatom
->getValue(client
.window
, XAtom::blackbox_attributes
,
2297 XAtom::blackbox_attributes
, num
,
2298 (unsigned long **)&net
))
2300 if (num
< PropBlackboxAttributesElements
) {
2305 if (net
->flags
& AttribShaded
&& net
->attrib
& AttribShaded
) {
2306 flags
.shaded
= False
;
2307 unsigned long orig_state
= current_state
;
2311 At this point in the life of a window, current_state should only be set
2312 to IconicState if the window was an *icon*, not if it was shaded.
2314 if (orig_state
!= IconicState
)
2315 current_state
= WithdrawnState
;
2318 if (net
->workspace
!= screen
->getCurrentWorkspaceID() &&
2319 net
->workspace
< screen
->getWorkspaceCount())
2320 screen
->reassociateWindow(this, net
->workspace
, True
);
2322 if ((blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID()) &&
2323 (blackbox_attrib
.workspace
< screen
->getWorkspaceCount())) {
2324 // set to WithdrawnState so it will be mapped on the new workspace
2325 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2326 } else if (current_state
== WithdrawnState
) {
2327 // the window is on this workspace and is Withdrawn, so it is waiting to
2329 current_state
= NormalState
;
2332 if (net
->flags
& AttribOmnipresent
&& net
->attrib
& AttribOmnipresent
&&
2336 // if the window was on another workspace, it was going to be hidden. this
2337 // specifies that the window should be mapped since it is sticky.
2338 if (current_state
== WithdrawnState
) current_state
= NormalState
;
2341 if (net
->flags
& AttribMaxHoriz
|| net
->flags
& AttribMaxVert
) {
2342 int x
= net
->premax_x
, y
= net
->premax_y
;
2343 unsigned int w
= net
->premax_w
, h
= net
->premax_h
;
2344 flags
.maximized
= 0;
2347 if ((net
->flags
& AttribMaxHoriz
) &&
2348 (net
->flags
& AttribMaxVert
))
2349 m
= (net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
2350 else if (net
->flags
& AttribMaxVert
)
2351 m
= (net
->attrib
& AttribMaxVert
) ? 2 : 0;
2352 else if (net
->flags
& AttribMaxHoriz
)
2353 m
= (net
->attrib
& AttribMaxHoriz
) ? 3 : 0;
2357 blackbox_attrib
.premax_x
= x
;
2358 blackbox_attrib
.premax_y
= y
;
2359 blackbox_attrib
.premax_w
= w
;
2360 blackbox_attrib
.premax_h
= h
;
2363 if (net
->flags
& AttribDecoration
) {
2364 switch (net
->decoration
) {
2369 /* since tools only let you toggle this anyways, we'll just make that all
2370 it supports for now.
2381 // with the state set it will then be the map event's job to read the
2382 // window's state and behave accordingly
2389 * Positions the Rect r according the the client window position and
2392 void BlackboxWindow::applyGravity(Rect
&r
) {
2393 // apply horizontal window gravity
2394 switch (client
.win_gravity
) {
2396 case NorthWestGravity
:
2397 case SouthWestGravity
:
2399 r
.setX(client
.rect
.x());
2405 r
.setX(client
.rect
.x() - (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2408 case NorthEastGravity
:
2409 case SouthEastGravity
:
2411 r
.setX(client
.rect
.x() - frame
.margin
.left
- frame
.margin
.right
+ 2);
2416 r
.setX(client
.rect
.x() - frame
.margin
.left
);
2420 // apply vertical window gravity
2421 switch (client
.win_gravity
) {
2423 case NorthWestGravity
:
2424 case NorthEastGravity
:
2426 r
.setY(client
.rect
.y());
2432 r
.setY(client
.rect
.y() - (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2435 case SouthWestGravity
:
2436 case SouthEastGravity
:
2438 r
.setY(client
.rect
.y() - frame
.margin
.top
- frame
.margin
.bottom
+ 2);
2443 r
.setY(client
.rect
.y() - frame
.margin
.top
);
2450 * The reverse of the applyGravity function.
2452 * Positions the Rect r according to the frame window position and
2455 void BlackboxWindow::restoreGravity(Rect
&r
) {
2456 // restore horizontal window gravity
2457 switch (client
.win_gravity
) {
2459 case NorthWestGravity
:
2460 case SouthWestGravity
:
2462 r
.setX(frame
.rect
.x());
2468 r
.setX(frame
.rect
.x() + (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2471 case NorthEastGravity
:
2472 case SouthEastGravity
:
2474 r
.setX(frame
.rect
.x() + frame
.margin
.left
+ frame
.margin
.right
- 2);
2479 r
.setX(frame
.rect
.x() + frame
.margin
.left
);
2483 // restore vertical window gravity
2484 switch (client
.win_gravity
) {
2486 case NorthWestGravity
:
2487 case NorthEastGravity
:
2489 r
.setY(frame
.rect
.y());
2495 r
.setY(frame
.rect
.y() + (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2498 case SouthWestGravity
:
2499 case SouthEastGravity
:
2501 r
.setY(frame
.rect
.y() + frame
.margin
.top
+ frame
.margin
.bottom
- 2);
2506 r
.setY(frame
.rect
.y() + frame
.margin
.top
);
2512 void BlackboxWindow::redrawLabel(void) const {
2513 if (flags
.focused
) {
2515 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2516 frame
.label
, frame
.flabel
);
2518 XSetWindowBackground(blackbox
->getXDisplay(),
2519 frame
.label
, frame
.flabel_pixel
);
2522 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2523 frame
.label
, frame
.ulabel
);
2525 XSetWindowBackground(blackbox
->getXDisplay(),
2526 frame
.label
, frame
.ulabel_pixel
);
2528 XClearWindow(blackbox
->getXDisplay(), frame
.label
);
2530 WindowStyle
*style
= screen
->getWindowStyle();
2532 int pos
= frame
.bevel_w
* 2;
2533 style
->doJustify(client
.title
.c_str(), pos
, frame
.label_w
, frame
.bevel_w
* 4);
2534 style
->font
->drawString(frame
.label
, pos
, 1,
2535 (flags
.focused
? style
->l_text_focus
:
2536 style
->l_text_unfocus
),
2541 void BlackboxWindow::redrawAllButtons(void) const {
2542 if (frame
.iconify_button
) redrawIconifyButton(False
);
2543 if (frame
.maximize_button
) redrawMaximizeButton(flags
.maximized
);
2544 if (frame
.close_button
) redrawCloseButton(False
);
2548 void BlackboxWindow::redrawIconifyButton(bool pressed
) const {
2550 if (flags
.focused
) {
2552 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2553 frame
.iconify_button
, frame
.fbutton
);
2555 XSetWindowBackground(blackbox
->getXDisplay(),
2556 frame
.iconify_button
, frame
.fbutton_pixel
);
2559 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2560 frame
.iconify_button
, frame
.ubutton
);
2562 XSetWindowBackground(blackbox
->getXDisplay(), frame
.iconify_button
,
2563 frame
.ubutton_pixel
);
2567 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2568 frame
.iconify_button
, frame
.pbutton
);
2570 XSetWindowBackground(blackbox
->getXDisplay(),
2571 frame
.iconify_button
, frame
.pbutton_pixel
);
2573 XClearWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
2575 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2576 screen
->getWindowStyle()->b_pic_unfocus
);
2577 XDrawRectangle(blackbox
->getXDisplay(), frame
.iconify_button
, pen
.gc(),
2578 2, (frame
.button_w
- 5), (frame
.button_w
- 5), 2);
2582 void BlackboxWindow::redrawMaximizeButton(bool pressed
) const {
2584 if (flags
.focused
) {
2586 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2587 frame
.maximize_button
, frame
.fbutton
);
2589 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2590 frame
.fbutton_pixel
);
2593 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2594 frame
.maximize_button
, frame
.ubutton
);
2596 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2597 frame
.ubutton_pixel
);
2601 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2602 frame
.maximize_button
, frame
.pbutton
);
2604 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2605 frame
.pbutton_pixel
);
2607 XClearWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
2609 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2610 screen
->getWindowStyle()->b_pic_unfocus
);
2611 XDrawRectangle(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2612 2, 2, (frame
.button_w
- 5), (frame
.button_w
- 5));
2613 XDrawLine(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2614 2, 3, (frame
.button_w
- 3), 3);
2618 void BlackboxWindow::redrawCloseButton(bool pressed
) const {
2620 if (flags
.focused
) {
2622 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2625 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2626 frame
.fbutton_pixel
);
2629 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2632 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2633 frame
.ubutton_pixel
);
2637 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2638 frame
.close_button
, frame
.pbutton
);
2640 XSetWindowBackground(blackbox
->getXDisplay(),
2641 frame
.close_button
, frame
.pbutton_pixel
);
2643 XClearWindow(blackbox
->getXDisplay(), frame
.close_button
);
2645 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2646 screen
->getWindowStyle()->b_pic_unfocus
, 0, 2);
2647 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2648 2, 2, (frame
.button_w
- 3), (frame
.button_w
- 3));
2649 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2650 2, (frame
.button_w
- 3), (frame
.button_w
- 3), 2);
2654 void BlackboxWindow::mapRequestEvent(const XMapRequestEvent
*re
) {
2655 if (re
->window
!= client
.window
)
2659 fprintf(stderr
, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2664 Even though the window wants to be shown, if it is not on the current
2665 workspace, then it isn't going to be shown right now.
2667 if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID() &&
2668 blackbox_attrib
.workspace
< screen
->getWorkspaceCount())
2669 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2671 switch (current_state
) {
2676 case WithdrawnState
:
2685 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2687 if (! blackbox
->isStartup()) {
2688 XSync(blackbox
->getXDisplay(), False
); // make sure the frame is mapped
2689 if (screen
->doFocusNew() || (isTransient() && getTransientFor() &&
2690 getTransientFor()->isFocused())) {
2693 if (screen
->getPlacementPolicy() == BScreen::ClickMousePlacement
) {
2697 XQueryPointer(blackbox
->getXDisplay(), screen
->getRootWindow(),
2698 &r
, &c
, &rx
, &ry
, &x
, &y
, &m
);
2708 void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent
*ue
) {
2709 if (ue
->window
!= client
.window
)
2713 fprintf(stderr
, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2717 screen
->unmanageWindow(this, False
);
2721 void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent
*de
) {
2722 if (de
->window
!= client
.window
)
2726 fprintf(stderr
, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2730 screen
->unmanageWindow(this, False
);
2734 void BlackboxWindow::reparentNotifyEvent(const XReparentEvent
*re
) {
2735 if (re
->window
!= client
.window
|| re
->parent
== frame
.plate
)
2739 fprintf(stderr
, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2740 "0x%lx.\n", client
.window
, re
->parent
);
2745 XPutBackEvent(blackbox
->getXDisplay(), &ev
);
2746 screen
->unmanageWindow(this, True
);
2750 void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent
*pe
) {
2751 if (pe
->state
== PropertyDelete
|| ! validateClient())
2755 fprintf(stderr
, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n",
2761 case XA_WM_CLIENT_MACHINE
:
2765 case XA_WM_TRANSIENT_FOR
: {
2766 bool s
= flags
.stuck
;
2768 // determine if this is a transient window
2771 if (flags
.stuck
!= s
) stick();
2773 // adjust the window decorations based on transience
2774 if (isTransient()) {
2775 functions
&= ~Func_Maximize
;
2776 setAllowedActions();
2788 case XA_WM_ICON_NAME
:
2790 if (flags
.iconic
) screen
->propagateWindowName(this);
2793 case XAtom::net_wm_name
:
2797 if (decorations
& Decor_Titlebar
)
2800 screen
->propagateWindowName(this);
2803 case XA_WM_NORMAL_HINTS
: {
2806 if ((client
.normal_hint_flags
& PMinSize
) &&
2807 (client
.normal_hint_flags
& PMaxSize
)) {
2808 // the window now can/can't resize itself, so the buttons need to be
2811 if (client
.max_width
<= client
.min_width
&&
2812 client
.max_height
<= client
.min_height
) {
2813 functions
&= ~(Func_Resize
| Func_Maximize
);
2815 if (! isTransient())
2816 functions
|= Func_Maximize
;
2817 functions
|= Func_Resize
;
2820 setAllowedActions();
2824 Rect old_rect
= frame
.rect
;
2828 if (old_rect
!= frame
.rect
)
2835 if (pe
->atom
== xatom
->getAtom(XAtom::wm_protocols
)) {
2838 if ((decorations
& Decor_Close
) && (! frame
.close_button
)) {
2839 createCloseButton();
2840 if (decorations
& Decor_Titlebar
) {
2841 positionButtons(True
);
2842 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
2844 if (windowmenu
) windowmenu
->reconfigure();
2846 } else if (pe
->atom
== xatom
->getAtom(XAtom::net_wm_strut
)) {
2855 void BlackboxWindow::exposeEvent(const XExposeEvent
*ee
) {
2857 fprintf(stderr
, "BlackboxWindow::exposeEvent() for 0x%lx\n", client
.window
);
2860 if (frame
.label
== ee
->window
&& (decorations
& Decor_Titlebar
))
2862 else if (frame
.close_button
== ee
->window
)
2863 redrawCloseButton(False
);
2864 else if (frame
.maximize_button
== ee
->window
)
2865 redrawMaximizeButton(flags
.maximized
);
2866 else if (frame
.iconify_button
== ee
->window
)
2867 redrawIconifyButton(False
);
2871 void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent
*cr
) {
2872 if (cr
->window
!= client
.window
|| flags
.iconic
)
2875 if (cr
->value_mask
& CWBorderWidth
)
2876 client
.old_bw
= cr
->border_width
;
2878 if (cr
->value_mask
& (CWX
| CWY
| CWWidth
| CWHeight
)) {
2879 frame
.changing
= frame
.rect
;
2881 if (cr
->value_mask
& (CWX
| CWY
)) {
2882 if (cr
->value_mask
& CWX
)
2883 client
.rect
.setX(cr
->x
);
2884 if (cr
->value_mask
& CWY
)
2885 client
.rect
.setY(cr
->y
);
2887 applyGravity(frame
.changing
);
2890 if (cr
->value_mask
& (CWWidth
| CWHeight
)) {
2891 if (cr
->value_mask
& CWWidth
)
2892 frame
.changing
.setWidth(cr
->width
+
2893 frame
.margin
.left
+ frame
.margin
.right
);
2895 if (cr
->value_mask
& CWHeight
)
2896 frame
.changing
.setHeight(cr
->height
+
2897 frame
.margin
.top
+ frame
.margin
.bottom
);
2900 if a position change ha been specified, then that position will be used
2901 instead of determining a position based on the window's gravity.
2903 if (cr
->value_mask
& (CWX
| CWY
)) {
2905 switch (client
.win_gravity
) {
2906 case NorthEastGravity
:
2910 case SouthWestGravity
:
2912 corner
= BottomLeft
;
2914 case SouthEastGravity
:
2915 corner
= BottomRight
;
2917 default: // NorthWest, Static, etc
2924 configure(frame
.changing
.x(), frame
.changing
.y(),
2925 frame
.changing
.width(), frame
.changing
.height());
2928 if (cr
->value_mask
& CWStackMode
&& !isDesktop()) {
2929 switch (cr
->detail
) {
2932 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2938 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2945 void BlackboxWindow::buttonPressEvent(const XButtonEvent
*be
) {
2947 fprintf(stderr
, "BlackboxWindow::buttonPressEvent() for 0x%lx\n",
2951 if (frame
.maximize_button
== be
->window
&& be
->button
<= 3) {
2952 redrawMaximizeButton(True
);
2953 } else if (be
->button
== 1 || (be
->button
== 3 && be
->state
== mod_mask
)) {
2954 if (! flags
.focused
)
2957 if (frame
.iconify_button
== be
->window
) {
2958 redrawIconifyButton(True
);
2959 } else if (frame
.close_button
== be
->window
) {
2960 redrawCloseButton(True
);
2961 } else if (frame
.plate
== be
->window
) {
2962 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2964 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2966 XAllowEvents(blackbox
->getXDisplay(), ReplayPointer
, be
->time
);
2968 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
2969 if (((be
->time
- lastButtonPressTime
) <=
2970 blackbox
->getDoubleClickInterval()) ||
2971 (be
->state
== ControlMask
)) {
2972 lastButtonPressTime
= 0;
2975 lastButtonPressTime
= be
->time
;
2979 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2981 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2983 } else if (be
->button
== 2 && (be
->window
!= frame
.iconify_button
) &&
2984 (be
->window
!= frame
.close_button
)) {
2985 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2986 } else if (windowmenu
&& be
->button
== 3 &&
2987 (frame
.title
== be
->window
|| frame
.label
== be
->window
||
2988 frame
.handle
== be
->window
|| frame
.window
== be
->window
)) {
2989 if (windowmenu
->isVisible()) {
2992 int mx
= be
->x_root
- windowmenu
->getWidth() / 2,
2993 my
= be
->y_root
- windowmenu
->getHeight() / 2;
2995 // snap the window menu into a corner/side if necessary
2996 int left_edge
, right_edge
, top_edge
, bottom_edge
;
2999 the " + (frame.border_w * 2) - 1" bits are to get the proper width
3000 and height of the menu, as the sizes returned by it do not include
3003 left_edge
= frame
.rect
.x();
3004 right_edge
= frame
.rect
.right() -
3005 (windowmenu
->getWidth() + (frame
.border_w
* 2) - 1);
3006 top_edge
= client
.rect
.top() - (frame
.border_w
+ frame
.mwm_border_w
);
3007 bottom_edge
= client
.rect
.bottom() -
3008 (windowmenu
->getHeight() + (frame
.border_w
* 2) - 1) +
3009 (frame
.border_w
+ frame
.mwm_border_w
);
3013 if (mx
> right_edge
)
3017 if (my
> bottom_edge
)
3020 windowmenu
->move(mx
, my
);
3022 XRaiseWindow(blackbox
->getXDisplay(), windowmenu
->getWindowID());
3023 XRaiseWindow(blackbox
->getXDisplay(),
3024 windowmenu
->getSendToMenu()->getWindowID());
3027 } else if (be
->button
== 4) {
3028 if ((be
->window
== frame
.label
||
3029 be
->window
== frame
.title
||
3030 be
->window
== frame
.maximize_button
||
3031 be
->window
== frame
.iconify_button
||
3032 be
->window
== frame
.close_button
) &&
3036 } else if (be
->button
== 5) {
3037 if ((be
->window
== frame
.label
||
3038 be
->window
== frame
.title
||
3039 be
->window
== frame
.maximize_button
||
3040 be
->window
== frame
.iconify_button
||
3041 be
->window
== frame
.close_button
) &&
3048 void BlackboxWindow::buttonReleaseEvent(const XButtonEvent
*re
) {
3050 fprintf(stderr
, "BlackboxWindow::buttonReleaseEvent() for 0x%lx\n",
3054 if (re
->window
== frame
.maximize_button
&&
3055 re
->button
>= 1 && re
->button
<= 3) {
3056 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3057 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
3058 maximize(re
->button
);
3060 redrawMaximizeButton(flags
.maximized
);
3062 } else if (re
->window
== frame
.iconify_button
&& re
->button
== 1) {
3063 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3064 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
3067 redrawIconifyButton(False
);
3069 } else if (re
->window
== frame
.close_button
& re
->button
== 1) {
3070 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3071 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
)))
3073 redrawCloseButton(False
);
3074 } else if (flags
.moving
) {
3076 } else if (flags
.resizing
) {
3078 } else if (re
->window
== frame
.window
) {
3079 if (re
->button
== 2 && re
->state
== mod_mask
)
3080 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3086 void BlackboxWindow::beginMove(int x_root
, int y_root
) {
3087 if (! (functions
& Func_Move
)) return;
3089 assert(! (flags
.resizing
|| flags
.moving
));
3092 Only one window can be moved/resized at a time. If another window is already
3093 being moved or resized, then stop it before whating to work with this one.
3095 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3096 if (changing
&& changing
!= this) {
3097 if (changing
->flags
.moving
)
3098 changing
->endMove();
3099 else // if (changing->flags.resizing)
3100 changing
->endResize();
3103 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3104 PointerMotionMask
| ButtonReleaseMask
,
3105 GrabModeAsync
, GrabModeAsync
,
3106 None
, blackbox
->getMoveCursor(), CurrentTime
);
3108 if (windowmenu
&& windowmenu
->isVisible())
3111 flags
.moving
= True
;
3112 blackbox
->setChangingWindow(this);
3114 if (! screen
->doOpaqueMove()) {
3115 XGrabServer(blackbox
->getXDisplay());
3117 frame
.changing
= frame
.rect
;
3118 screen
->showPosition(frame
.changing
.x(), frame
.changing
.y());
3120 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3124 frame
.changing
.width() - 1,
3125 frame
.changing
.height() - 1);
3128 frame
.grab_x
= x_root
- frame
.rect
.x() - frame
.border_w
;
3129 frame
.grab_y
= y_root
- frame
.rect
.y() - frame
.border_w
;
3133 void BlackboxWindow::doMove(int x_root
, int y_root
) {
3134 assert(flags
.moving
);
3135 assert(blackbox
->getChangingWindow() == this);
3137 int dx
= x_root
- frame
.grab_x
, dy
= y_root
- frame
.grab_y
;
3138 dx
-= frame
.border_w
;
3139 dy
-= frame
.border_w
;
3141 doWindowSnapping(dx
, dy
);
3143 if (screen
->doOpaqueMove()) {
3144 if (screen
->doWorkspaceWarping())
3145 doWorkspaceWarping(x_root
, y_root
, dx
);
3147 configure(dx
, dy
, frame
.rect
.width(), frame
.rect
.height());
3149 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3153 frame
.changing
.width() - 1,
3154 frame
.changing
.height() - 1);
3156 if (screen
->doWorkspaceWarping())
3157 doWorkspaceWarping(x_root
, y_root
, dx
);
3159 frame
.changing
.setPos(dx
, dy
);
3161 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3165 frame
.changing
.width() - 1,
3166 frame
.changing
.height() - 1);
3169 screen
->showPosition(dx
, dy
);
3173 void BlackboxWindow::doWorkspaceWarping(int x_root
, int y_root
, int &dx
) {
3174 // workspace warping
3176 unsigned int dest
= screen
->getCurrentWorkspaceID();
3180 if (dest
> 0) dest
--;
3181 else dest
= screen
->getNumberOfWorkspaces() - 1;
3183 } else if (x_root
>= screen
->getRect().right()) {
3186 if (dest
< screen
->getNumberOfWorkspaces() - 1) dest
++;
3192 bool focus
= flags
.focused
; // had focus while moving?
3194 int dest_x
= x_root
;
3196 dest_x
+= screen
->getRect().width() - 1;
3197 dx
+= screen
->getRect().width() - 1;
3199 dest_x
-= screen
->getRect().width() - 1;
3200 dx
-= screen
->getRect().width() - 1;
3204 screen
->reassociateWindow(this, dest
, False
);
3205 screen
->changeWorkspaceID(dest
);
3207 if (screen
->doOpaqueMove())
3208 XGrabServer(blackbox
->getXDisplay());
3210 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3211 XWarpPointer(blackbox
->getXDisplay(), None
,
3212 screen
->getRootWindow(), 0, 0, 0, 0,
3214 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3215 PointerMotionMask
| ButtonReleaseMask
,
3216 GrabModeAsync
, GrabModeAsync
,
3217 None
, blackbox
->getMoveCursor(), CurrentTime
);
3219 if (screen
->doOpaqueMove())
3220 XUngrabServer(blackbox
->getXDisplay());
3228 void BlackboxWindow::doWindowSnapping(int &dx
, int &dy
) {
3229 // how much resistance to edges to provide
3230 const int resistance_size
= screen
->getResistanceSize();
3232 // how far away to snap
3233 const int snap_distance
= screen
->getSnapThreshold();
3235 // how to snap windows
3236 const int snap_to_windows
= screen
->getWindowToWindowSnap();
3237 const int snap_to_edges
= screen
->getWindowToEdgeSnap();
3238 // the amount of space away from the edge to provide resistance/snap
3239 const int snap_offset
= screen
->getSnapOffset();
3241 // find the geomeetery where the moving window currently is
3242 const Rect
&moving
= screen
->doOpaqueMove() ? frame
.rect
: frame
.changing
;
3245 const int wleft
= dx
,
3246 wright
= dx
+ frame
.rect
.width() - 1,
3248 wbottom
= dy
+ frame
.rect
.height() - 1;
3250 if (snap_to_windows
) {
3253 Workspace
*w
= screen
->getWorkspace(getWorkspaceNumber());
3256 // add windows on the workspace to the rect list
3257 const BlackboxWindowList
& stack_list
= w
->getStackingList();
3258 BlackboxWindowList::const_iterator st_it
, st_end
= stack_list
.end();
3259 for (st_it
= stack_list
.begin(); st_it
!= st_end
; ++st_it
)
3260 if (*st_it
!= this) // don't snap to ourself
3261 rectlist
.push_back( (*st_it
)->frameRect() );
3263 // add the toolbar and the slit to the rect list.
3264 // (only if they are not hidden)
3265 Toolbar
*tbar
= screen
->getToolbar();
3266 Slit
*slit
= screen
->getSlit();
3267 Rect tbar_rect
, slit_rect
;
3268 unsigned int bwidth
= screen
->getBorderWidth() * 2;
3270 if (! (screen
->doHideToolbar() || tbar
->isHidden())) {
3271 tbar_rect
.setRect(tbar
->getX(), tbar
->getY(), tbar
->getWidth() + bwidth
,
3272 tbar
->getHeight() + bwidth
);
3273 rectlist
.push_back(tbar_rect
);
3276 if (! slit
->isHidden()) {
3277 slit_rect
.setRect(slit
->getX(), slit
->getY(), slit
->getWidth() + bwidth
,
3278 slit
->getHeight() + bwidth
);
3279 rectlist
.push_back(slit_rect
);
3282 RectList::const_iterator it
, end
= rectlist
.end();
3283 for (it
= rectlist
.begin(); it
!= end
; ++it
) {
3284 bool snapped
= False
;
3285 const Rect
&winrect
= *it
;
3287 offsetrect
.setCoords(winrect
.left() - snap_offset
,
3288 winrect
.top() - snap_offset
,
3289 winrect
.right() + snap_offset
,
3290 winrect
.bottom() + snap_offset
);
3292 if (snap_to_windows
== BScreen::WindowResistance
)
3293 // if the window is already over top of this snap target, then
3294 // resistance is futile, so just ignore it
3295 if (winrect
.intersects(moving
))
3298 int dleft
, dright
, dtop
, dbottom
;
3300 // if the windows are in the same plane vertically
3301 if (wtop
>= (signed)(winrect
.y() - frame
.rect
.height() + 1) &&
3302 wtop
< (signed)(winrect
.y() + winrect
.height() - 1)) {
3304 if (snap_to_windows
== BScreen::WindowResistance
) {
3305 dleft
= wright
- offsetrect
.left();
3306 dright
= offsetrect
.right() - wleft
;
3308 // snap left of other window?
3309 if (dleft
>= 0 && dleft
< resistance_size
&&
3310 dleft
< (wright
- wleft
)) {
3311 dx
= offsetrect
.left() - frame
.rect
.width();
3314 // snap right of other window?
3315 else if (dright
>= 0 && dright
< resistance_size
&&
3316 dright
< (wright
- wleft
)) {
3317 dx
= offsetrect
.right() + 1;
3320 } else { // BScreen::WindowSnap
3321 dleft
= abs(wright
- offsetrect
.left());
3322 dright
= abs(wleft
- offsetrect
.right());
3324 // snap left of other window?
3325 if (dleft
< snap_distance
&& dleft
<= dright
) {
3326 dx
= offsetrect
.left() - frame
.rect
.width();
3329 // snap right of other window?
3330 else if (dright
< snap_distance
) {
3331 dx
= offsetrect
.right() + 1;
3337 if (screen
->getWindowCornerSnap()) {
3338 // try corner-snap to its other sides
3339 if (snap_to_windows
== BScreen::WindowResistance
) {
3340 dtop
= winrect
.top() - wtop
;
3341 dbottom
= wbottom
- winrect
.bottom();
3342 if (dtop
> 0 && dtop
< resistance_size
) {
3343 // if we're already past the top edge, then don't provide
3345 if (moving
.top() >= winrect
.top())
3347 } else if (dbottom
> 0 && dbottom
< resistance_size
) {
3348 // if we're already past the bottom edge, then don't provide
3350 if (moving
.bottom() <= winrect
.bottom())
3351 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
3353 } else { // BScreen::WindowSnap
3354 dtop
= abs(wtop
- winrect
.top());
3355 dbottom
= abs(wbottom
- winrect
.bottom());
3356 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3358 else if (dbottom
< snap_distance
)
3359 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
3367 // if the windows are on the same plane horizontally
3368 if (wleft
>= (signed)(winrect
.x() - frame
.rect
.width() + 1) &&
3369 wleft
< (signed)(winrect
.x() + winrect
.width() - 1)) {
3371 if (snap_to_windows
== BScreen::WindowResistance
) {
3372 dtop
= wbottom
- offsetrect
.top();
3373 dbottom
= offsetrect
.bottom() - wtop
;
3375 // snap top of other window?
3376 if (dtop
>= 0 && dtop
< resistance_size
&& dtop
< (wbottom
- wtop
)) {
3377 dy
= offsetrect
.top() - frame
.rect
.height();
3380 // snap bottom of other window?
3381 else if (dbottom
>= 0 && dbottom
< resistance_size
&&
3382 dbottom
< (wbottom
- wtop
)) {
3383 dy
= offsetrect
.bottom() + 1;
3386 } else { // BScreen::WindowSnap
3387 dtop
= abs(wbottom
- offsetrect
.top());
3388 dbottom
= abs(wtop
- offsetrect
.bottom());
3390 // snap top of other window?
3391 if (dtop
< snap_distance
&& dtop
<= dbottom
) {
3392 dy
= offsetrect
.top() - frame
.rect
.height();
3395 // snap bottom of other window?
3396 else if (dbottom
< snap_distance
) {
3397 dy
= offsetrect
.bottom() + 1;
3404 if (screen
->getWindowCornerSnap()) {
3405 // try corner-snap to its other sides
3406 if (snap_to_windows
== BScreen::WindowResistance
) {
3407 dleft
= winrect
.left() - wleft
;
3408 dright
= wright
- winrect
.right();
3409 if (dleft
> 0 && dleft
< resistance_size
) {
3410 // if we're already past the left edge, then don't provide
3412 if (moving
.left() >= winrect
.left())
3413 dx
= winrect
.left();
3414 } else if (dright
> 0 && dright
< resistance_size
) {
3415 // if we're already past the right edge, then don't provide
3417 if (moving
.right() <= winrect
.right())
3418 dx
= winrect
.right() - frame
.rect
.width() + 1;
3420 } else { // BScreen::WindowSnap
3421 dleft
= abs(wleft
- winrect
.left());
3422 dright
= abs(wright
- winrect
.right());
3423 if (dleft
< snap_distance
&& dleft
<= dright
)
3424 dx
= winrect
.left();
3425 else if (dright
< snap_distance
)
3426 dx
= winrect
.right() - frame
.rect
.width() + 1;
3436 if (snap_to_edges
) {
3439 // snap to the screen edges (and screen boundaries for xinerama)
3441 if (screen
->isXineramaActive() && blackbox
->doXineramaSnapping()) {
3442 rectlist
.insert(rectlist
.begin(),
3443 screen
->getXineramaAreas().begin(),
3444 screen
->getXineramaAreas().end());
3447 rectlist
.push_back(screen
->getRect());
3449 RectList::const_iterator it
, end
= rectlist
.end();
3450 for (it
= rectlist
.begin(); it
!= end
; ++it
) {
3451 const Rect
&srect
= *it
;
3453 offsetrect
.setCoords(srect
.left() + snap_offset
,
3454 srect
.top() + snap_offset
,
3455 srect
.right() - snap_offset
,
3456 srect
.bottom() - snap_offset
);
3458 if (snap_to_edges
== BScreen::WindowResistance
) {
3459 // if we're not in the rectangle then don't snap to it.
3460 if (! srect
.contains(moving
))
3462 } else { // BScreen::WindowSnap
3463 // if we're not in the rectangle then don't snap to it.
3464 if (! srect
.intersects(Rect(wleft
, wtop
, frame
.rect
.width(),
3465 frame
.rect
.height())))
3469 if (snap_to_edges
== BScreen::WindowResistance
) {
3470 int dleft
= offsetrect
.left() - wleft
,
3471 dright
= wright
- offsetrect
.right(),
3472 dtop
= offsetrect
.top() - wtop
,
3473 dbottom
= wbottom
- offsetrect
.bottom();
3476 if (dleft
> 0 && dleft
< resistance_size
)
3477 dx
= offsetrect
.left();
3479 else if (dright
> 0 && dright
< resistance_size
)
3480 dx
= offsetrect
.right() - frame
.rect
.width() + 1;
3483 if (dtop
> 0 && dtop
< resistance_size
)
3484 dy
= offsetrect
.top();
3486 else if (dbottom
> 0 && dbottom
< resistance_size
)
3487 dy
= offsetrect
.bottom() - frame
.rect
.height() + 1;
3488 } else { // BScreen::WindowSnap
3489 int dleft
= abs(wleft
- offsetrect
.left()),
3490 dright
= abs(wright
- offsetrect
.right()),
3491 dtop
= abs(wtop
- offsetrect
.top()),
3492 dbottom
= abs(wbottom
- offsetrect
.bottom());
3495 if (dleft
< snap_distance
&& dleft
<= dright
)
3496 dx
= offsetrect
.left();
3498 else if (dright
< snap_distance
)
3499 dx
= offsetrect
.right() - frame
.rect
.width() + 1;
3502 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3503 dy
= offsetrect
.top();
3505 else if (dbottom
< snap_distance
)
3506 dy
= offsetrect
.bottom() - frame
.rect
.height() + 1;
3513 void BlackboxWindow::endMove(void) {
3514 assert(flags
.moving
);
3515 assert(blackbox
->getChangingWindow() == this);
3517 flags
.moving
= False
;
3518 blackbox
->setChangingWindow(0);
3520 if (! screen
->doOpaqueMove()) {
3521 /* when drawing the rubber band, we need to make sure we only draw inside
3522 * the frame... frame.changing_* contain the new coords for the window,
3523 * so we need to subtract 1 from changing_w/changing_h every where we
3524 * draw the rubber band (for both moving and resizing)
3526 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3527 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3528 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3529 XUngrabServer(blackbox
->getXDisplay());
3531 configure(frame
.changing
.x(), frame
.changing
.y(),
3532 frame
.changing
.width(), frame
.changing
.height());
3534 configure(frame
.rect
.x(), frame
.rect
.y(),
3535 frame
.rect
.width(), frame
.rect
.height());
3537 screen
->hideGeometry();
3539 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3541 // if there are any left over motions from the move, drop them now
3542 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3544 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3549 void BlackboxWindow::beginResize(int x_root
, int y_root
, Corner dir
) {
3550 if (! (functions
& Func_Resize
)) return;
3552 assert(! (flags
.resizing
|| flags
.moving
));
3555 Only one window can be moved/resized at a time. If another window is
3556 already being moved or resized, then stop it before whating to work with
3559 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3560 if (changing
&& changing
!= this) {
3561 if (changing
->flags
.moving
)
3562 changing
->endMove();
3563 else // if (changing->flags.resizing)
3564 changing
->endResize();
3572 switch (resize_dir
) {
3575 cursor
= blackbox
->getLowerLeftAngleCursor();
3580 cursor
= blackbox
->getLowerRightAngleCursor();
3584 anchor
= BottomRight
;
3585 cursor
= blackbox
->getUpperLeftAngleCursor();
3589 anchor
= BottomLeft
;
3590 cursor
= blackbox
->getUpperRightAngleCursor();
3594 assert(false); // unhandled Corner
3595 return; // unreachable, for the compiler
3598 XGrabServer(blackbox
->getXDisplay());
3599 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3600 PointerMotionMask
| ButtonReleaseMask
,
3601 GrabModeAsync
, GrabModeAsync
, None
, cursor
, CurrentTime
);
3603 flags
.resizing
= True
;
3604 blackbox
->setChangingWindow(this);
3606 unsigned int gw
, gh
;
3607 frame
.changing
= frame
.rect
;
3609 constrain(anchor
, &gw
, &gh
);
3611 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3612 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3613 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3615 screen
->showGeometry(gw
, gh
);
3617 frame
.grab_x
= x_root
;
3618 frame
.grab_y
= y_root
;
3622 void BlackboxWindow::doResize(int x_root
, int y_root
) {
3623 assert(flags
.resizing
);
3624 assert(blackbox
->getChangingWindow() == this);
3626 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3627 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3628 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3630 unsigned int gw
, gh
;
3632 int dx
, dy
; // the amount of change in the size of the window
3634 switch (resize_dir
) {
3637 dx
= - (x_root
- frame
.grab_x
);
3638 dy
= + (y_root
- frame
.grab_y
);
3642 dx
= + (x_root
- frame
.grab_x
);
3643 dy
= + (y_root
- frame
.grab_y
);
3646 anchor
= BottomRight
;
3647 dx
= - (x_root
- frame
.grab_x
);
3648 dy
= - (y_root
- frame
.grab_y
);
3651 anchor
= BottomLeft
;
3652 dx
= + (x_root
- frame
.grab_x
);
3653 dy
= - (y_root
- frame
.grab_y
);
3657 assert(false); // unhandled Corner
3658 return; // unreachable, for the compiler
3661 // make sure the user cant resize the window smaller than 0, which makes it
3662 // wrap around and become huge
3663 if (dx
< -(signed)client
.rect
.width()) dx
= -(signed)client
.rect
.width();
3664 if (dy
< -(signed)client
.rect
.height()) dy
= -(signed)client
.rect
.height();
3666 frame
.changing
.setSize(frame
.rect
.width() + dx
, frame
.rect
.height() + dy
);
3668 constrain(anchor
, &gw
, &gh
);
3670 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3671 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3672 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3674 screen
->showGeometry(gw
, gh
);
3678 void BlackboxWindow::endResize(void) {
3679 assert(flags
.resizing
);
3680 assert(blackbox
->getChangingWindow() == this);
3682 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3683 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3684 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3685 XUngrabServer(blackbox
->getXDisplay());
3687 // unset maximized state after resized when fully maximized
3688 if (flags
.maximized
== 1)
3691 flags
.resizing
= False
;
3692 blackbox
->setChangingWindow(0);
3694 configure(frame
.changing
.x(), frame
.changing
.y(),
3695 frame
.changing
.width(), frame
.changing
.height());
3696 screen
->hideGeometry();
3698 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3700 // if there are any left over motions from the resize, drop them now
3701 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3703 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3708 void BlackboxWindow::motionNotifyEvent(const XMotionEvent
*me
) {
3710 fprintf(stderr
, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n",
3715 doMove(me
->x_root
, me
->y_root
);
3716 } else if (flags
.resizing
) {
3717 doResize(me
->x_root
, me
->y_root
);
3719 if ((functions
& Func_Move
) &&
3720 (me
->state
& Button1Mask
) &&
3721 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3722 frame
.handle
== me
->window
|| frame
.window
== me
->window
)) {
3723 beginMove(me
->x_root
, me
->y_root
);
3724 } else if ((functions
& Func_Resize
) &&
3725 ((me
->state
& Button1Mask
) && (me
->window
== frame
.right_grip
||
3726 me
->window
== frame
.left_grip
)) ||
3727 ((me
->state
& Button3Mask
) && (me
->state
& mod_mask
) &&
3728 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3729 frame
.handle
== me
->window
|| frame
.window
== me
->window
))) {
3730 unsigned int zones
= screen
->getResizeZones();
3733 if (me
->window
== frame
.left_grip
) {
3734 corner
= BottomLeft
;
3735 } else if (me
->window
== frame
.right_grip
|| zones
== 1) {
3736 corner
= BottomRight
;
3739 bool left
= (me
->x_root
- frame
.rect
.x() <=
3740 static_cast<signed>(frame
.rect
.width() / 2));
3743 else // (zones == 4)
3744 top
= (me
->y_root
- frame
.rect
.y() <=
3745 static_cast<signed>(frame
.rect
.height() / 2));
3746 corner
= (top
? (left
? TopLeft
: TopRight
) :
3747 (left
? BottomLeft
: BottomRight
));
3750 beginResize(me
->x_root
, me
->y_root
, corner
);
3756 void BlackboxWindow::enterNotifyEvent(const XCrossingEvent
* ce
) {
3757 if (! (screen
->isSloppyFocus() && isVisible() && isNormal()))
3761 bool leave
= False
, inferior
= False
;
3763 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), ce
->window
,
3765 if (e
.type
== LeaveNotify
&& e
.xcrossing
.mode
== NotifyNormal
) {
3767 inferior
= (e
.xcrossing
.detail
== NotifyInferior
);
3771 if (! leave
|| inferior
) {
3772 if (! isFocused()) {
3773 bool success
= setInputFocus();
3774 if (success
) // if focus succeeded install the colormap
3775 installColormap(True
); // XXX: shouldnt we honour no install?
3778 if (screen
->doAutoRaise())
3784 void BlackboxWindow::leaveNotifyEvent(const XCrossingEvent
*) {
3785 if (! (screen
->isSloppyFocus() && screen
->doAutoRaise() && isNormal()))
3788 installColormap(False
);
3790 if (timer
->isTiming())
3796 void BlackboxWindow::shapeEvent(XShapeEvent
*e
) {
3797 if (blackbox
->hasShapeExtensions()) {
3798 if (! e
->shaped
&& flags
.shaped
) {
3800 flags
.shaped
= False
;
3801 } else if (e
->shaped
) {
3803 flags
.shaped
= True
;
3810 bool BlackboxWindow::validateClient(void) const {
3811 XSync(blackbox
->getXDisplay(), False
);
3814 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3815 DestroyNotify
, &e
) ||
3816 XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3818 XPutBackEvent(blackbox
->getXDisplay(), &e
);
3827 void BlackboxWindow::restore(bool remap
) {
3828 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeDelete
);
3829 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
3830 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, NoEventMask
);
3832 // do not leave a shaded window as an icon unless it was an icon
3833 if (flags
.shaded
&& ! flags
.iconic
)
3834 setState(NormalState
);
3836 // erase the netwm stuff that we read when a window maps, so that it
3837 // doesn't persist between mappings.
3838 // (these are the ones read in getNetWMFlags().)
3839 xatom
->eraseValue(client
.window
, XAtom::net_wm_desktop
);
3840 xatom
->eraseValue(client
.window
, XAtom::net_wm_state
);
3842 restoreGravity(client
.rect
);
3844 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
3845 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
3847 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, client
.old_bw
);
3850 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3851 ReparentNotify
, &ev
)) {
3854 // according to the ICCCM - if the client doesn't reparent to
3855 // root, then we have to do it for them
3856 XReparentWindow(blackbox
->getXDisplay(), client
.window
,
3857 screen
->getRootWindow(),
3858 client
.rect
.x(), client
.rect
.y());
3861 if (remap
) XMapWindow(blackbox
->getXDisplay(), client
.window
);
3865 // timer for autoraise
3866 void BlackboxWindow::timeout(void) {
3867 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3871 void BlackboxWindow::changeBlackboxHints(const BlackboxHints
*net
) {
3872 if ((net
->flags
& AttribShaded
) &&
3873 ((blackbox_attrib
.attrib
& AttribShaded
) !=
3874 (net
->attrib
& AttribShaded
)))
3877 if (flags
.visible
&& // watch out for requests when we can not be seen
3878 (net
->flags
& (AttribMaxVert
| AttribMaxHoriz
)) &&
3879 ((blackbox_attrib
.attrib
& (AttribMaxVert
| AttribMaxHoriz
)) !=
3880 (net
->attrib
& (AttribMaxVert
| AttribMaxHoriz
)))) {
3881 if (flags
.maximized
) {
3886 if ((net
->flags
& AttribMaxHoriz
) && (net
->flags
& AttribMaxVert
))
3887 button
= ((net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0);
3888 else if (net
->flags
& AttribMaxVert
)
3889 button
= ((net
->attrib
& AttribMaxVert
) ? 2 : 0);
3890 else if (net
->flags
& AttribMaxHoriz
)
3891 button
= ((net
->attrib
& AttribMaxHoriz
) ? 3 : 0);
3897 if ((net
->flags
& AttribOmnipresent
) &&
3898 ((blackbox_attrib
.attrib
& AttribOmnipresent
) !=
3899 (net
->attrib
& AttribOmnipresent
)))
3902 if ((net
->flags
& AttribWorkspace
) &&
3903 (blackbox_attrib
.workspace
!= net
->workspace
)) {
3904 screen
->reassociateWindow(this, net
->workspace
, True
);
3906 if (screen
->getCurrentWorkspaceID() != net
->workspace
) {
3910 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3914 if (net
->flags
& AttribDecoration
) {
3915 switch (net
->decoration
) {
3932 * Set the sizes of all components of the window frame
3933 * (the window decorations).
3934 * These values are based upon the current style settings and the client
3935 * window's dimensions.
3937 void BlackboxWindow::upsize(void) {
3938 frame
.bevel_w
= screen
->getBevelWidth();
3940 if (decorations
& Decor_Border
) {
3941 frame
.border_w
= screen
->getBorderWidth();
3942 if (! isTransient())
3943 frame
.mwm_border_w
= screen
->getFrameWidth();
3945 frame
.mwm_border_w
= 0;
3947 frame
.mwm_border_w
= frame
.border_w
= 0;
3950 if (decorations
& Decor_Titlebar
) {
3951 // the height of the titlebar is based upon the height of the font being
3952 // used to display the window's title
3953 WindowStyle
*style
= screen
->getWindowStyle();
3954 frame
.title_h
= style
->font
->height() + (frame
.bevel_w
* 2) + 2;
3956 frame
.label_h
= frame
.title_h
- (frame
.bevel_w
* 2);
3957 frame
.button_w
= (frame
.label_h
- 2);
3959 // set the top frame margin
3960 frame
.margin
.top
= frame
.border_w
+ frame
.title_h
+
3961 frame
.border_w
+ frame
.mwm_border_w
;
3967 // set the top frame margin
3968 frame
.margin
.top
= frame
.border_w
+ frame
.mwm_border_w
;
3971 // set the left/right frame margin
3972 frame
.margin
.left
= frame
.margin
.right
= frame
.border_w
+ frame
.mwm_border_w
;
3974 if (decorations
& Decor_Handle
) {
3975 frame
.grip_w
= frame
.button_w
* 2;
3976 frame
.handle_h
= screen
->getHandleWidth();
3978 // set the bottom frame margin
3979 frame
.margin
.bottom
= frame
.border_w
+ frame
.handle_h
+
3980 frame
.border_w
+ frame
.mwm_border_w
;
3985 // set the bottom frame margin
3986 frame
.margin
.bottom
= frame
.border_w
+ frame
.mwm_border_w
;
3990 We first get the normal dimensions and use this to define the inside_w/h
3991 then we modify the height if shading is in effect.
3992 If the shade state is not considered then frame.rect gets reset to the
3993 normal window size on a reconfigure() call resulting in improper
3994 dimensions appearing in move/resize and other events.
3997 height
= client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
,
3998 width
= client
.rect
.width() + frame
.margin
.left
+ frame
.margin
.right
;
4000 frame
.inside_w
= width
- (frame
.border_w
* 2);
4001 frame
.inside_h
= height
- (frame
.border_w
* 2);
4004 height
= frame
.title_h
+ (frame
.border_w
* 2);
4005 frame
.rect
.setSize(width
, height
);
4010 * Calculate the size of the client window and constrain it to the
4011 * size specified by the size hints of the client window.
4013 * The logical width and height are placed into pw and ph, if they
4014 * are non-zero. Logical size refers to the users perception of
4015 * the window size (for example an xterm resizes in cells, not in pixels).
4016 * pw and ph are then used to display the geometry during window moves, resize,
4019 * The physical geometry is placed into frame.changing_{x,y,width,height}.
4020 * Physical geometry refers to the geometry of the window in pixels.
4022 void BlackboxWindow::constrain(Corner anchor
,
4023 unsigned int *pw
, unsigned int *ph
) {
4024 // frame.changing represents the requested frame size, we need to
4025 // strip the frame margin off and constrain the client size
4026 frame
.changing
.setCoords(frame
.changing
.left() + frame
.margin
.left
,
4027 frame
.changing
.top() + frame
.margin
.top
,
4028 frame
.changing
.right() - frame
.margin
.right
,
4029 frame
.changing
.bottom() - frame
.margin
.bottom
);
4031 unsigned int dw
= frame
.changing
.width(), dh
= frame
.changing
.height(),
4032 base_width
= (client
.base_width
) ? client
.base_width
: client
.min_width
,
4033 base_height
= (client
.base_height
) ? client
.base_height
:
4037 if (dw
< client
.min_width
) dw
= client
.min_width
;
4038 if (dh
< client
.min_height
) dh
= client
.min_height
;
4039 if (dw
> client
.max_width
) dw
= client
.max_width
;
4040 if (dh
> client
.max_height
) dh
= client
.max_height
;
4042 assert(dw
>= base_width
&& dh
>= base_height
);
4044 if (client
.width_inc
> 1) {
4046 dw
/= client
.width_inc
;
4048 if (client
.height_inc
> 1) {
4050 dh
/= client
.height_inc
;
4059 if (client
.width_inc
> 1) {
4060 dw
*= client
.width_inc
;
4063 if (client
.height_inc
> 1) {
4064 dh
*= client
.height_inc
;
4068 frame
.changing
.setSize(dw
, dh
);
4070 // add the frame margin back onto frame.changing
4071 frame
.changing
.setCoords(frame
.changing
.left() - frame
.margin
.left
,
4072 frame
.changing
.top() - frame
.margin
.top
,
4073 frame
.changing
.right() + frame
.margin
.right
,
4074 frame
.changing
.bottom() + frame
.margin
.bottom
);
4076 // move frame.changing to the specified anchor
4084 dx
= frame
.rect
.right() - frame
.changing
.right();
4088 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
4092 dx
= frame
.rect
.right() - frame
.changing
.right();
4093 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
4097 assert(false); // unhandled corner
4099 frame
.changing
.setPos(frame
.changing
.x() + dx
, frame
.changing
.y() + dy
);
4103 void WindowStyle::doJustify(const std::string
&text
, int &start_pos
,
4104 unsigned int max_length
,
4105 unsigned int modifier
) const {
4106 size_t text_len
= text
.size();
4107 unsigned int length
;
4110 length
= font
->measureString(string(text
, 0, text_len
)) + modifier
;
4111 } while (length
> max_length
&& text_len
-- > 0);
4115 start_pos
+= max_length
- length
;
4119 start_pos
+= (max_length
- length
) / 2;
4129 BWindowGroup::BWindowGroup(Blackbox
*b
, Window _group
)
4130 : blackbox(b
), group(_group
) {
4131 XWindowAttributes wattrib
;
4132 if (! XGetWindowAttributes(blackbox
->getXDisplay(), group
, &wattrib
)) {
4133 // group window doesn't seem to exist anymore
4138 XSelectInput(blackbox
->getXDisplay(), group
,
4139 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
4141 blackbox
->saveGroupSearch(group
, this);
4145 BWindowGroup::~BWindowGroup(void) {
4146 blackbox
->removeGroupSearch(group
);
4151 BWindowGroup::find(BScreen
*screen
, bool allow_transients
) const {
4152 BlackboxWindow
*ret
= blackbox
->getFocusedWindow();
4154 // does the focus window match (or any transient_fors)?
4155 for (; ret
; ret
= ret
->getTransientFor()) {
4156 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
&&
4157 (! ret
->isTransient() || allow_transients
))
4161 if (ret
) return ret
;
4163 // the focus window didn't match, look in the group's window list
4164 BlackboxWindowList::const_iterator it
, end
= windowList
.end();
4165 for (it
= windowList
.begin(); it
!= end
; ++it
) {
4167 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
&&
4168 (! ret
->isTransient() || allow_transients
))