1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2 // Window.cc for Blackbox - an X11 Window manager
3 // Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry <shaleh at debian.org>
4 // Copyright (c) 1997 - 2000, 2002 Brad Hughes <bhughes at trolltech.com>
6 // Permission is hereby granted, free of charge, to any person obtaining a
7 // copy of this software and associated documentation files (the "Software"),
8 // to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 // and/or sell copies of the Software, and to permit persons to whom the
11 // Software is furnished to do so, subject to the following conditions:
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 // DEALINGS IN THE SOFTWARE.
25 # include "../config.h"
26 #endif // HAVE_CONFIG_H
29 #include <X11/Xatom.h>
30 #include <X11/keysym.h>
34 #endif // HAVE_STRING_H
39 # endif // HAVE_STDIO_H
44 #endif // HAVE_STDLIB_H
48 #include "blackbox.hh"
49 #include "Clientmenu.hh"
52 #include "Iconmenu.hh"
58 #include "Windowmenu.hh"
59 #include "Workspace.hh"
66 * Initializes the class with default values/the window's set initial values.
68 BlackboxWindow::BlackboxWindow(Blackbox
*b
, Window w
, BScreen
*s
) {
69 // fprintf(stderr, "BlackboxWindow size: %d bytes\n",
70 // sizeof(BlackboxWindow));
73 fprintf(stderr
, "BlackboxWindow::BlackboxWindow(): creating 0x%lx\n", w
);
77 set timer to zero... it is initialized properly later, so we check
78 if timer is zero in the destructor, and assume that the window is not
79 fully constructed if timer is zero...
85 xatom
= blackbox
->getXAtom();
87 if (! validateClient()) {
92 // fetch client size and placement
93 XWindowAttributes wattrib
;
94 if (! XGetWindowAttributes(blackbox
->getXDisplay(),
95 client
.window
, &wattrib
) ||
96 ! wattrib
.screen
|| wattrib
.override_redirect
) {
99 "BlackboxWindow::BlackboxWindow(): XGetWindowAttributes failed\n");
106 // set the eventmask early in the game so that we make sure we get
107 // all the events we are interested in
108 XSetWindowAttributes attrib_set
;
109 attrib_set
.event_mask
= PropertyChangeMask
| FocusChangeMask
|
111 attrib_set
.do_not_propagate_mask
= ButtonPressMask
| ButtonReleaseMask
|
113 XChangeWindowAttributes(blackbox
->getXDisplay(), client
.window
,
114 CWEventMask
|CWDontPropagate
, &attrib_set
);
116 flags
.moving
= flags
.resizing
= flags
.shaded
= flags
.visible
=
117 flags
.iconic
= flags
.focused
= flags
.stuck
= flags
.modal
=
118 flags
.send_focus_message
= flags
.shaped
= flags
.skip_taskbar
=
119 flags
.skip_pager
= flags
.fullscreen
= False
;
122 blackbox_attrib
.workspace
= window_number
= BSENTINEL
;
124 blackbox_attrib
.flags
= blackbox_attrib
.attrib
= blackbox_attrib
.stack
= 0l;
125 blackbox_attrib
.decoration
= DecorNormal
;
126 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
127 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
130 frame
.window
= frame
.plate
= frame
.title
= frame
.handle
= None
;
131 frame
.close_button
= frame
.iconify_button
= frame
.maximize_button
= None
;
132 frame
.right_grip
= frame
.left_grip
= None
;
134 frame
.ulabel_pixel
= frame
.flabel_pixel
= frame
.utitle_pixel
=
135 frame
.ftitle_pixel
= frame
.uhandle_pixel
= frame
.fhandle_pixel
=
136 frame
.ubutton_pixel
= frame
.fbutton_pixel
= frame
.pbutton_pixel
=
137 frame
.uborder_pixel
= frame
.fborder_pixel
= frame
.ugrip_pixel
=
138 frame
.fgrip_pixel
= 0;
139 frame
.utitle
= frame
.ftitle
= frame
.uhandle
= frame
.fhandle
= None
;
140 frame
.ulabel
= frame
.flabel
= frame
.ubutton
= frame
.fbutton
= None
;
141 frame
.pbutton
= frame
.ugrip
= frame
.fgrip
= None
;
143 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
144 mwm_decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
145 Decor_Iconify
| Decor_Maximize
;
147 client
.normal_hint_flags
= 0;
148 client
.window_group
= None
;
149 client
.transient_for
= 0;
151 current_state
= NormalState
;
156 set the initial size and location of client window (relative to the
157 _root window_). This position is the reference point used with the
158 window's gravity to find the window's initial position.
160 client
.rect
.setRect(wattrib
.x
, wattrib
.y
, wattrib
.width
, wattrib
.height
);
161 client
.old_bw
= wattrib
.border_width
;
163 lastButtonPressTime
= 0;
165 timer
= new BTimer(blackbox
, this);
166 timer
->setTimeout(blackbox
->getAutoRaiseDelay());
168 // get size, aspect, minimum/maximum size and other hints set by the
171 if (! getBlackboxHints())
178 frame
.window
= createToplevelWindow();
180 blackbox
->saveWindowSearch(frame
.window
, this);
182 frame
.plate
= createChildWindow(frame
.window
);
183 blackbox
->saveWindowSearch(frame
.plate
, this);
185 // determine if this is a transient window
188 // determine the window's type, so we can decide its decorations and
189 // functionality, or if we should not manage it at all
190 if (getWindowType()) {
191 // adjust the window decorations/behavior based on the window type
192 switch (window_type
) {
196 blackbox_attrib
.workspace
= 0; // we do need to belong to a workspace
197 flags
.stuck
= True
; // we show up on all workspaces
199 // none of these windows are manipulated by the window manager
205 // these windows get less functionality
206 functions
&= ~(Func_Maximize
| Func_Resize
| Func_Iconify
);
210 // dialogs cannot be maximized
211 functions
&= ~Func_Maximize
;
215 // normal windows retain all of the possible decorations and functionality
222 // further adjeust the window's decorations/behavior based on window sizes
223 if ((client
.normal_hint_flags
& PMinSize
) &&
224 (client
.normal_hint_flags
& PMaxSize
) &&
225 client
.max_width
<= client
.min_width
&&
226 client
.max_height
<= client
.min_height
) {
227 functions
&= ~(Func_Resize
| Func_Maximize
);
234 if (decorations
& Decor_Titlebar
)
237 if (decorations
& Decor_Handle
)
240 // apply the size and gravity hint to the frame
244 bool place_window
= True
;
245 if (blackbox
->isStartup() || isTransient() ||
246 client
.normal_hint_flags
& (PPosition
|USPosition
)) {
247 applyGravity(frame
.rect
);
249 if (blackbox
->isStartup() || client
.rect
.intersects(screen
->getRect()))
250 place_window
= False
;
253 // add the window's strut. note this is done *after* placing the window.
254 screen
->addStrut(&client
.strut
);
258 the server needs to be grabbed here to prevent client's from sending
259 events while we are in the process of configuring their window.
260 We hold the grab until after we are done moving the window around.
263 XGrabServer(blackbox
->getXDisplay());
265 associateClientWindow();
267 blackbox
->saveWindowSearch(client
.window
, this);
269 if (blackbox_attrib
.workspace
>= screen
->getWorkspaceCount())
270 screen
->getCurrentWorkspace()->addWindow(this, place_window
);
272 screen
->getWorkspace(blackbox_attrib
.workspace
)->
273 addWindow(this, place_window
);
275 if (! place_window
) {
276 // don't need to call configure if we are letting the workspace
278 configure(frame
.rect
.x(), frame
.rect
.y(),
279 frame
.rect
.width(), frame
.rect
.height());
285 XUngrabServer(blackbox
->getXDisplay());
288 if (blackbox
->hasShapeExtensions() && flags
.shaped
)
292 // now that we know where to put the window and what it should look like
293 // we apply the decorations
298 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
300 // this ensures the title, buttons, and other decor are properly displayed
303 // preserve the window's initial state on first map, and its current state
305 unsigned long initial_state
= current_state
;
307 current_state
= initial_state
;
309 // get sticky state from our parent window if we've got one
310 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
311 client
.transient_for
->isStuck() != flags
.stuck
)
315 flags
.shaded
= False
;
316 initial_state
= current_state
;
320 At this point in the life of a window, current_state should only be set
321 to IconicState if the window was an *icon*, not if it was shaded.
323 if (initial_state
!= IconicState
)
324 current_state
= NormalState
;
332 if (flags
.maximized
&& (functions
& Func_Maximize
))
335 // create this last so it only needs to be configured once
336 windowmenu
= new Windowmenu(this);
340 BlackboxWindow::~BlackboxWindow(void) {
342 fprintf(stderr
, "BlackboxWindow::~BlackboxWindow: destroying 0x%lx\n",
346 if (! timer
) // window not managed...
352 screen
->removeStrut(&client
.strut
);
353 screen
->updateAvailableArea();
355 // We don't need to worry about resizing because resizing always grabs the X
356 // server. This should only ever happen if using opaque moving.
364 if (client
.window_group
) {
365 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
366 if (group
) group
->removeWindow(this);
369 // remove ourselves from our transient_for
371 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul)
372 client
.transient_for
->client
.transientList
.remove(this);
373 client
.transient_for
= (BlackboxWindow
*) 0;
376 if (client
.transientList
.size() > 0) {
377 // reset transient_for for all transients
378 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
379 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
380 (*it
)->client
.transient_for
= (BlackboxWindow
*) 0;
390 blackbox
->removeWindowSearch(frame
.plate
);
391 XDestroyWindow(blackbox
->getXDisplay(), frame
.plate
);
395 blackbox
->removeWindowSearch(frame
.window
);
396 XDestroyWindow(blackbox
->getXDisplay(), frame
.window
);
399 blackbox
->removeWindowSearch(client
.window
);
403 void BlackboxWindow::enableDecor(bool enable
) {
404 blackbox_attrib
.flags
|= AttribDecoration
;
405 blackbox_attrib
.decoration
= enable
? DecorNormal
: DecorNone
;
408 // we can not be shaded if we lack a titlebar
409 if (! (decorations
& Decor_Titlebar
) && flags
.shaded
)
412 if (flags
.visible
&& frame
.window
) {
413 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
414 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
418 setState(current_state
);
422 void BlackboxWindow::setupDecor() {
423 if (blackbox_attrib
.decoration
!= DecorNone
) {
424 // start with everything on
425 decorations
= Decor_Close
|
426 (mwm_decorations
& Decor_Titlebar
? Decor_Titlebar
: 0) |
427 (mwm_decorations
& Decor_Border
? Decor_Border
: 0) |
428 (mwm_decorations
& Decor_Handle
? Decor_Handle
: 0) |
429 (mwm_decorations
& Decor_Iconify
? Decor_Iconify
: 0) |
430 (mwm_decorations
& Decor_Maximize
? Decor_Maximize
: 0);
432 if (! (functions
& Func_Close
)) decorations
&= ~Decor_Close
;
433 if (! (functions
& Func_Maximize
)) decorations
&= ~Decor_Maximize
;
434 if (! (functions
& Func_Iconify
)) decorations
&= ~Decor_Iconify
;
435 if (! (functions
& Func_Resize
)) decorations
&= ~Decor_Handle
;
437 switch (window_type
) {
442 // none of these windows are decorated by the window manager at all
448 decorations
&= ~(Decor_Border
);
452 decorations
&= ~Decor_Handle
;
464 * Creates a new top level window, with a given location, size, and border
466 * Returns: the newly created window
468 Window
BlackboxWindow::createToplevelWindow(void) {
469 XSetWindowAttributes attrib_create
;
470 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
| CWColormap
|
471 CWOverrideRedirect
| CWEventMask
;
473 attrib_create
.background_pixmap
= None
;
474 attrib_create
.colormap
= screen
->getColormap();
475 attrib_create
.override_redirect
= True
;
476 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
478 EnterWindowMask
| LeaveWindowMask
;
480 return XCreateWindow(blackbox
->getXDisplay(), screen
->getRootWindow(),
481 0, 0, 1, 1, frame
.border_w
, screen
->getDepth(),
482 InputOutput
, screen
->getVisual(), create_mask
,
488 * Creates a child window, and optionally associates a given cursor with
491 Window
BlackboxWindow::createChildWindow(Window parent
, Cursor cursor
) {
492 XSetWindowAttributes attrib_create
;
493 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
|
496 attrib_create
.background_pixmap
= None
;
497 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
498 ButtonMotionMask
| ExposureMask
;
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 blackbox
->saveWindowSearch(frame
.handle
, this);
653 createChildWindow(frame
.handle
, blackbox
->getLowerLeftAngleCursor());
654 blackbox
->saveWindowSearch(frame
.left_grip
, this);
657 createChildWindow(frame
.handle
, blackbox
->getLowerRightAngleCursor());
658 blackbox
->saveWindowSearch(frame
.right_grip
, this);
662 void BlackboxWindow::destroyHandle(void) {
664 screen
->getImageControl()->removeImage(frame
.fhandle
);
667 screen
->getImageControl()->removeImage(frame
.uhandle
);
670 screen
->getImageControl()->removeImage(frame
.fgrip
);
673 screen
->getImageControl()->removeImage(frame
.ugrip
);
675 blackbox
->removeWindowSearch(frame
.left_grip
);
676 blackbox
->removeWindowSearch(frame
.right_grip
);
678 XDestroyWindow(blackbox
->getXDisplay(), frame
.left_grip
);
679 XDestroyWindow(blackbox
->getXDisplay(), frame
.right_grip
);
680 frame
.left_grip
= frame
.right_grip
= None
;
682 blackbox
->removeWindowSearch(frame
.handle
);
683 XDestroyWindow(blackbox
->getXDisplay(), frame
.handle
);
688 void BlackboxWindow::createTitlebar(void) {
689 frame
.title
= createChildWindow(frame
.window
);
690 frame
.label
= createChildWindow(frame
.title
);
691 blackbox
->saveWindowSearch(frame
.title
, this);
692 blackbox
->saveWindowSearch(frame
.label
, this);
694 if (decorations
& Decor_Iconify
) createIconifyButton();
695 if (decorations
& Decor_Maximize
) createMaximizeButton();
696 if (decorations
& Decor_Close
) createCloseButton();
700 void BlackboxWindow::destroyTitlebar(void) {
701 if (frame
.close_button
)
702 destroyCloseButton();
704 if (frame
.iconify_button
)
705 destroyIconifyButton();
707 if (frame
.maximize_button
)
708 destroyMaximizeButton();
711 screen
->getImageControl()->removeImage(frame
.ftitle
);
714 screen
->getImageControl()->removeImage(frame
.utitle
);
717 screen
->getImageControl()->removeImage(frame
.flabel
);
720 screen
->getImageControl()->removeImage(frame
.ulabel
);
723 screen
->getImageControl()->removeImage(frame
.fbutton
);
726 screen
->getImageControl()->removeImage(frame
.ubutton
);
729 screen
->getImageControl()->removeImage(frame
.pbutton
);
731 blackbox
->removeWindowSearch(frame
.title
);
732 blackbox
->removeWindowSearch(frame
.label
);
734 XDestroyWindow(blackbox
->getXDisplay(), frame
.label
);
735 XDestroyWindow(blackbox
->getXDisplay(), frame
.title
);
736 frame
.title
= frame
.label
= None
;
740 void BlackboxWindow::createCloseButton(void) {
741 if (frame
.title
!= None
) {
742 frame
.close_button
= createChildWindow(frame
.title
);
743 blackbox
->saveWindowSearch(frame
.close_button
, this);
748 void BlackboxWindow::destroyCloseButton(void) {
749 blackbox
->removeWindowSearch(frame
.close_button
);
750 XDestroyWindow(blackbox
->getXDisplay(), frame
.close_button
);
751 frame
.close_button
= None
;
755 void BlackboxWindow::createIconifyButton(void) {
756 if (frame
.title
!= None
) {
757 frame
.iconify_button
= createChildWindow(frame
.title
);
758 blackbox
->saveWindowSearch(frame
.iconify_button
, this);
763 void BlackboxWindow::destroyIconifyButton(void) {
764 blackbox
->removeWindowSearch(frame
.iconify_button
);
765 XDestroyWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
766 frame
.iconify_button
= None
;
770 void BlackboxWindow::createMaximizeButton(void) {
771 if (frame
.title
!= None
) {
772 frame
.maximize_button
= createChildWindow(frame
.title
);
773 blackbox
->saveWindowSearch(frame
.maximize_button
, this);
778 void BlackboxWindow::destroyMaximizeButton(void) {
779 blackbox
->removeWindowSearch(frame
.maximize_button
);
780 XDestroyWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
781 frame
.maximize_button
= None
;
785 void BlackboxWindow::positionButtons(bool redecorate_label
) {
786 string layout
= blackbox
->getTitlebarLayout();
789 bool hasclose
, hasiconify
, hasmaximize
, haslabel
;
790 hasclose
= hasiconify
= hasmaximize
= haslabel
= false;
792 string::const_iterator it
, end
;
793 for (it
= layout
.begin(), end
= layout
.end(); it
!= end
; ++it
) {
796 if (! hasclose
&& (decorations
& Decor_Close
)) {
802 if (! hasiconify
&& (decorations
& Decor_Iconify
)) {
808 if (! hasmaximize
&& (decorations
& Decor_Maximize
)) {
820 if (! hasclose
&& frame
.close_button
)
821 destroyCloseButton();
822 if (! hasiconify
&& frame
.iconify_button
)
823 destroyIconifyButton();
824 if (! hasmaximize
&& frame
.maximize_button
)
825 destroyMaximizeButton();
827 parsed
+= 'L'; // require that the label be in the layout
829 const unsigned int bsep
= frame
.bevel_w
+ 1; // separation between elements
830 const unsigned int by
= frame
.bevel_w
+ 1;
831 const unsigned int ty
= frame
.bevel_w
;
833 frame
.label_w
= frame
.inside_w
- bsep
* 2 -
834 (frame
.button_w
+ bsep
) * (parsed
.size() - 1);
836 unsigned int x
= bsep
;
837 for (it
= parsed
.begin(), end
= parsed
.end(); it
!= end
; ++it
) {
840 if (! frame
.close_button
) createCloseButton();
841 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.close_button
, x
, by
,
842 frame
.button_w
, frame
.button_w
);
843 x
+= frame
.button_w
+ bsep
;
846 if (! frame
.iconify_button
) createIconifyButton();
847 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.iconify_button
, x
, by
,
848 frame
.button_w
, frame
.button_w
);
849 x
+= frame
.button_w
+ bsep
;
852 if (! frame
.maximize_button
) createMaximizeButton();
853 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.maximize_button
, x
, by
,
854 frame
.button_w
, frame
.button_w
);
855 x
+= frame
.button_w
+ bsep
;
858 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.label
, x
, ty
,
859 frame
.label_w
, frame
.label_h
);
860 x
+= frame
.label_w
+ bsep
;
865 if (redecorate_label
) decorateLabel();
871 void BlackboxWindow::reconfigure(void) {
872 restoreGravity(client
.rect
);
874 applyGravity(frame
.rect
);
883 windowmenu
->move(windowmenu
->getX(), frame
.rect
.y() + frame
.title_h
);
884 windowmenu
->reconfigure();
889 void BlackboxWindow::grabButtons(void) {
890 mod_mask
= blackbox
->getMouseModMask();
892 if (! screen
->isSloppyFocus() || screen
->doClickRaise())
893 // grab button 1 for changing focus/raising
894 blackbox
->grabButton(Button1
, 0, frame
.plate
, True
, ButtonPressMask
,
895 GrabModeSync
, GrabModeSync
, frame
.plate
, None
,
896 screen
->allowScrollLock());
898 if (functions
& Func_Move
)
899 blackbox
->grabButton(Button1
, mod_mask
, frame
.window
, True
,
900 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
901 GrabModeAsync
, frame
.window
, None
,
902 screen
->allowScrollLock());
903 if (functions
& Func_Resize
)
904 blackbox
->grabButton(Button3
, mod_mask
, frame
.window
, True
,
905 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
906 GrabModeAsync
, frame
.window
, None
,
907 screen
->allowScrollLock());
908 // alt+middle lowers the window
909 blackbox
->grabButton(Button2
, mod_mask
, frame
.window
, True
,
910 ButtonReleaseMask
, GrabModeAsync
, GrabModeAsync
,
912 screen
->allowScrollLock());
916 void BlackboxWindow::ungrabButtons(void) {
917 blackbox
->ungrabButton(Button1
, 0, frame
.plate
);
918 blackbox
->ungrabButton(Button1
, mod_mask
, frame
.window
);
919 blackbox
->ungrabButton(Button2
, mod_mask
, frame
.window
);
920 blackbox
->ungrabButton(Button3
, mod_mask
, frame
.window
);
924 void BlackboxWindow::positionWindows(void) {
925 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.window
,
926 frame
.rect
.x(), frame
.rect
.y(), frame
.inside_w
,
927 (flags
.shaded
) ? frame
.title_h
: frame
.inside_h
);
928 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.window
,
930 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.plate
,
932 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.plate
,
933 frame
.margin
.left
- frame
.mwm_border_w
- frame
.border_w
,
934 frame
.margin
.top
- frame
.mwm_border_w
- frame
.border_w
,
935 client
.rect
.width(), client
.rect
.height());
936 XMoveResizeWindow(blackbox
->getXDisplay(), client
.window
,
937 0, 0, client
.rect
.width(), client
.rect
.height());
938 // ensure client.rect contains the real location
939 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
940 frame
.rect
.top() + frame
.margin
.top
);
942 if (decorations
& Decor_Titlebar
) {
943 if (frame
.title
== None
) createTitlebar();
945 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.title
,
947 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.title
, -frame
.border_w
,
948 -frame
.border_w
, frame
.inside_w
, frame
.title_h
);
951 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
952 XMapWindow(blackbox
->getXDisplay(), frame
.title
);
953 } else if (frame
.title
) {
956 if (decorations
& Decor_Handle
) {
957 if (frame
.handle
== None
) createHandle();
958 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.handle
,
960 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.left_grip
,
962 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.right_grip
,
965 // use client.rect here so the value is correct even if shaded
966 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.handle
,
968 client
.rect
.height() + frame
.margin
.top
+
969 frame
.mwm_border_w
- frame
.border_w
,
970 frame
.inside_w
, frame
.handle_h
);
971 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.left_grip
,
972 -frame
.border_w
, -frame
.border_w
,
973 frame
.grip_w
, frame
.handle_h
);
974 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.right_grip
,
975 frame
.inside_w
- frame
.grip_w
- frame
.border_w
,
976 -frame
.border_w
, frame
.grip_w
, frame
.handle_h
);
978 XMapSubwindows(blackbox
->getXDisplay(), frame
.handle
);
979 XMapWindow(blackbox
->getXDisplay(), frame
.handle
);
980 } else if (frame
.handle
) {
983 XSync(blackbox
->getXDisplay(), False
);
987 void BlackboxWindow::updateStrut(void) {
988 unsigned long num
= 4;
990 if (! xatom
->getValue(client
.window
, XAtom::net_wm_strut
, XAtom::cardinal
,
995 client
.strut
.left
= data
[0];
996 client
.strut
.right
= data
[1];
997 client
.strut
.top
= data
[2];
998 client
.strut
.bottom
= data
[3];
1000 screen
->updateAvailableArea();
1007 bool BlackboxWindow::getWindowType(void) {
1008 window_type
= (WindowType
) -1;
1011 unsigned long num
= (unsigned) -1;
1012 if (xatom
->getValue(client
.window
, XAtom::net_wm_window_type
, XAtom::atom
,
1014 for (unsigned long i
= 0; i
< num
; ++i
) {
1015 if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_desktop
))
1016 window_type
= Type_Desktop
;
1017 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_dock
))
1018 window_type
= Type_Dock
;
1019 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_toolbar
))
1020 window_type
= Type_Toolbar
;
1021 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_menu
))
1022 window_type
= Type_Menu
;
1023 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_utility
))
1024 window_type
= Type_Utility
;
1025 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_splash
))
1026 window_type
= Type_Splash
;
1027 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_dialog
))
1028 window_type
= Type_Dialog
;
1029 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_normal
))
1030 window_type
= Type_Normal
;
1032 xatom
->getAtom(XAtom::kde_net_wm_window_type_override
))
1033 mwm_decorations
= 0; // prevent this window from getting any decor
1038 if (window_type
== (WindowType
) -1) {
1040 * the window type hint was not set, which means we either classify ourself
1041 * as a normal window or a dialog, depending on if we are a transient.
1044 window_type
= Type_Dialog
;
1046 window_type
= Type_Normal
;
1055 void BlackboxWindow::getWMName(void) {
1056 if (xatom
->getValue(client
.window
, XAtom::net_wm_name
,
1057 XAtom::utf8
, client
.title
) &&
1058 !client
.title
.empty()) {
1059 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
1062 //fall through to using WM_NAME
1063 if (xatom
->getValue(client
.window
, XAtom::wm_name
, XAtom::ansi
, client
.title
)
1064 && !client
.title
.empty()) {
1065 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
1068 // fall back to an internal default
1069 client
.title
= i18n(WindowSet
, WindowUnnamed
, "Unnamed");
1070 xatom
->setValue(client
.window
, XAtom::net_wm_visible_name
, XAtom::utf8
,
1075 void BlackboxWindow::getWMIconName(void) {
1076 if (xatom
->getValue(client
.window
, XAtom::net_wm_icon_name
,
1077 XAtom::utf8
, client
.icon_title
) &&
1078 !client
.icon_title
.empty()) {
1079 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1082 //fall through to using WM_ICON_NAME
1083 if (xatom
->getValue(client
.window
, XAtom::wm_icon_name
, XAtom::ansi
,
1084 client
.icon_title
) &&
1085 !client
.icon_title
.empty()) {
1086 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1089 // fall back to using the main name
1090 client
.icon_title
= client
.title
;
1091 xatom
->setValue(client
.window
, XAtom::net_wm_visible_icon_name
, XAtom::utf8
,
1097 * Retrieve which WM Protocols are supported by the client window.
1098 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
1099 * window's decorations and allow the close behavior.
1100 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
1103 void BlackboxWindow::getWMProtocols(void) {
1107 if (XGetWMProtocols(blackbox
->getXDisplay(), client
.window
,
1108 &proto
, &num_return
)) {
1109 for (int i
= 0; i
< num_return
; ++i
) {
1110 if (proto
[i
] == xatom
->getAtom(XAtom::wm_delete_window
)) {
1111 decorations
|= Decor_Close
;
1112 functions
|= Func_Close
;
1113 } else if (proto
[i
] == xatom
->getAtom(XAtom::wm_take_focus
))
1114 flags
.send_focus_message
= True
;
1115 else if (proto
[i
] == xatom
->getAtom(XAtom::blackbox_structure_messages
))
1116 screen
->addNetizen(new Netizen(screen
, client
.window
));
1125 * Gets the value of the WM_HINTS property.
1126 * If the property is not set, then use a set of default values.
1128 void BlackboxWindow::getWMHints(void) {
1129 focus_mode
= F_Passive
;
1131 // remove from current window group
1132 if (client
.window_group
) {
1133 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1134 if (group
) group
->removeWindow(this);
1136 client
.window_group
= None
;
1138 XWMHints
*wmhint
= XGetWMHints(blackbox
->getXDisplay(), client
.window
);
1143 if (wmhint
->flags
& InputHint
) {
1144 if (wmhint
->input
== True
) {
1145 if (flags
.send_focus_message
)
1146 focus_mode
= F_LocallyActive
;
1148 if (flags
.send_focus_message
)
1149 focus_mode
= F_GloballyActive
;
1151 focus_mode
= F_NoInput
;
1155 if (wmhint
->flags
& StateHint
)
1156 current_state
= wmhint
->initial_state
;
1158 if (wmhint
->flags
& WindowGroupHint
) {
1159 client
.window_group
= wmhint
->window_group
;
1161 // add window to the appropriate group
1162 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1163 if (! group
) { // no group found, create it!
1164 new BWindowGroup(blackbox
, client
.window_group
);
1165 group
= blackbox
->searchGroup(client
.window_group
);
1168 group
->addWindow(this);
1176 * Gets the value of the WM_NORMAL_HINTS property.
1177 * If the property is not set, then use a set of default values.
1179 void BlackboxWindow::getWMNormalHints(void) {
1181 XSizeHints sizehint
;
1183 client
.min_width
= client
.min_height
=
1184 client
.width_inc
= client
.height_inc
= 1;
1185 client
.base_width
= client
.base_height
= 0;
1186 client
.win_gravity
= NorthWestGravity
;
1188 client
.min_aspect_x
= client
.min_aspect_y
=
1189 client
.max_aspect_x
= client
.max_aspect_y
= 1;
1193 use the full screen, not the strut modified size. otherwise when the
1194 availableArea changes max_width/height will be incorrect and lead to odd
1197 const Rect
& screen_area
= screen
->getRect();
1198 client
.max_width
= screen_area
.width();
1199 client
.max_height
= screen_area
.height();
1201 if (! XGetWMNormalHints(blackbox
->getXDisplay(), client
.window
,
1202 &sizehint
, &icccm_mask
))
1205 client
.normal_hint_flags
= sizehint
.flags
;
1207 if (sizehint
.flags
& PMinSize
) {
1208 if (sizehint
.min_width
>= 0)
1209 client
.min_width
= sizehint
.min_width
;
1210 if (sizehint
.min_height
>= 0)
1211 client
.min_height
= sizehint
.min_height
;
1214 if (sizehint
.flags
& PMaxSize
) {
1215 if (sizehint
.max_width
> static_cast<signed>(client
.min_width
))
1216 client
.max_width
= sizehint
.max_width
;
1218 client
.max_width
= client
.min_width
;
1220 if (sizehint
.max_height
> static_cast<signed>(client
.min_height
))
1221 client
.max_height
= sizehint
.max_height
;
1223 client
.max_height
= client
.min_height
;
1226 if (sizehint
.flags
& PResizeInc
) {
1227 client
.width_inc
= sizehint
.width_inc
;
1228 client
.height_inc
= sizehint
.height_inc
;
1231 #if 0 // we do not support this at the moment
1232 if (sizehint
.flags
& PAspect
) {
1233 client
.min_aspect_x
= sizehint
.min_aspect
.x
;
1234 client
.min_aspect_y
= sizehint
.min_aspect
.y
;
1235 client
.max_aspect_x
= sizehint
.max_aspect
.x
;
1236 client
.max_aspect_y
= sizehint
.max_aspect
.y
;
1240 if (sizehint
.flags
& PBaseSize
) {
1241 client
.base_width
= sizehint
.base_width
;
1242 client
.base_height
= sizehint
.base_height
;
1245 if (sizehint
.flags
& PWinGravity
)
1246 client
.win_gravity
= sizehint
.win_gravity
;
1251 * Gets the NETWM hints for the class' contained window.
1253 void BlackboxWindow::getNetWMHints(void) {
1254 unsigned long workspace
;
1256 if (xatom
->getValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1258 if (workspace
== 0xffffffff)
1261 blackbox_attrib
.workspace
= workspace
;
1264 unsigned long *state
;
1265 unsigned long num
= (unsigned) -1;
1266 if (xatom
->getValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
1270 for (unsigned long i
= 0; i
< num
; ++i
) {
1271 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
))
1273 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_shaded
))
1274 flags
.shaded
= True
;
1275 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
))
1276 flags
.skip_taskbar
= True
;
1277 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_pager
))
1278 flags
.skip_pager
= True
;
1279 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_fullscreen
))
1280 flags
.fullscreen
= True
;
1281 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_hidden
))
1282 setState(IconicState
);
1283 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_vert
))
1285 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_horz
))
1289 flags
.maximized
= 1;
1291 flags
.maximized
= 2;
1293 flags
.maximized
= 3;
1301 * Gets the MWM hints for the class' contained window.
1302 * This is used while initializing the window to its first state, and not
1304 * Returns: true if the MWM hints are successfully retreived and applied;
1305 * false if they are not.
1307 void BlackboxWindow::getMWMHints(void) {
1311 num
= PropMwmHintsElements
;
1312 if (! xatom
->getValue(client
.window
, XAtom::motif_wm_hints
,
1313 XAtom::motif_wm_hints
, num
,
1314 (unsigned long **)&mwm_hint
))
1316 if (num
< PropMwmHintsElements
) {
1321 if (mwm_hint
->flags
& MwmHintsDecorations
) {
1322 if (mwm_hint
->decorations
& MwmDecorAll
) {
1323 mwm_decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
1324 Decor_Iconify
| Decor_Maximize
;
1326 mwm_decorations
= 0;
1328 if (mwm_hint
->decorations
& MwmDecorBorder
)
1329 mwm_decorations
|= Decor_Border
;
1330 if (mwm_hint
->decorations
& MwmDecorHandle
)
1331 mwm_decorations
|= Decor_Handle
;
1332 if (mwm_hint
->decorations
& MwmDecorTitle
)
1333 mwm_decorations
|= Decor_Titlebar
;
1334 if (mwm_hint
->decorations
& MwmDecorIconify
)
1335 mwm_decorations
|= Decor_Iconify
;
1336 if (mwm_hint
->decorations
& MwmDecorMaximize
)
1337 mwm_decorations
|= Decor_Maximize
;
1341 if (mwm_hint
->flags
& MwmHintsFunctions
) {
1342 if (mwm_hint
->functions
& MwmFuncAll
) {
1343 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
|
1348 if (mwm_hint
->functions
& MwmFuncResize
)
1349 functions
|= Func_Resize
;
1350 if (mwm_hint
->functions
& MwmFuncMove
)
1351 functions
|= Func_Move
;
1352 if (mwm_hint
->functions
& MwmFuncIconify
)
1353 functions
|= Func_Iconify
;
1354 if (mwm_hint
->functions
& MwmFuncMaximize
)
1355 functions
|= Func_Maximize
;
1356 if (mwm_hint
->functions
& MwmFuncClose
)
1357 functions
|= Func_Close
;
1365 * Gets the blackbox hints from the class' contained window.
1366 * This is used while initializing the window to its first state, and not
1368 * Returns: true if the hints are successfully retreived and applied; false if
1371 bool BlackboxWindow::getBlackboxHints(void) {
1373 BlackboxHints
*blackbox_hint
;
1375 num
= PropBlackboxHintsElements
;
1376 if (! xatom
->getValue(client
.window
, XAtom::blackbox_hints
,
1377 XAtom::blackbox_hints
, num
,
1378 (unsigned long **)&blackbox_hint
))
1380 if (num
< PropBlackboxHintsElements
) {
1381 delete [] blackbox_hint
;
1385 if (blackbox_hint
->flags
& AttribShaded
)
1386 flags
.shaded
= (blackbox_hint
->attrib
& AttribShaded
);
1388 if ((blackbox_hint
->flags
& AttribMaxHoriz
) &&
1389 (blackbox_hint
->flags
& AttribMaxVert
))
1390 flags
.maximized
= (blackbox_hint
->attrib
&
1391 (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1392 else if (blackbox_hint
->flags
& AttribMaxVert
)
1393 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxVert
) ? 2 : 0;
1394 else if (blackbox_hint
->flags
& AttribMaxHoriz
)
1395 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1397 if (blackbox_hint
->flags
& AttribOmnipresent
)
1398 flags
.stuck
= (blackbox_hint
->attrib
& AttribOmnipresent
);
1400 if (blackbox_hint
->flags
& AttribWorkspace
)
1401 blackbox_attrib
.workspace
= blackbox_hint
->workspace
;
1403 // if (blackbox_hint->flags & AttribStack)
1404 // don't yet have always on top/bottom for blackbox yet... working
1407 if (blackbox_hint
->flags
& AttribDecoration
) {
1408 switch (blackbox_hint
->decoration
) {
1410 blackbox_attrib
.decoration
= DecorNone
;
1417 // blackbox_attrib.decoration defaults to DecorNormal
1422 delete [] blackbox_hint
;
1428 void BlackboxWindow::getTransientInfo(void) {
1429 if (client
.transient_for
&&
1430 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1431 // reset transient_for in preparation of looking for a new owner
1432 client
.transient_for
->client
.transientList
.remove(this);
1435 // we have no transient_for until we find a new one
1436 client
.transient_for
= (BlackboxWindow
*) 0;
1439 if (! XGetTransientForHint(blackbox
->getXDisplay(), client
.window
,
1441 // transient_for hint not set
1445 if (trans_for
== client
.window
) {
1446 // wierd client... treat this window as a normal window
1450 if (trans_for
== None
|| trans_for
== screen
->getRootWindow()) {
1451 // this is an undocumented interpretation of the ICCCM. a transient
1452 // associated with None/Root/itself is assumed to be a modal root
1453 // transient. we don't support the concept of a global transient,
1454 // so we just associate this transient with nothing, and perhaps
1455 // we will add support later for global modality.
1456 client
.transient_for
= (BlackboxWindow
*) ~0ul;
1461 client
.transient_for
= blackbox
->searchWindow(trans_for
);
1462 if (! client
.transient_for
&&
1463 client
.window_group
&& trans_for
== client
.window_group
) {
1464 // no direct transient_for, perhaps this is a group transient?
1465 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1466 if (group
) client
.transient_for
= group
->find(screen
);
1469 if (! client
.transient_for
|| client
.transient_for
== this) {
1470 // no transient_for found, or we have a wierd client that wants to be
1471 // a transient for itself, so we treat this window as a normal window
1472 client
.transient_for
= (BlackboxWindow
*) 0;
1476 // Check for a circular transient state: this can lock up Blackbox
1477 // when it tries to find the non-transient window for a transient.
1478 BlackboxWindow
*w
= this;
1479 while(w
->client
.transient_for
&&
1480 w
->client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1481 if(w
->client
.transient_for
== this) {
1482 client
.transient_for
= (BlackboxWindow
*) 0;
1485 w
= w
->client
.transient_for
;
1488 if (client
.transient_for
&&
1489 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1490 // register ourselves with our new transient_for
1491 client
.transient_for
->client
.transientList
.push_back(this);
1492 flags
.stuck
= client
.transient_for
->flags
.stuck
;
1497 BlackboxWindow
*BlackboxWindow::getTransientFor(void) const {
1498 if (client
.transient_for
&&
1499 client
.transient_for
!= (BlackboxWindow
*) ~0ul)
1500 return client
.transient_for
;
1506 * This function is responsible for updating both the client and the frame
1508 * According to the ICCCM a client message is not sent for a resize, only a
1511 void BlackboxWindow::configure(int dx
, int dy
,
1512 unsigned int dw
, unsigned int dh
) {
1513 bool send_event
= ((frame
.rect
.x() != dx
|| frame
.rect
.y() != dy
) &&
1516 if (dw
!= frame
.rect
.width() || dh
!= frame
.rect
.height()) {
1517 frame
.rect
.setRect(dx
, dy
, dw
, dh
);
1518 frame
.inside_w
= frame
.rect
.width() - (frame
.border_w
* 2);
1519 frame
.inside_h
= frame
.rect
.height() - (frame
.border_w
* 2);
1521 if (frame
.rect
.right() <= 0 || frame
.rect
.bottom() <= 0)
1522 frame
.rect
.setPos(0, 0);
1524 client
.rect
.setCoords(frame
.rect
.left() + frame
.margin
.left
,
1525 frame
.rect
.top() + frame
.margin
.top
,
1526 frame
.rect
.right() - frame
.margin
.right
,
1527 frame
.rect
.bottom() - frame
.margin
.bottom
);
1530 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
1537 redrawWindowFrame();
1539 frame
.rect
.setPos(dx
, dy
);
1541 XMoveWindow(blackbox
->getXDisplay(), frame
.window
,
1542 frame
.rect
.x(), frame
.rect
.y());
1544 we may have been called just after an opaque window move, so even though
1545 the old coords match the new ones no ConfigureNotify has been sent yet.
1546 There are likely other times when this will be relevant as well.
1548 if (! flags
.moving
) send_event
= True
;
1552 // if moving, the update and event will occur when the move finishes
1553 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1554 frame
.rect
.top() + frame
.margin
.top
);
1557 event
.type
= ConfigureNotify
;
1559 event
.xconfigure
.display
= blackbox
->getXDisplay();
1560 event
.xconfigure
.event
= client
.window
;
1561 event
.xconfigure
.window
= client
.window
;
1562 event
.xconfigure
.x
= client
.rect
.x();
1563 event
.xconfigure
.y
= client
.rect
.y();
1564 event
.xconfigure
.width
= client
.rect
.width();
1565 event
.xconfigure
.height
= client
.rect
.height();
1566 event
.xconfigure
.border_width
= client
.old_bw
;
1567 event
.xconfigure
.above
= frame
.window
;
1568 event
.xconfigure
.override_redirect
= False
;
1570 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1571 StructureNotifyMask
, &event
);
1572 screen
->updateNetizenConfigNotify(&event
);
1573 XFlush(blackbox
->getXDisplay());
1579 void BlackboxWindow::configureShape(void) {
1580 XShapeCombineShape(blackbox
->getXDisplay(), frame
.window
, ShapeBounding
,
1581 frame
.margin
.left
- frame
.border_w
,
1582 frame
.margin
.top
- frame
.border_w
,
1583 client
.window
, ShapeBounding
, ShapeSet
);
1586 XRectangle xrect
[2];
1588 if (decorations
& Decor_Titlebar
) {
1589 xrect
[0].x
= xrect
[0].y
= -frame
.border_w
;
1590 xrect
[0].width
= frame
.rect
.width();
1591 xrect
[0].height
= frame
.title_h
+ (frame
.border_w
* 2);
1595 if (decorations
& Decor_Handle
) {
1596 xrect
[1].x
= -frame
.border_w
;
1597 xrect
[1].y
= frame
.rect
.height() - frame
.margin
.bottom
+
1598 frame
.mwm_border_w
- frame
.border_w
;
1599 xrect
[1].width
= frame
.rect
.width();
1600 xrect
[1].height
= frame
.handle_h
+ (frame
.border_w
* 2);
1604 XShapeCombineRectangles(blackbox
->getXDisplay(), frame
.window
,
1605 ShapeBounding
, 0, 0, xrect
, num
,
1606 ShapeUnion
, Unsorted
);
1611 bool BlackboxWindow::setInputFocus(void) {
1612 if (flags
.focused
) return True
;
1614 assert(flags
.stuck
|| // window must be on the current workspace or sticky
1615 blackbox_attrib
.workspace
== screen
->getCurrentWorkspaceID());
1618 We only do this check for normal windows and dialogs because other windows
1619 do this on purpose, such as kde's kicker, and we don't want to go moving
1622 if (window_type
== Type_Normal
|| window_type
== Type_Dialog
)
1623 if (! frame
.rect
.intersects(screen
->getRect())) {
1624 // client is outside the screen, move it to the center
1625 configure((screen
->getWidth() - frame
.rect
.width()) / 2,
1626 (screen
->getHeight() - frame
.rect
.height()) / 2,
1627 frame
.rect
.width(), frame
.rect
.height());
1630 if (client
.transientList
.size() > 0) {
1631 // transfer focus to any modal transients
1632 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1633 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1634 if ((*it
)->flags
.modal
) return (*it
)->setInputFocus();
1638 if (focus_mode
== F_LocallyActive
|| focus_mode
== F_Passive
) {
1639 XSetInputFocus(blackbox
->getXDisplay(), client
.window
,
1640 RevertToPointerRoot
, CurrentTime
);
1642 /* we could set the focus to none, since the window doesn't accept focus,
1643 * but we shouldn't set focus to nothing since this would surely make
1649 if (flags
.send_focus_message
) {
1651 ce
.xclient
.type
= ClientMessage
;
1652 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1653 ce
.xclient
.display
= blackbox
->getXDisplay();
1654 ce
.xclient
.window
= client
.window
;
1655 ce
.xclient
.format
= 32;
1656 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_take_focus
);
1657 ce
.xclient
.data
.l
[1] = blackbox
->getLastTime();
1658 ce
.xclient
.data
.l
[2] = 0l;
1659 ce
.xclient
.data
.l
[3] = 0l;
1660 ce
.xclient
.data
.l
[4] = 0l;
1661 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1663 XFlush(blackbox
->getXDisplay());
1670 void BlackboxWindow::iconify(void) {
1671 if (flags
.iconic
) return;
1673 // We don't need to worry about resizing because resizing always grabs the X
1674 // server. This should only ever happen if using opaque moving.
1678 if (windowmenu
) windowmenu
->hide();
1681 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1682 * we need to clear the event mask on client.window for a split second.
1683 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1684 * split second, leaving us with a ghost window... so, we need to do this
1685 * while the X server is grabbed
1687 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1688 StructureNotifyMask
;
1689 XGrabServer(blackbox
->getXDisplay());
1690 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1691 event_mask
& ~StructureNotifyMask
);
1692 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1693 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1694 XUngrabServer(blackbox
->getXDisplay());
1696 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1697 flags
.visible
= False
;
1698 flags
.iconic
= True
;
1700 setState(IconicState
);
1702 screen
->getWorkspace(blackbox_attrib
.workspace
)->removeWindow(this);
1704 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
1705 if (i
!= blackbox_attrib
.workspace
)
1706 screen
->getWorkspace(i
)->removeWindow(this, True
);
1709 if (isTransient()) {
1710 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1711 ! client
.transient_for
->flags
.iconic
) {
1712 // iconify our transient_for
1713 client
.transient_for
->iconify();
1717 screen
->addIcon(this);
1719 if (client
.transientList
.size() > 0) {
1720 // iconify all transients
1721 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1722 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1723 if (! (*it
)->flags
.iconic
) (*it
)->iconify();
1726 screen
->updateStackingList();
1730 void BlackboxWindow::show(void) {
1731 flags
.visible
= True
;
1732 flags
.iconic
= False
;
1734 current_state
= (flags
.shaded
) ? IconicState
: NormalState
;
1735 setState(current_state
);
1737 XMapWindow(blackbox
->getXDisplay(), client
.window
);
1738 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
1739 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
1744 XTranslateCoordinates(blackbox
->getXDisplay(), client
.window
,
1745 screen
->getRootWindow(),
1746 0, 0, &real_x
, &real_y
, &child
);
1747 fprintf(stderr
, "%s -- assumed: (%d, %d), real: (%d, %d)\n", getTitle(),
1748 client
.rect
.left(), client
.rect
.top(), real_x
, real_y
);
1749 assert(client
.rect
.left() == real_x
&& client
.rect
.top() == real_y
);
1754 void BlackboxWindow::deiconify(bool reassoc
, bool raise
) {
1755 if (flags
.iconic
|| reassoc
)
1756 screen
->reassociateWindow(this, BSENTINEL
, False
);
1757 else if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID())
1762 // reassociate and deiconify all transients
1763 if (reassoc
&& client
.transientList
.size() > 0) {
1764 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1765 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1766 (*it
)->deiconify(True
, False
);
1770 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1774 void BlackboxWindow::close(void) {
1776 ce
.xclient
.type
= ClientMessage
;
1777 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1778 ce
.xclient
.display
= blackbox
->getXDisplay();
1779 ce
.xclient
.window
= client
.window
;
1780 ce
.xclient
.format
= 32;
1781 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_delete_window
);
1782 ce
.xclient
.data
.l
[1] = CurrentTime
;
1783 ce
.xclient
.data
.l
[2] = 0l;
1784 ce
.xclient
.data
.l
[3] = 0l;
1785 ce
.xclient
.data
.l
[4] = 0l;
1786 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
, NoEventMask
, &ce
);
1787 XFlush(blackbox
->getXDisplay());
1791 void BlackboxWindow::withdraw(void) {
1792 // We don't need to worry about resizing because resizing always grabs the X
1793 // server. This should only ever happen if using opaque moving.
1797 flags
.visible
= False
;
1798 flags
.iconic
= False
;
1800 setState(current_state
);
1802 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1804 XGrabServer(blackbox
->getXDisplay());
1806 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1807 StructureNotifyMask
;
1808 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1809 event_mask
& ~StructureNotifyMask
);
1810 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1811 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1813 XUngrabServer(blackbox
->getXDisplay());
1815 if (windowmenu
) windowmenu
->hide();
1819 void BlackboxWindow::maximize(unsigned int button
) {
1820 // We don't need to worry about resizing because resizing always grabs the X
1821 // server. This should only ever happen if using opaque moving.
1825 // handle case where menu is open then the max button is used instead
1826 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
1828 if (flags
.maximized
) {
1829 flags
.maximized
= 0;
1831 blackbox_attrib
.flags
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1832 blackbox_attrib
.attrib
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1835 when a resize finishes, maximize(0) is called to clear any maximization
1836 flags currently set. Otherwise it still thinks it is maximized.
1837 so we do not need to call configure() because resizing will handle it
1839 if (! flags
.resizing
)
1840 configure(blackbox_attrib
.premax_x
, blackbox_attrib
.premax_y
,
1841 blackbox_attrib
.premax_w
, blackbox_attrib
.premax_h
);
1843 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
1844 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
1846 redrawAllButtons(); // in case it is not called in configure()
1847 setState(current_state
);
1851 blackbox_attrib
.premax_x
= frame
.rect
.x();
1852 blackbox_attrib
.premax_y
= frame
.rect
.y();
1853 blackbox_attrib
.premax_w
= frame
.rect
.width();
1854 // use client.rect so that clients can be restored even if shaded
1855 blackbox_attrib
.premax_h
=
1856 client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
;
1859 if (screen
->isXineramaActive() && blackbox
->doXineramaMaximizing()) {
1860 // find the area to use
1861 RectList availableAreas
= screen
->allAvailableAreas();
1862 RectList::iterator it
, end
= availableAreas
.end();
1864 for (it
= availableAreas
.begin(); it
!= end
; ++it
)
1865 if (it
->intersects(frame
.rect
)) break;
1866 if (it
== end
) // the window isn't inside an area
1867 it
= availableAreas
.begin(); // so just default to the first one
1869 frame
.changing
= *it
;
1872 frame
.changing
= screen
->availableArea();
1876 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1877 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1881 blackbox_attrib
.flags
|= AttribMaxVert
;
1882 blackbox_attrib
.attrib
|= AttribMaxVert
;
1884 frame
.changing
.setX(frame
.rect
.x());
1885 frame
.changing
.setWidth(frame
.rect
.width());
1889 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1890 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1892 frame
.changing
.setY(frame
.rect
.y());
1893 frame
.changing
.setHeight(frame
.rect
.height());
1900 blackbox_attrib
.flags
^= AttribShaded
;
1901 blackbox_attrib
.attrib
^= AttribShaded
;
1902 flags
.shaded
= False
;
1905 flags
.maximized
= button
;
1907 configure(frame
.changing
.x(), frame
.changing
.y(),
1908 frame
.changing
.width(), frame
.changing
.height());
1910 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1911 redrawAllButtons(); // in case it is not called in configure()
1912 setState(current_state
);
1916 // re-maximizes the window to take into account availableArea changes
1917 void BlackboxWindow::remaximize(void) {
1919 // we only update the window's attributes otherwise we lose the shade bit
1920 switch(flags
.maximized
) {
1922 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1923 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1927 blackbox_attrib
.flags
|= AttribMaxVert
;
1928 blackbox_attrib
.attrib
|= AttribMaxVert
;
1932 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1933 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1939 // save the original dimensions because maximize will wipe them out
1940 int premax_x
= blackbox_attrib
.premax_x
,
1941 premax_y
= blackbox_attrib
.premax_y
,
1942 premax_w
= blackbox_attrib
.premax_w
,
1943 premax_h
= blackbox_attrib
.premax_h
;
1945 unsigned int button
= flags
.maximized
;
1946 flags
.maximized
= 0; // trick maximize() into working
1949 // restore saved values
1950 blackbox_attrib
.premax_x
= premax_x
;
1951 blackbox_attrib
.premax_y
= premax_y
;
1952 blackbox_attrib
.premax_w
= premax_w
;
1953 blackbox_attrib
.premax_h
= premax_h
;
1957 void BlackboxWindow::setWorkspace(unsigned int n
) {
1958 blackbox_attrib
.flags
|= AttribWorkspace
;
1959 blackbox_attrib
.workspace
= n
;
1960 if (n
== BSENTINEL
) { // iconified window
1962 we set the workspace to 'all workspaces' so that taskbars will show the
1963 window. otherwise, it made uniconifying a window imposible without the
1964 blackbox workspace menu
1968 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
, n
);
1972 void BlackboxWindow::shade(void) {
1974 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1975 frame
.inside_w
, frame
.inside_h
);
1976 flags
.shaded
= False
;
1977 blackbox_attrib
.flags
^= AttribShaded
;
1978 blackbox_attrib
.attrib
^= AttribShaded
;
1980 setState(NormalState
);
1982 // set the frame rect to the normal size
1983 frame
.rect
.setHeight(client
.rect
.height() + frame
.margin
.top
+
1984 frame
.margin
.bottom
);
1986 if (! (decorations
& Decor_Titlebar
))
1987 return; // can't shade it without a titlebar!
1989 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1990 frame
.inside_w
, frame
.title_h
);
1991 flags
.shaded
= True
;
1992 blackbox_attrib
.flags
|= AttribShaded
;
1993 blackbox_attrib
.attrib
|= AttribShaded
;
1995 setState(IconicState
);
1997 // set the frame rect to the shaded size
1998 frame
.rect
.setHeight(frame
.title_h
+ (frame
.border_w
* 2));
2004 * (Un)Sticks a window and its relatives.
2006 void BlackboxWindow::stick(void) {
2008 blackbox_attrib
.flags
^= AttribOmnipresent
;
2009 blackbox_attrib
.attrib
^= AttribOmnipresent
;
2011 flags
.stuck
= False
;
2013 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
2014 if (i
!= blackbox_attrib
.workspace
)
2015 screen
->getWorkspace(i
)->removeWindow(this, True
);
2018 screen
->reassociateWindow(this, BSENTINEL
, True
);
2019 // temporary fix since sticky windows suck. set the hint to what we
2020 // actually hold in our data.
2021 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
2022 blackbox_attrib
.workspace
);
2024 setState(current_state
);
2028 blackbox_attrib
.flags
|= AttribOmnipresent
;
2029 blackbox_attrib
.attrib
|= AttribOmnipresent
;
2031 // temporary fix since sticky windows suck. set the hint to a different
2032 // value than that contained in the class' data.
2033 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
2036 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
2037 if (i
!= blackbox_attrib
.workspace
)
2038 screen
->getWorkspace(i
)->addWindow(this, False
, True
);
2040 setState(current_state
);
2043 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
2044 client
.transient_for
->isStuck() != flags
.stuck
)
2045 client
.transient_for
->stick();
2046 // go down the chain
2047 BlackboxWindowList::iterator it
;
2048 const BlackboxWindowList::iterator end
= client
.transientList
.end();
2049 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
2050 if ((*it
)->isStuck() != flags
.stuck
)
2055 void BlackboxWindow::redrawWindowFrame(void) const {
2056 if (decorations
& Decor_Titlebar
) {
2057 if (flags
.focused
) {
2059 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2060 frame
.title
, frame
.ftitle
);
2062 XSetWindowBackground(blackbox
->getXDisplay(),
2063 frame
.title
, frame
.ftitle_pixel
);
2066 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2067 frame
.title
, frame
.utitle
);
2069 XSetWindowBackground(blackbox
->getXDisplay(),
2070 frame
.title
, frame
.utitle_pixel
);
2072 XClearWindow(blackbox
->getXDisplay(), frame
.title
);
2078 if (decorations
& Decor_Handle
) {
2079 if (flags
.focused
) {
2081 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2082 frame
.handle
, frame
.fhandle
);
2084 XSetWindowBackground(blackbox
->getXDisplay(),
2085 frame
.handle
, frame
.fhandle_pixel
);
2088 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2089 frame
.left_grip
, frame
.fgrip
);
2090 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2091 frame
.right_grip
, frame
.fgrip
);
2093 XSetWindowBackground(blackbox
->getXDisplay(),
2094 frame
.left_grip
, frame
.fgrip_pixel
);
2095 XSetWindowBackground(blackbox
->getXDisplay(),
2096 frame
.right_grip
, frame
.fgrip_pixel
);
2100 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2101 frame
.handle
, frame
.uhandle
);
2103 XSetWindowBackground(blackbox
->getXDisplay(),
2104 frame
.handle
, frame
.uhandle_pixel
);
2107 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2108 frame
.left_grip
, frame
.ugrip
);
2109 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2110 frame
.right_grip
, frame
.ugrip
);
2112 XSetWindowBackground(blackbox
->getXDisplay(),
2113 frame
.left_grip
, frame
.ugrip_pixel
);
2114 XSetWindowBackground(blackbox
->getXDisplay(),
2115 frame
.right_grip
, frame
.ugrip_pixel
);
2118 XClearWindow(blackbox
->getXDisplay(), frame
.handle
);
2119 XClearWindow(blackbox
->getXDisplay(), frame
.left_grip
);
2120 XClearWindow(blackbox
->getXDisplay(), frame
.right_grip
);
2123 if (decorations
& Decor_Border
) {
2125 XSetWindowBorder(blackbox
->getXDisplay(),
2126 frame
.plate
, frame
.fborder_pixel
);
2128 XSetWindowBorder(blackbox
->getXDisplay(),
2129 frame
.plate
, frame
.uborder_pixel
);
2134 void BlackboxWindow::setFocusFlag(bool focus
) {
2135 // only focus a window if it is visible
2136 if (focus
&& ! flags
.visible
)
2139 flags
.focused
= focus
;
2141 redrawWindowFrame();
2144 blackbox
->setFocusedWindow(this);
2146 if (! flags
.iconic
) {
2147 // iconic windows arent in a workspace menu!
2149 screen
->getCurrentWorkspace()->setFocused(this, isFocused());
2151 screen
->getWorkspace(blackbox_attrib
.workspace
)->
2152 setFocused(this, flags
.focused
);
2157 void BlackboxWindow::installColormap(bool install
) {
2158 int i
= 0, ncmap
= 0;
2159 Colormap
*cmaps
= XListInstalledColormaps(blackbox
->getXDisplay(),
2160 client
.window
, &ncmap
);
2162 XWindowAttributes wattrib
;
2163 if (XGetWindowAttributes(blackbox
->getXDisplay(),
2164 client
.window
, &wattrib
)) {
2166 // install the window's colormap
2167 for (i
= 0; i
< ncmap
; i
++) {
2168 if (*(cmaps
+ i
) == wattrib
.colormap
)
2169 // this window is using an installed color map... do not install
2172 // otherwise, install the window's colormap
2174 XInstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2176 // uninstall the window's colormap
2177 for (i
= 0; i
< ncmap
; i
++) {
2178 if (*(cmaps
+ i
) == wattrib
.colormap
)
2179 // we found the colormap to uninstall
2180 XUninstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2190 void BlackboxWindow::setAllowedActions(void) {
2194 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_shade
);
2195 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_change_desktop
);
2196 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_close
);
2198 if (functions
& Func_Move
)
2199 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_move
);
2200 if (functions
& Func_Resize
)
2201 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_resize
);
2202 if (functions
& Func_Maximize
) {
2203 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_horz
);
2204 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_vert
);
2207 xatom
->setValue(client
.window
, XAtom::net_wm_allowed_actions
, XAtom::atom
,
2212 void BlackboxWindow::setState(unsigned long new_state
) {
2213 current_state
= new_state
;
2215 unsigned long state
[2];
2216 state
[0] = current_state
;
2218 xatom
->setValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
, state
, 2);
2220 xatom
->setValue(client
.window
, XAtom::blackbox_attributes
,
2221 XAtom::blackbox_attributes
, (unsigned long *)&blackbox_attrib
,
2222 PropBlackboxAttributesElements
);
2227 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_modal
);
2229 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_shaded
);
2231 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_hidden
);
2232 if (flags
.skip_taskbar
)
2233 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
);
2234 if (flags
.skip_pager
)
2235 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_pager
);
2236 if (flags
.fullscreen
)
2237 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_fullscreen
);
2238 if (flags
.maximized
== 1 || flags
.maximized
== 2)
2239 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_vert
);
2240 if (flags
.maximized
== 1 || flags
.maximized
== 3)
2241 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_horz
);
2242 xatom
->setValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
2247 bool BlackboxWindow::getState(void) {
2248 bool ret
= xatom
->getValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
,
2250 if (! ret
) current_state
= 0;
2255 void BlackboxWindow::restoreAttributes(void) {
2256 unsigned long num
= PropBlackboxAttributesElements
;
2257 BlackboxAttributes
*net
;
2258 if (! xatom
->getValue(client
.window
, XAtom::blackbox_attributes
,
2259 XAtom::blackbox_attributes
, num
,
2260 (unsigned long **)&net
))
2262 if (num
< PropBlackboxAttributesElements
) {
2267 if (net
->flags
& AttribShaded
&& net
->attrib
& AttribShaded
) {
2268 flags
.shaded
= False
;
2269 unsigned long orig_state
= current_state
;
2273 At this point in the life of a window, current_state should only be set
2274 to IconicState if the window was an *icon*, not if it was shaded.
2276 if (orig_state
!= IconicState
)
2277 current_state
= WithdrawnState
;
2280 if (net
->workspace
!= screen
->getCurrentWorkspaceID() &&
2281 net
->workspace
< screen
->getWorkspaceCount())
2282 screen
->reassociateWindow(this, net
->workspace
, True
);
2284 if ((blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID()) &&
2285 (blackbox_attrib
.workspace
< screen
->getWorkspaceCount())) {
2286 // set to WithdrawnState so it will be mapped on the new workspace
2287 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2288 } else if (current_state
== WithdrawnState
) {
2289 // the window is on this workspace and is Withdrawn, so it is waiting to
2291 current_state
= NormalState
;
2294 if (net
->flags
& AttribOmnipresent
&& net
->attrib
& AttribOmnipresent
&&
2298 // if the window was on another workspace, it was going to be hidden. this
2299 // specifies that the window should be mapped since it is sticky.
2300 if (current_state
== WithdrawnState
) current_state
= NormalState
;
2303 if (net
->flags
& AttribMaxHoriz
|| net
->flags
& AttribMaxVert
) {
2304 int x
= net
->premax_x
, y
= net
->premax_y
;
2305 unsigned int w
= net
->premax_w
, h
= net
->premax_h
;
2306 flags
.maximized
= 0;
2309 if ((net
->flags
& AttribMaxHoriz
) &&
2310 (net
->flags
& AttribMaxVert
))
2311 m
= (net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
2312 else if (net
->flags
& AttribMaxVert
)
2313 m
= (net
->attrib
& AttribMaxVert
) ? 2 : 0;
2314 else if (net
->flags
& AttribMaxHoriz
)
2315 m
= (net
->attrib
& AttribMaxHoriz
) ? 3 : 0;
2319 blackbox_attrib
.premax_x
= x
;
2320 blackbox_attrib
.premax_y
= y
;
2321 blackbox_attrib
.premax_w
= w
;
2322 blackbox_attrib
.premax_h
= h
;
2325 if (net
->flags
& AttribDecoration
) {
2326 switch (net
->decoration
) {
2331 /* since tools only let you toggle this anyways, we'll just make that all
2332 it supports for now.
2343 // with the state set it will then be the map event's job to read the
2344 // window's state and behave accordingly
2351 * Positions the Rect r according the the client window position and
2354 void BlackboxWindow::applyGravity(Rect
&r
) {
2355 // apply horizontal window gravity
2356 switch (client
.win_gravity
) {
2358 case NorthWestGravity
:
2359 case SouthWestGravity
:
2361 r
.setX(client
.rect
.x());
2367 r
.setX(client
.rect
.x() - (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2370 case NorthEastGravity
:
2371 case SouthEastGravity
:
2373 r
.setX(client
.rect
.x() - frame
.margin
.left
- frame
.margin
.right
+ 2);
2378 r
.setX(client
.rect
.x() - frame
.margin
.left
);
2382 // apply vertical window gravity
2383 switch (client
.win_gravity
) {
2385 case NorthWestGravity
:
2386 case NorthEastGravity
:
2388 r
.setY(client
.rect
.y());
2394 r
.setY(client
.rect
.y() - (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2397 case SouthWestGravity
:
2398 case SouthEastGravity
:
2400 r
.setY(client
.rect
.y() - frame
.margin
.top
- frame
.margin
.bottom
+ 2);
2405 r
.setY(client
.rect
.y() - frame
.margin
.top
);
2412 * The reverse of the applyGravity function.
2414 * Positions the Rect r according to the frame window position and
2417 void BlackboxWindow::restoreGravity(Rect
&r
) {
2418 // restore horizontal window gravity
2419 switch (client
.win_gravity
) {
2421 case NorthWestGravity
:
2422 case SouthWestGravity
:
2424 r
.setX(frame
.rect
.x());
2430 r
.setX(frame
.rect
.x() + (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2433 case NorthEastGravity
:
2434 case SouthEastGravity
:
2436 r
.setX(frame
.rect
.x() + frame
.margin
.left
+ frame
.margin
.right
- 2);
2441 r
.setX(frame
.rect
.x() + frame
.margin
.left
);
2445 // restore vertical window gravity
2446 switch (client
.win_gravity
) {
2448 case NorthWestGravity
:
2449 case NorthEastGravity
:
2451 r
.setY(frame
.rect
.y());
2457 r
.setY(frame
.rect
.y() + (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2460 case SouthWestGravity
:
2461 case SouthEastGravity
:
2463 r
.setY(frame
.rect
.y() + frame
.margin
.top
+ frame
.margin
.bottom
- 2);
2468 r
.setY(frame
.rect
.y() + frame
.margin
.top
);
2474 void BlackboxWindow::redrawLabel(void) const {
2475 if (flags
.focused
) {
2477 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2478 frame
.label
, frame
.flabel
);
2480 XSetWindowBackground(blackbox
->getXDisplay(),
2481 frame
.label
, frame
.flabel_pixel
);
2484 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2485 frame
.label
, frame
.ulabel
);
2487 XSetWindowBackground(blackbox
->getXDisplay(),
2488 frame
.label
, frame
.ulabel_pixel
);
2490 XClearWindow(blackbox
->getXDisplay(), frame
.label
);
2492 WindowStyle
*style
= screen
->getWindowStyle();
2494 int pos
= frame
.bevel_w
* 2;
2495 style
->doJustify(client
.title
.c_str(), pos
, frame
.label_w
, frame
.bevel_w
* 4);
2496 style
->font
->drawString(frame
.label
, pos
, 1,
2497 (flags
.focused
? style
->l_text_focus
:
2498 style
->l_text_unfocus
),
2503 void BlackboxWindow::redrawAllButtons(void) const {
2504 if (frame
.iconify_button
) redrawIconifyButton(False
);
2505 if (frame
.maximize_button
) redrawMaximizeButton(flags
.maximized
);
2506 if (frame
.close_button
) redrawCloseButton(False
);
2510 void BlackboxWindow::redrawIconifyButton(bool pressed
) const {
2512 if (flags
.focused
) {
2514 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2515 frame
.iconify_button
, frame
.fbutton
);
2517 XSetWindowBackground(blackbox
->getXDisplay(),
2518 frame
.iconify_button
, frame
.fbutton_pixel
);
2521 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2522 frame
.iconify_button
, frame
.ubutton
);
2524 XSetWindowBackground(blackbox
->getXDisplay(), frame
.iconify_button
,
2525 frame
.ubutton_pixel
);
2529 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2530 frame
.iconify_button
, frame
.pbutton
);
2532 XSetWindowBackground(blackbox
->getXDisplay(),
2533 frame
.iconify_button
, frame
.pbutton_pixel
);
2535 XClearWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
2537 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2538 screen
->getWindowStyle()->b_pic_unfocus
);
2539 XDrawRectangle(blackbox
->getXDisplay(), frame
.iconify_button
, pen
.gc(),
2540 2, (frame
.button_w
- 5), (frame
.button_w
- 5), 2);
2544 void BlackboxWindow::redrawMaximizeButton(bool pressed
) const {
2546 if (flags
.focused
) {
2548 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2549 frame
.maximize_button
, frame
.fbutton
);
2551 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2552 frame
.fbutton_pixel
);
2555 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2556 frame
.maximize_button
, frame
.ubutton
);
2558 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2559 frame
.ubutton_pixel
);
2563 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2564 frame
.maximize_button
, frame
.pbutton
);
2566 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2567 frame
.pbutton_pixel
);
2569 XClearWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
2571 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2572 screen
->getWindowStyle()->b_pic_unfocus
);
2573 XDrawRectangle(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2574 2, 2, (frame
.button_w
- 5), (frame
.button_w
- 5));
2575 XDrawLine(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2576 2, 3, (frame
.button_w
- 3), 3);
2580 void BlackboxWindow::redrawCloseButton(bool pressed
) const {
2582 if (flags
.focused
) {
2584 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2587 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2588 frame
.fbutton_pixel
);
2591 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2594 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2595 frame
.ubutton_pixel
);
2599 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2600 frame
.close_button
, frame
.pbutton
);
2602 XSetWindowBackground(blackbox
->getXDisplay(),
2603 frame
.close_button
, frame
.pbutton_pixel
);
2605 XClearWindow(blackbox
->getXDisplay(), frame
.close_button
);
2607 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2608 screen
->getWindowStyle()->b_pic_unfocus
);
2609 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2610 2, 2, (frame
.button_w
- 3), (frame
.button_w
- 3));
2611 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2612 2, (frame
.button_w
- 3), (frame
.button_w
- 3), 2);
2616 void BlackboxWindow::mapRequestEvent(const XMapRequestEvent
*re
) {
2617 if (re
->window
!= client
.window
)
2621 fprintf(stderr
, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2626 Even though the window wants to be shown, if it is not on the current
2627 workspace, then it isn't going to be shown right now.
2629 if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID() &&
2630 blackbox_attrib
.workspace
< screen
->getWorkspaceCount())
2631 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2633 switch (current_state
) {
2638 case WithdrawnState
:
2647 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2649 if (! blackbox
->isStartup()) {
2650 XSync(blackbox
->getXDisplay(), False
); // make sure the frame is mapped
2651 if (screen
->doFocusNew() || (isTransient() && getTransientFor() &&
2652 getTransientFor()->isFocused())) {
2655 if (screen
->getPlacementPolicy() == BScreen::ClickMousePlacement
) {
2659 XQueryPointer(blackbox
->getXDisplay(), screen
->getRootWindow(),
2660 &r
, &c
, &rx
, &ry
, &x
, &y
, &m
);
2670 void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent
*ue
) {
2671 if (ue
->window
!= client
.window
)
2675 fprintf(stderr
, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2679 screen
->unmanageWindow(this, False
);
2683 void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent
*de
) {
2684 if (de
->window
!= client
.window
)
2688 fprintf(stderr
, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2692 screen
->unmanageWindow(this, False
);
2696 void BlackboxWindow::reparentNotifyEvent(const XReparentEvent
*re
) {
2697 if (re
->window
!= client
.window
|| re
->parent
== frame
.plate
)
2701 fprintf(stderr
, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2702 "0x%lx.\n", client
.window
, re
->parent
);
2707 XPutBackEvent(blackbox
->getXDisplay(), &ev
);
2708 screen
->unmanageWindow(this, True
);
2712 void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent
*pe
) {
2713 if (pe
->state
== PropertyDelete
|| ! validateClient())
2717 fprintf(stderr
, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n",
2723 case XA_WM_CLIENT_MACHINE
:
2727 case XA_WM_TRANSIENT_FOR
: {
2728 bool s
= flags
.stuck
;
2730 // determine if this is a transient window
2733 if (flags
.stuck
!= s
) stick();
2735 // adjust the window decorations based on transience
2736 if (isTransient()) {
2737 functions
&= ~Func_Maximize
;
2738 setAllowedActions();
2750 case XA_WM_ICON_NAME
:
2752 if (flags
.iconic
) screen
->propagateWindowName(this);
2755 case XAtom::net_wm_name
:
2759 if (decorations
& Decor_Titlebar
)
2762 screen
->propagateWindowName(this);
2765 case XA_WM_NORMAL_HINTS
: {
2768 if ((client
.normal_hint_flags
& PMinSize
) &&
2769 (client
.normal_hint_flags
& PMaxSize
)) {
2770 // the window now can/can't resize itself, so the buttons need to be
2773 if (client
.max_width
<= client
.min_width
&&
2774 client
.max_height
<= client
.min_height
) {
2775 functions
&= ~(Func_Resize
| Func_Maximize
);
2777 if (! isTransient())
2778 functions
|= Func_Maximize
;
2779 functions
|= Func_Resize
;
2782 setAllowedActions();
2786 Rect old_rect
= frame
.rect
;
2790 if (old_rect
!= frame
.rect
)
2797 if (pe
->atom
== xatom
->getAtom(XAtom::wm_protocols
)) {
2800 if ((decorations
& Decor_Close
) && (! frame
.close_button
)) {
2801 createCloseButton();
2802 if (decorations
& Decor_Titlebar
) {
2803 positionButtons(True
);
2804 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
2806 if (windowmenu
) windowmenu
->reconfigure();
2808 } else if (pe
->atom
== xatom
->getAtom(XAtom::net_wm_strut
)) {
2817 void BlackboxWindow::exposeEvent(const XExposeEvent
*ee
) {
2819 fprintf(stderr
, "BlackboxWindow::exposeEvent() for 0x%lx\n", client
.window
);
2822 if (frame
.label
== ee
->window
&& (decorations
& Decor_Titlebar
))
2824 else if (frame
.close_button
== ee
->window
)
2825 redrawCloseButton(False
);
2826 else if (frame
.maximize_button
== ee
->window
)
2827 redrawMaximizeButton(flags
.maximized
);
2828 else if (frame
.iconify_button
== ee
->window
)
2829 redrawIconifyButton(False
);
2833 void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent
*cr
) {
2834 if (cr
->window
!= client
.window
|| flags
.iconic
)
2837 if (cr
->value_mask
& CWBorderWidth
)
2838 client
.old_bw
= cr
->border_width
;
2840 if (cr
->value_mask
& (CWX
| CWY
| CWWidth
| CWHeight
)) {
2841 Rect req
= frame
.rect
;
2843 if (cr
->value_mask
& (CWX
| CWY
)) {
2844 if (cr
->value_mask
& CWX
)
2845 client
.rect
.setX(cr
->x
);
2846 if (cr
->value_mask
& CWY
)
2847 client
.rect
.setY(cr
->y
);
2852 if (cr
->value_mask
& CWWidth
)
2853 req
.setWidth(cr
->width
+ frame
.margin
.left
+ frame
.margin
.right
);
2855 if (cr
->value_mask
& CWHeight
)
2856 req
.setHeight(cr
->height
+ frame
.margin
.top
+ frame
.margin
.bottom
);
2858 configure(req
.x(), req
.y(), req
.width(), req
.height());
2861 if (cr
->value_mask
& CWStackMode
&& !isDesktop()) {
2862 switch (cr
->detail
) {
2865 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2871 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2878 void BlackboxWindow::buttonPressEvent(const XButtonEvent
*be
) {
2880 fprintf(stderr
, "BlackboxWindow::buttonPressEvent() for 0x%lx\n",
2884 if (frame
.maximize_button
== be
->window
&& be
->button
<= 3) {
2885 redrawMaximizeButton(True
);
2886 } else if (be
->button
== 1 || (be
->button
== 3 && be
->state
== mod_mask
)) {
2887 if (! flags
.focused
)
2890 if (frame
.iconify_button
== be
->window
) {
2891 redrawIconifyButton(True
);
2892 } else if (frame
.close_button
== be
->window
) {
2893 redrawCloseButton(True
);
2894 } else if (frame
.plate
== be
->window
) {
2895 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2897 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2899 XAllowEvents(blackbox
->getXDisplay(), ReplayPointer
, be
->time
);
2901 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
2902 if (((be
->time
- lastButtonPressTime
) <=
2903 blackbox
->getDoubleClickInterval()) ||
2904 (be
->state
== ControlMask
)) {
2905 lastButtonPressTime
= 0;
2908 lastButtonPressTime
= be
->time
;
2912 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2914 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2916 } else if (be
->button
== 2 && (be
->window
!= frame
.iconify_button
) &&
2917 (be
->window
!= frame
.close_button
)) {
2918 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2919 } else if (windowmenu
&& be
->button
== 3 &&
2920 (frame
.title
== be
->window
|| frame
.label
== be
->window
||
2921 frame
.handle
== be
->window
|| frame
.window
== be
->window
)) {
2922 if (windowmenu
->isVisible()) {
2925 int mx
= be
->x_root
- windowmenu
->getWidth() / 2,
2926 my
= be
->y_root
- windowmenu
->getHeight() / 2;
2928 // snap the window menu into a corner/side if necessary
2929 int left_edge
, right_edge
, top_edge
, bottom_edge
;
2932 the " + (frame.border_w * 2) - 1" bits are to get the proper width
2933 and height of the menu, as the sizes returned by it do not include
2936 left_edge
= frame
.rect
.x();
2937 right_edge
= frame
.rect
.right() -
2938 (windowmenu
->getWidth() + (frame
.border_w
* 2) - 1);
2939 top_edge
= client
.rect
.top() - (frame
.border_w
+ frame
.mwm_border_w
);
2940 bottom_edge
= client
.rect
.bottom() -
2941 (windowmenu
->getHeight() + (frame
.border_w
* 2) - 1) +
2942 (frame
.border_w
+ frame
.mwm_border_w
);
2946 if (mx
> right_edge
)
2950 if (my
> bottom_edge
)
2953 windowmenu
->move(mx
, my
);
2955 XRaiseWindow(blackbox
->getXDisplay(), windowmenu
->getWindowID());
2956 XRaiseWindow(blackbox
->getXDisplay(),
2957 windowmenu
->getSendToMenu()->getWindowID());
2960 } else if (be
->button
== 4) {
2961 if ((be
->window
== frame
.label
||
2962 be
->window
== frame
.title
||
2963 be
->window
== frame
.maximize_button
||
2964 be
->window
== frame
.iconify_button
||
2965 be
->window
== frame
.close_button
) &&
2969 } else if (be
->button
== 5) {
2970 if ((be
->window
== frame
.label
||
2971 be
->window
== frame
.title
||
2972 be
->window
== frame
.maximize_button
||
2973 be
->window
== frame
.iconify_button
||
2974 be
->window
== frame
.close_button
) &&
2981 void BlackboxWindow::buttonReleaseEvent(const XButtonEvent
*re
) {
2983 fprintf(stderr
, "BlackboxWindow::buttonReleaseEvent() for 0x%lx\n",
2987 if (re
->window
== frame
.maximize_button
&&
2988 re
->button
>= 1 && re
->button
<= 3) {
2989 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2990 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2991 maximize(re
->button
);
2993 redrawMaximizeButton(flags
.maximized
);
2995 } else if (re
->window
== frame
.iconify_button
&& re
->button
== 1) {
2996 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2997 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
3000 redrawIconifyButton(False
);
3002 } else if (re
->window
== frame
.close_button
& re
->button
== 1) {
3003 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3004 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
)))
3006 redrawCloseButton(False
);
3007 } else if (flags
.moving
) {
3009 } else if (flags
.resizing
) {
3011 } else if (re
->window
== frame
.window
) {
3012 if (re
->button
== 2 && re
->state
== mod_mask
)
3013 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3019 void BlackboxWindow::beginMove(int x_root
, int y_root
) {
3020 assert(! (flags
.resizing
|| flags
.moving
));
3023 Only one window can be moved/resized at a time. If another window is already
3024 being moved or resized, then stop it before whating to work with this one.
3026 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3027 if (changing
&& changing
!= this) {
3028 if (changing
->flags
.moving
)
3029 changing
->endMove();
3030 else // if (changing->flags.resizing)
3031 changing
->endResize();
3034 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3035 PointerMotionMask
| ButtonReleaseMask
,
3036 GrabModeAsync
, GrabModeAsync
,
3037 None
, blackbox
->getMoveCursor(), CurrentTime
);
3039 if (windowmenu
&& windowmenu
->isVisible())
3042 flags
.moving
= True
;
3043 blackbox
->setChangingWindow(this);
3045 if (! screen
->doOpaqueMove()) {
3046 XGrabServer(blackbox
->getXDisplay());
3048 frame
.changing
= frame
.rect
;
3049 screen
->showPosition(frame
.changing
.x(), frame
.changing
.y());
3051 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3055 frame
.changing
.width() - 1,
3056 frame
.changing
.height() - 1);
3059 frame
.grab_x
= x_root
- frame
.rect
.x() - frame
.border_w
;
3060 frame
.grab_y
= y_root
- frame
.rect
.y() - frame
.border_w
;
3064 void BlackboxWindow::doMove(int x_root
, int y_root
) {
3065 assert(flags
.moving
);
3066 assert(blackbox
->getChangingWindow() == this);
3068 int dx
= x_root
- frame
.grab_x
, dy
= y_root
- frame
.grab_y
;
3069 dx
-= frame
.border_w
;
3070 dy
-= frame
.border_w
;
3072 doWindowSnapping(dx
, dy
);
3074 if (screen
->doOpaqueMove()) {
3075 if (screen
->doWorkspaceWarping())
3076 doWorkspaceWarping(x_root
, y_root
, dx
);
3078 configure(dx
, dy
, frame
.rect
.width(), frame
.rect
.height());
3080 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3084 frame
.changing
.width() - 1,
3085 frame
.changing
.height() - 1);
3087 if (screen
->doWorkspaceWarping())
3088 doWorkspaceWarping(x_root
, y_root
, dx
);
3090 frame
.changing
.setPos(dx
, dy
);
3092 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3096 frame
.changing
.width() - 1,
3097 frame
.changing
.height() - 1);
3100 screen
->showPosition(dx
, dy
);
3104 void BlackboxWindow::doWorkspaceWarping(int x_root
, int y_root
, int &dx
) {
3105 // workspace warping
3107 unsigned int dest
= screen
->getCurrentWorkspaceID();
3111 if (dest
> 0) dest
--;
3112 else dest
= screen
->getNumberOfWorkspaces() - 1;
3114 } else if (x_root
>= screen
->getRect().right()) {
3117 if (dest
< screen
->getNumberOfWorkspaces() - 1) dest
++;
3123 bool focus
= flags
.focused
; // had focus while moving?
3125 int dest_x
= x_root
;
3127 dest_x
+= screen
->getRect().width() - 1;
3128 dx
+= screen
->getRect().width() - 1;
3130 dest_x
-= screen
->getRect().width() - 1;
3131 dx
-= screen
->getRect().width() - 1;
3135 screen
->reassociateWindow(this, dest
, False
);
3136 screen
->changeWorkspaceID(dest
);
3138 if (screen
->doOpaqueMove())
3139 XGrabServer(blackbox
->getXDisplay());
3141 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3142 XWarpPointer(blackbox
->getXDisplay(), None
,
3143 screen
->getRootWindow(), 0, 0, 0, 0,
3145 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3146 PointerMotionMask
| ButtonReleaseMask
,
3147 GrabModeAsync
, GrabModeAsync
,
3148 None
, blackbox
->getMoveCursor(), CurrentTime
);
3150 if (screen
->doOpaqueMove())
3151 XUngrabServer(blackbox
->getXDisplay());
3159 void BlackboxWindow::doWindowSnapping(int &dx
, int &dy
) {
3160 // how much resistance to edges to provide
3161 const int resistance_size
= screen
->getResistanceSize();
3163 // how far away to snap
3164 const int snap_distance
= screen
->getSnapThreshold();
3166 // how to snap windows
3167 const int snap_to_windows
= screen
->getWindowToWindowSnap();
3168 const int snap_to_edges
= screen
->getWindowToEdgeSnap();
3169 // the amount of space away from the edge to provide resistance/snap
3170 const int snap_offset
= screen
->getSnapOffset();
3172 // find the geomeetery where the moving window currently is
3173 const Rect
&moving
= screen
->doOpaqueMove() ? frame
.rect
: frame
.changing
;
3176 const int wleft
= dx
,
3177 wright
= dx
+ frame
.rect
.width() - 1,
3179 wbottom
= dy
+ frame
.rect
.height() - 1;
3181 if (snap_to_windows
) {
3184 Workspace
*w
= screen
->getWorkspace(getWorkspaceNumber());
3187 // add windows on the workspace to the rect list
3188 const BlackboxWindowList
& stack_list
= w
->getStackingList();
3189 BlackboxWindowList::const_iterator st_it
, st_end
= stack_list
.end();
3190 for (st_it
= stack_list
.begin(); st_it
!= st_end
; ++st_it
)
3191 if (*st_it
!= this) // don't snap to ourself
3192 rectlist
.push_back( (*st_it
)->frameRect() );
3194 // add the toolbar and the slit to the rect list.
3195 // (only if they are not hidden)
3196 Toolbar
*tbar
= screen
->getToolbar();
3197 Slit
*slit
= screen
->getSlit();
3198 Rect tbar_rect
, slit_rect
;
3199 unsigned int bwidth
= screen
->getBorderWidth() * 2;
3201 if (! (screen
->doHideToolbar() || tbar
->isHidden())) {
3202 tbar_rect
.setRect(tbar
->getX(), tbar
->getY(), tbar
->getWidth() + bwidth
,
3203 tbar
->getHeight() + bwidth
);
3204 rectlist
.push_back(tbar_rect
);
3207 if (! slit
->isHidden()) {
3208 slit_rect
.setRect(slit
->getX(), slit
->getY(), slit
->getWidth() + bwidth
,
3209 slit
->getHeight() + bwidth
);
3210 rectlist
.push_back(slit_rect
);
3213 RectList::const_iterator it
, end
= rectlist
.end();
3214 for (it
= rectlist
.begin(); it
!= end
; ++it
) {
3215 bool snapped
= False
;
3216 const Rect
&winrect
= *it
;
3218 offsetrect
.setCoords(winrect
.left() - snap_offset
,
3219 winrect
.top() - snap_offset
,
3220 winrect
.right() + snap_offset
,
3221 winrect
.bottom() + snap_offset
);
3223 if (snap_to_windows
== BScreen::WindowResistance
)
3224 // if the window is already over top of this snap target, then
3225 // resistance is futile, so just ignore it
3226 if (winrect
.intersects(moving
))
3229 int dleft
, dright
, dtop
, dbottom
;
3231 // if the windows are in the same plane vertically
3232 if (wtop
>= (signed)(winrect
.y() - frame
.rect
.height() + 1) &&
3233 wtop
< (signed)(winrect
.y() + winrect
.height() - 1)) {
3235 if (snap_to_windows
== BScreen::WindowResistance
) {
3236 dleft
= wright
- offsetrect
.left();
3237 dright
= offsetrect
.right() - wleft
;
3239 // snap left of other window?
3240 if (dleft
>= 0 && dleft
< resistance_size
&&
3241 dleft
< (wright
- wleft
)) {
3242 dx
= offsetrect
.left() - frame
.rect
.width();
3245 // snap right of other window?
3246 else if (dright
>= 0 && dright
< resistance_size
&&
3247 dright
< (wright
- wleft
)) {
3248 dx
= offsetrect
.right() + 1;
3251 } else { // BScreen::WindowSnap
3252 dleft
= abs(wright
- offsetrect
.left());
3253 dright
= abs(wleft
- offsetrect
.right());
3255 // snap left of other window?
3256 if (dleft
< snap_distance
&& dleft
<= dright
) {
3257 dx
= offsetrect
.left() - frame
.rect
.width();
3260 // snap right of other window?
3261 else if (dright
< snap_distance
) {
3262 dx
= offsetrect
.right() + 1;
3268 if (screen
->getWindowCornerSnap()) {
3269 // try corner-snap to its other sides
3270 if (snap_to_windows
== BScreen::WindowResistance
) {
3271 dtop
= winrect
.top() - wtop
;
3272 dbottom
= wbottom
- winrect
.bottom();
3273 if (dtop
> 0 && dtop
< resistance_size
) {
3274 // if we're already past the top edge, then don't provide
3276 if (moving
.top() >= winrect
.top())
3278 } else if (dbottom
> 0 && dbottom
< resistance_size
) {
3279 // if we're already past the bottom edge, then don't provide
3281 if (moving
.bottom() <= winrect
.bottom())
3282 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
3284 } else { // BScreen::WindowSnap
3285 dtop
= abs(wtop
- winrect
.top());
3286 dbottom
= abs(wbottom
- winrect
.bottom());
3287 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3289 else if (dbottom
< snap_distance
)
3290 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
3298 // if the windows are on the same plane horizontally
3299 if (wleft
>= (signed)(winrect
.x() - frame
.rect
.width() + 1) &&
3300 wleft
< (signed)(winrect
.x() + winrect
.width() - 1)) {
3302 if (snap_to_windows
== BScreen::WindowResistance
) {
3303 dtop
= wbottom
- offsetrect
.top();
3304 dbottom
= offsetrect
.bottom() - wtop
;
3306 // snap top of other window?
3307 if (dtop
>= 0 && dtop
< resistance_size
&& dtop
< (wbottom
- wtop
)) {
3308 dy
= offsetrect
.top() - frame
.rect
.height();
3311 // snap bottom of other window?
3312 else if (dbottom
>= 0 && dbottom
< resistance_size
&&
3313 dbottom
< (wbottom
- wtop
)) {
3314 dy
= offsetrect
.bottom() + 1;
3317 } else { // BScreen::WindowSnap
3318 dtop
= abs(wbottom
- offsetrect
.top());
3319 dbottom
= abs(wtop
- offsetrect
.bottom());
3321 // snap top of other window?
3322 if (dtop
< snap_distance
&& dtop
<= dbottom
) {
3323 dy
= offsetrect
.top() - frame
.rect
.height();
3326 // snap bottom of other window?
3327 else if (dbottom
< snap_distance
) {
3328 dy
= offsetrect
.bottom() + 1;
3335 if (screen
->getWindowCornerSnap()) {
3336 // try corner-snap to its other sides
3337 if (snap_to_windows
== BScreen::WindowResistance
) {
3338 dleft
= winrect
.left() - wleft
;
3339 dright
= wright
- winrect
.right();
3340 if (dleft
> 0 && dleft
< resistance_size
) {
3341 // if we're already past the left edge, then don't provide
3343 if (moving
.left() >= winrect
.left())
3344 dx
= winrect
.left();
3345 } else if (dright
> 0 && dright
< resistance_size
) {
3346 // if we're already past the right edge, then don't provide
3348 if (moving
.right() <= winrect
.right())
3349 dx
= winrect
.right() - frame
.rect
.width() + 1;
3351 } else { // BScreen::WindowSnap
3352 dleft
= abs(wleft
- winrect
.left());
3353 dright
= abs(wright
- winrect
.right());
3354 if (dleft
< snap_distance
&& dleft
<= dright
)
3355 dx
= winrect
.left();
3356 else if (dright
< snap_distance
)
3357 dx
= winrect
.right() - frame
.rect
.width() + 1;
3367 if (snap_to_edges
) {
3370 // snap to the screen edges (and screen boundaries for xinerama)
3372 if (screen
->isXineramaActive() && blackbox
->doXineramaSnapping()) {
3373 rectlist
.insert(rectlist
.begin(),
3374 screen
->getXineramaAreas().begin(),
3375 screen
->getXineramaAreas().end());
3378 rectlist
.push_back(screen
->getRect());
3380 RectList::const_iterator it
, end
= rectlist
.end();
3381 for (it
= rectlist
.begin(); it
!= end
; ++it
) {
3382 const Rect
&srect
= *it
;
3384 offsetrect
.setCoords(srect
.left() + snap_offset
,
3385 srect
.top() + snap_offset
,
3386 srect
.right() - snap_offset
,
3387 srect
.bottom() - snap_offset
);
3389 if (snap_to_edges
== BScreen::WindowResistance
) {
3390 // if we're not in the rectangle then don't snap to it.
3391 if (! srect
.contains(moving
))
3393 } else { // BScreen::WindowSnap
3394 // if we're not in the rectangle then don't snap to it.
3395 if (! srect
.intersects(Rect(wleft
, wtop
, frame
.rect
.width(),
3396 frame
.rect
.height())))
3400 if (snap_to_edges
== BScreen::WindowResistance
) {
3401 int dleft
= offsetrect
.left() - wleft
,
3402 dright
= wright
- offsetrect
.right(),
3403 dtop
= offsetrect
.top() - wtop
,
3404 dbottom
= wbottom
- offsetrect
.bottom();
3407 if (dleft
> 0 && dleft
< resistance_size
)
3408 dx
= offsetrect
.left();
3410 else if (dright
> 0 && dright
< resistance_size
)
3411 dx
= offsetrect
.right() - frame
.rect
.width() + 1;
3414 if (dtop
> 0 && dtop
< resistance_size
)
3415 dy
= offsetrect
.top();
3417 else if (dbottom
> 0 && dbottom
< resistance_size
)
3418 dy
= offsetrect
.bottom() - frame
.rect
.height() + 1;
3419 } else { // BScreen::WindowSnap
3420 int dleft
= abs(wleft
- offsetrect
.left()),
3421 dright
= abs(wright
- offsetrect
.right()),
3422 dtop
= abs(wtop
- offsetrect
.top()),
3423 dbottom
= abs(wbottom
- offsetrect
.bottom());
3426 if (dleft
< snap_distance
&& dleft
<= dright
)
3427 dx
= offsetrect
.left();
3429 else if (dright
< snap_distance
)
3430 dx
= offsetrect
.right() - frame
.rect
.width() + 1;
3433 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3434 dy
= offsetrect
.top();
3436 else if (dbottom
< snap_distance
)
3437 dy
= offsetrect
.bottom() - frame
.rect
.height() + 1;
3444 void BlackboxWindow::endMove(void) {
3445 assert(flags
.moving
);
3446 assert(blackbox
->getChangingWindow() == this);
3448 flags
.moving
= False
;
3449 blackbox
->setChangingWindow(0);
3451 if (! screen
->doOpaqueMove()) {
3452 /* when drawing the rubber band, we need to make sure we only draw inside
3453 * the frame... frame.changing_* contain the new coords for the window,
3454 * so we need to subtract 1 from changing_w/changing_h every where we
3455 * draw the rubber band (for both moving and resizing)
3457 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3458 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3459 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3460 XUngrabServer(blackbox
->getXDisplay());
3462 configure(frame
.changing
.x(), frame
.changing
.y(),
3463 frame
.changing
.width(), frame
.changing
.height());
3465 configure(frame
.rect
.x(), frame
.rect
.y(),
3466 frame
.rect
.width(), frame
.rect
.height());
3468 screen
->hideGeometry();
3470 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3472 // if there are any left over motions from the move, drop them now
3473 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3475 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3480 void BlackboxWindow::beginResize(int x_root
, int y_root
, Corner dir
) {
3481 assert(! (flags
.resizing
|| flags
.moving
));
3484 Only one window can be moved/resized at a time. If another window is already
3485 being moved or resized, then stop it before whating to work with this one.
3487 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3488 if (changing
&& changing
!= this) {
3489 if (changing
->flags
.moving
)
3490 changing
->endMove();
3491 else // if (changing->flags.resizing)
3492 changing
->endResize();
3500 switch (resize_dir
) {
3503 cursor
= blackbox
->getLowerLeftAngleCursor();
3508 cursor
= blackbox
->getLowerRightAngleCursor();
3512 anchor
= BottomRight
;
3513 cursor
= blackbox
->getUpperLeftAngleCursor();
3517 anchor
= BottomLeft
;
3518 cursor
= blackbox
->getUpperRightAngleCursor();
3522 assert(false); // unhandled Corner
3523 return; // unreachable, for the compiler
3526 XGrabServer(blackbox
->getXDisplay());
3527 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3528 PointerMotionMask
| ButtonReleaseMask
,
3529 GrabModeAsync
, GrabModeAsync
, None
, cursor
, CurrentTime
);
3531 flags
.resizing
= True
;
3532 blackbox
->setChangingWindow(this);
3534 unsigned int gw
, gh
;
3535 frame
.changing
= frame
.rect
;
3537 constrain(anchor
, &gw
, &gh
);
3539 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3540 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3541 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3543 screen
->showGeometry(gw
, gh
);
3545 frame
.grab_x
= x_root
;
3546 frame
.grab_y
= y_root
;
3550 void BlackboxWindow::doResize(int x_root
, int y_root
) {
3551 assert(flags
.resizing
);
3552 assert(blackbox
->getChangingWindow() == this);
3554 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3555 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3556 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3558 unsigned int gw
, gh
;
3561 switch (resize_dir
) {
3564 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3565 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3569 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3570 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3573 anchor
= BottomRight
;
3574 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3575 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3578 anchor
= BottomLeft
;
3579 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3580 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3584 assert(false); // unhandled Corner
3585 return; // unreachable, for the compiler
3588 constrain(anchor
, &gw
, &gh
);
3590 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3591 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3592 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3594 screen
->showGeometry(gw
, gh
);
3598 void BlackboxWindow::endResize(void) {
3599 assert(flags
.resizing
);
3600 assert(blackbox
->getChangingWindow() == this);
3602 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3603 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3604 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3605 XUngrabServer(blackbox
->getXDisplay());
3607 // unset maximized state after resized when fully maximized
3608 if (flags
.maximized
== 1)
3611 flags
.resizing
= False
;
3612 blackbox
->setChangingWindow(0);
3614 configure(frame
.changing
.x(), frame
.changing
.y(),
3615 frame
.changing
.width(), frame
.changing
.height());
3616 screen
->hideGeometry();
3618 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3620 // if there are any left over motions from the resize, drop them now
3621 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3623 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3628 void BlackboxWindow::motionNotifyEvent(const XMotionEvent
*me
) {
3630 fprintf(stderr
, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n",
3635 doMove(me
->x_root
, me
->y_root
);
3636 } else if (flags
.resizing
) {
3637 doResize(me
->x_root
, me
->y_root
);
3639 if ((functions
& Func_Move
) &&
3640 (me
->state
& Button1Mask
) &&
3641 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3642 frame
.handle
== me
->window
|| frame
.window
== me
->window
)) {
3643 beginMove(me
->x_root
, me
->y_root
);
3644 } else if ((functions
& Func_Resize
) &&
3645 ((me
->state
& Button1Mask
) && (me
->window
== frame
.right_grip
||
3646 me
->window
== frame
.left_grip
)) ||
3647 ((me
->state
& Button3Mask
) && (me
->state
& mod_mask
) &&
3648 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3649 frame
.handle
== me
->window
|| frame
.window
== me
->window
))) {
3650 unsigned int zones
= screen
->getResizeZones();
3653 if (me
->window
== frame
.left_grip
) {
3654 corner
= BottomLeft
;
3655 } else if (me
->window
== frame
.right_grip
|| zones
== 1) {
3656 corner
= BottomRight
;
3659 bool left
= (me
->x_root
- frame
.rect
.x() <=
3660 static_cast<signed>(frame
.rect
.width() / 2));
3663 else // (zones == 4)
3664 top
= (me
->y_root
- frame
.rect
.y() <=
3665 static_cast<signed>(frame
.rect
.height() / 2));
3666 corner
= (top
? (left
? TopLeft
: TopRight
) :
3667 (left
? BottomLeft
: BottomRight
));
3670 beginResize(me
->x_root
, me
->y_root
, corner
);
3676 void BlackboxWindow::enterNotifyEvent(const XCrossingEvent
* ce
) {
3677 if (! (screen
->isSloppyFocus() && isVisible() && isNormal()))
3681 bool leave
= False
, inferior
= False
;
3683 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), ce
->window
,
3685 if (e
.type
== LeaveNotify
&& e
.xcrossing
.mode
== NotifyNormal
) {
3687 inferior
= (e
.xcrossing
.detail
== NotifyInferior
);
3691 if (! leave
|| inferior
) {
3692 if (! isFocused()) {
3693 bool success
= setInputFocus();
3694 if (success
) // if focus succeeded install the colormap
3695 installColormap(True
); // XXX: shouldnt we honour no install?
3698 if (screen
->doAutoRaise())
3704 void BlackboxWindow::leaveNotifyEvent(const XCrossingEvent
*) {
3705 if (! (screen
->isSloppyFocus() && screen
->doAutoRaise() && isNormal()))
3708 installColormap(False
);
3710 if (timer
->isTiming())
3716 void BlackboxWindow::shapeEvent(XShapeEvent
*) {
3717 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
3724 bool BlackboxWindow::validateClient(void) const {
3725 XSync(blackbox
->getXDisplay(), False
);
3728 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3729 DestroyNotify
, &e
) ||
3730 XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3732 XPutBackEvent(blackbox
->getXDisplay(), &e
);
3741 void BlackboxWindow::restore(bool remap
) {
3742 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeDelete
);
3743 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
3744 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, NoEventMask
);
3746 // do not leave a shaded window as an icon unless it was an icon
3747 if (flags
.shaded
&& ! flags
.iconic
)
3748 setState(NormalState
);
3750 // erase the netwm stuff that we read when a window maps, so that it
3751 // doesn't persist between mappings.
3752 // (these are the ones read in getNetWMFlags().)
3753 xatom
->eraseValue(client
.window
, XAtom::net_wm_desktop
);
3754 xatom
->eraseValue(client
.window
, XAtom::net_wm_state
);
3756 restoreGravity(client
.rect
);
3758 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
3759 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
3761 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, client
.old_bw
);
3764 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3765 ReparentNotify
, &ev
)) {
3768 // according to the ICCCM - if the client doesn't reparent to
3769 // root, then we have to do it for them
3770 XReparentWindow(blackbox
->getXDisplay(), client
.window
,
3771 screen
->getRootWindow(),
3772 client
.rect
.x(), client
.rect
.y());
3775 if (remap
) XMapWindow(blackbox
->getXDisplay(), client
.window
);
3779 // timer for autoraise
3780 void BlackboxWindow::timeout(void) {
3781 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3785 void BlackboxWindow::changeBlackboxHints(const BlackboxHints
*net
) {
3786 if ((net
->flags
& AttribShaded
) &&
3787 ((blackbox_attrib
.attrib
& AttribShaded
) !=
3788 (net
->attrib
& AttribShaded
)))
3791 if (flags
.visible
&& // watch out for requests when we can not be seen
3792 (net
->flags
& (AttribMaxVert
| AttribMaxHoriz
)) &&
3793 ((blackbox_attrib
.attrib
& (AttribMaxVert
| AttribMaxHoriz
)) !=
3794 (net
->attrib
& (AttribMaxVert
| AttribMaxHoriz
)))) {
3795 if (flags
.maximized
) {
3800 if ((net
->flags
& AttribMaxHoriz
) && (net
->flags
& AttribMaxVert
))
3801 button
= ((net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0);
3802 else if (net
->flags
& AttribMaxVert
)
3803 button
= ((net
->attrib
& AttribMaxVert
) ? 2 : 0);
3804 else if (net
->flags
& AttribMaxHoriz
)
3805 button
= ((net
->attrib
& AttribMaxHoriz
) ? 3 : 0);
3811 if ((net
->flags
& AttribOmnipresent
) &&
3812 ((blackbox_attrib
.attrib
& AttribOmnipresent
) !=
3813 (net
->attrib
& AttribOmnipresent
)))
3816 if ((net
->flags
& AttribWorkspace
) &&
3817 (blackbox_attrib
.workspace
!= net
->workspace
)) {
3818 screen
->reassociateWindow(this, net
->workspace
, True
);
3820 if (screen
->getCurrentWorkspaceID() != net
->workspace
) {
3824 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3828 if (net
->flags
& AttribDecoration
) {
3829 switch (net
->decoration
) {
3846 * Set the sizes of all components of the window frame
3847 * (the window decorations).
3848 * These values are based upon the current style settings and the client
3849 * window's dimensions.
3851 void BlackboxWindow::upsize(void) {
3852 frame
.bevel_w
= screen
->getBevelWidth();
3854 if (decorations
& Decor_Border
) {
3855 frame
.border_w
= screen
->getBorderWidth();
3856 if (! isTransient())
3857 frame
.mwm_border_w
= screen
->getFrameWidth();
3859 frame
.mwm_border_w
= 0;
3861 frame
.mwm_border_w
= frame
.border_w
= 0;
3864 if (decorations
& Decor_Titlebar
) {
3865 // the height of the titlebar is based upon the height of the font being
3866 // used to display the window's title
3867 WindowStyle
*style
= screen
->getWindowStyle();
3868 frame
.title_h
= style
->font
->height() + (frame
.bevel_w
* 2) + 2;
3870 frame
.label_h
= frame
.title_h
- (frame
.bevel_w
* 2);
3871 frame
.button_w
= (frame
.label_h
- 2);
3873 // set the top frame margin
3874 frame
.margin
.top
= frame
.border_w
+ frame
.title_h
+
3875 frame
.border_w
+ frame
.mwm_border_w
;
3881 // set the top frame margin
3882 frame
.margin
.top
= frame
.border_w
+ frame
.mwm_border_w
;
3885 // set the left/right frame margin
3886 frame
.margin
.left
= frame
.margin
.right
= frame
.border_w
+ frame
.mwm_border_w
;
3888 if (decorations
& Decor_Handle
) {
3889 frame
.grip_w
= frame
.button_w
* 2;
3890 frame
.handle_h
= screen
->getHandleWidth();
3892 // set the bottom frame margin
3893 frame
.margin
.bottom
= frame
.border_w
+ frame
.handle_h
+
3894 frame
.border_w
+ frame
.mwm_border_w
;
3899 // set the bottom frame margin
3900 frame
.margin
.bottom
= frame
.border_w
+ frame
.mwm_border_w
;
3904 We first get the normal dimensions and use this to define the inside_w/h
3905 then we modify the height if shading is in effect.
3906 If the shade state is not considered then frame.rect gets reset to the
3907 normal window size on a reconfigure() call resulting in improper
3908 dimensions appearing in move/resize and other events.
3911 height
= client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
,
3912 width
= client
.rect
.width() + frame
.margin
.left
+ frame
.margin
.right
;
3914 frame
.inside_w
= width
- (frame
.border_w
* 2);
3915 frame
.inside_h
= height
- (frame
.border_w
* 2);
3918 height
= frame
.title_h
+ (frame
.border_w
* 2);
3919 frame
.rect
.setSize(width
, height
);
3924 * Calculate the size of the client window and constrain it to the
3925 * size specified by the size hints of the client window.
3927 * The logical width and height are placed into pw and ph, if they
3928 * are non-zero. Logical size refers to the users perception of
3929 * the window size (for example an xterm resizes in cells, not in pixels).
3930 * pw and ph are then used to display the geometry during window moves, resize,
3933 * The physical geometry is placed into frame.changing_{x,y,width,height}.
3934 * Physical geometry refers to the geometry of the window in pixels.
3936 void BlackboxWindow::constrain(Corner anchor
,
3937 unsigned int *pw
, unsigned int *ph
) {
3938 // frame.changing represents the requested frame size, we need to
3939 // strip the frame margin off and constrain the client size
3940 frame
.changing
.setCoords(frame
.changing
.left() + frame
.margin
.left
,
3941 frame
.changing
.top() + frame
.margin
.top
,
3942 frame
.changing
.right() - frame
.margin
.right
,
3943 frame
.changing
.bottom() - frame
.margin
.bottom
);
3945 unsigned int dw
= frame
.changing
.width(), dh
= frame
.changing
.height(),
3946 base_width
= (client
.base_width
) ? client
.base_width
: client
.min_width
,
3947 base_height
= (client
.base_height
) ? client
.base_height
:
3951 if (dw
< client
.min_width
) dw
= client
.min_width
;
3952 if (dh
< client
.min_height
) dh
= client
.min_height
;
3953 if (dw
> client
.max_width
) dw
= client
.max_width
;
3954 if (dh
> client
.max_height
) dh
= client
.max_height
;
3956 assert(dw
>= base_width
&& dh
>= base_height
);
3958 if (client
.width_inc
> 1) {
3960 dw
/= client
.width_inc
;
3962 if (client
.height_inc
> 1) {
3964 dh
/= client
.height_inc
;
3973 if (client
.width_inc
> 1) {
3974 dw
*= client
.width_inc
;
3977 if (client
.height_inc
> 1) {
3978 dh
*= client
.height_inc
;
3982 frame
.changing
.setSize(dw
, dh
);
3984 // add the frame margin back onto frame.changing
3985 frame
.changing
.setCoords(frame
.changing
.left() - frame
.margin
.left
,
3986 frame
.changing
.top() - frame
.margin
.top
,
3987 frame
.changing
.right() + frame
.margin
.right
,
3988 frame
.changing
.bottom() + frame
.margin
.bottom
);
3990 // move frame.changing to the specified anchor
3998 dx
= frame
.rect
.right() - frame
.changing
.right();
4002 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
4006 dx
= frame
.rect
.right() - frame
.changing
.right();
4007 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
4011 assert(false); // unhandled corner
4013 frame
.changing
.setPos(frame
.changing
.x() + dx
, frame
.changing
.y() + dy
);
4017 void WindowStyle::doJustify(const std::string
&text
, int &start_pos
,
4018 unsigned int max_length
,
4019 unsigned int modifier
) const {
4020 size_t text_len
= text
.size();
4021 unsigned int length
;
4024 length
= font
->measureString(string(text
, 0, text_len
)) + modifier
;
4025 } while (length
> max_length
&& text_len
-- > 0);
4029 start_pos
+= max_length
- length
;
4033 start_pos
+= (max_length
- length
) / 2;
4043 BWindowGroup::BWindowGroup(Blackbox
*b
, Window _group
)
4044 : blackbox(b
), group(_group
) {
4045 XWindowAttributes wattrib
;
4046 if (! XGetWindowAttributes(blackbox
->getXDisplay(), group
, &wattrib
)) {
4047 // group window doesn't seem to exist anymore
4052 XSelectInput(blackbox
->getXDisplay(), group
,
4053 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
4055 blackbox
->saveGroupSearch(group
, this);
4059 BWindowGroup::~BWindowGroup(void) {
4060 blackbox
->removeGroupSearch(group
);
4065 BWindowGroup::find(BScreen
*screen
, bool allow_transients
) const {
4066 BlackboxWindow
*ret
= blackbox
->getFocusedWindow();
4068 // does the focus window match (or any transient_fors)?
4069 for (; ret
; ret
= ret
->getTransientFor()) {
4070 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
&&
4071 (! ret
->isTransient() || allow_transients
))
4075 if (ret
) return ret
;
4077 // the focus window didn't match, look in the group's window list
4078 BlackboxWindowList::const_iterator it
, end
= windowList
.end();
4079 for (it
= windowList
.begin(); it
!= end
; ++it
) {
4081 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
&&
4082 (! ret
->isTransient() || allow_transients
))