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 get 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
.pixel();
594 frame
.uborder_pixel
= screen
->getWindowStyle()->f_unfocus
.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) {
1009 if (xatom
->getValue(client
.window
, XAtom::net_wm_window_type
, XAtom::atom
,
1011 if (val
== xatom
->getAtom(XAtom::net_wm_window_type_desktop
))
1012 window_type
= Type_Desktop
;
1013 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_dock
))
1014 window_type
= Type_Dock
;
1015 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_toolbar
))
1016 window_type
= Type_Toolbar
;
1017 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_menu
))
1018 window_type
= Type_Menu
;
1019 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_utility
))
1020 window_type
= Type_Utility
;
1021 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_splash
))
1022 window_type
= Type_Splash
;
1023 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_dialog
))
1024 window_type
= Type_Dialog
;
1025 else //if (val[0] == xatom->getAtom(XAtom::net_wm_window_type_normal))
1026 window_type
= Type_Normal
;
1032 * the window type hint was not set, which means we either classify ourself
1033 * as a normal window or a dialog, depending on if we are a transient.
1036 window_type
= Type_Dialog
;
1038 window_type
= Type_Normal
;
1044 void BlackboxWindow::getWMName(void) {
1045 if (xatom
->getValue(client
.window
, XAtom::net_wm_name
,
1046 XAtom::utf8
, client
.title
) &&
1047 !client
.title
.empty()) {
1048 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
1051 //fall through to using WM_NAME
1052 if (xatom
->getValue(client
.window
, XAtom::wm_name
, XAtom::ansi
, client
.title
)
1053 && !client
.title
.empty()) {
1054 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
1057 // fall back to an internal default
1058 client
.title
= i18n(WindowSet
, WindowUnnamed
, "Unnamed");
1059 xatom
->setValue(client
.window
, XAtom::net_wm_visible_name
, XAtom::utf8
,
1064 void BlackboxWindow::getWMIconName(void) {
1065 if (xatom
->getValue(client
.window
, XAtom::net_wm_icon_name
,
1066 XAtom::utf8
, client
.icon_title
) &&
1067 !client
.icon_title
.empty()) {
1068 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1071 //fall through to using WM_ICON_NAME
1072 if (xatom
->getValue(client
.window
, XAtom::wm_icon_name
, XAtom::ansi
,
1073 client
.icon_title
) &&
1074 !client
.icon_title
.empty()) {
1075 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1078 // fall back to using the main name
1079 client
.icon_title
= client
.title
;
1080 xatom
->setValue(client
.window
, XAtom::net_wm_visible_icon_name
, XAtom::utf8
,
1086 * Retrieve which WM Protocols are supported by the client window.
1087 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
1088 * window's decorations and allow the close behavior.
1089 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
1092 void BlackboxWindow::getWMProtocols(void) {
1096 if (XGetWMProtocols(blackbox
->getXDisplay(), client
.window
,
1097 &proto
, &num_return
)) {
1098 for (int i
= 0; i
< num_return
; ++i
) {
1099 if (proto
[i
] == xatom
->getAtom(XAtom::wm_delete_window
)) {
1100 decorations
|= Decor_Close
;
1101 functions
|= Func_Close
;
1102 } else if (proto
[i
] == xatom
->getAtom(XAtom::wm_take_focus
))
1103 flags
.send_focus_message
= True
;
1104 else if (proto
[i
] == xatom
->getAtom(XAtom::blackbox_structure_messages
))
1105 screen
->addNetizen(new Netizen(screen
, client
.window
));
1114 * Gets the value of the WM_HINTS property.
1115 * If the property is not set, then use a set of default values.
1117 void BlackboxWindow::getWMHints(void) {
1118 focus_mode
= F_Passive
;
1120 // remove from current window group
1121 if (client
.window_group
) {
1122 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1123 if (group
) group
->removeWindow(this);
1125 client
.window_group
= None
;
1127 XWMHints
*wmhint
= XGetWMHints(blackbox
->getXDisplay(), client
.window
);
1132 if (wmhint
->flags
& InputHint
) {
1133 if (wmhint
->input
== True
) {
1134 if (flags
.send_focus_message
)
1135 focus_mode
= F_LocallyActive
;
1137 if (flags
.send_focus_message
)
1138 focus_mode
= F_GloballyActive
;
1140 focus_mode
= F_NoInput
;
1144 if (wmhint
->flags
& StateHint
)
1145 current_state
= wmhint
->initial_state
;
1147 if (wmhint
->flags
& WindowGroupHint
) {
1148 client
.window_group
= wmhint
->window_group
;
1150 // add window to the appropriate group
1151 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1152 if (! group
) { // no group found, create it!
1153 new BWindowGroup(blackbox
, client
.window_group
);
1154 group
= blackbox
->searchGroup(client
.window_group
);
1157 group
->addWindow(this);
1165 * Gets the value of the WM_NORMAL_HINTS property.
1166 * If the property is not set, then use a set of default values.
1168 void BlackboxWindow::getWMNormalHints(void) {
1170 XSizeHints sizehint
;
1172 client
.min_width
= client
.min_height
=
1173 client
.width_inc
= client
.height_inc
= 1;
1174 client
.base_width
= client
.base_height
= 0;
1175 client
.win_gravity
= NorthWestGravity
;
1177 client
.min_aspect_x
= client
.min_aspect_y
=
1178 client
.max_aspect_x
= client
.max_aspect_y
= 1;
1182 use the full screen, not the strut modified size. otherwise when the
1183 availableArea changes max_width/height will be incorrect and lead to odd
1186 const Rect
& screen_area
= screen
->getRect();
1187 client
.max_width
= screen_area
.width();
1188 client
.max_height
= screen_area
.height();
1190 if (! XGetWMNormalHints(blackbox
->getXDisplay(), client
.window
,
1191 &sizehint
, &icccm_mask
))
1194 client
.normal_hint_flags
= sizehint
.flags
;
1196 if (sizehint
.flags
& PMinSize
) {
1197 if (sizehint
.min_width
>= 0)
1198 client
.min_width
= sizehint
.min_width
;
1199 if (sizehint
.min_height
>= 0)
1200 client
.min_height
= sizehint
.min_height
;
1203 if (sizehint
.flags
& PMaxSize
) {
1204 if (sizehint
.max_width
> static_cast<signed>(client
.min_width
))
1205 client
.max_width
= sizehint
.max_width
;
1207 client
.max_width
= client
.min_width
;
1209 if (sizehint
.max_height
> static_cast<signed>(client
.min_height
))
1210 client
.max_height
= sizehint
.max_height
;
1212 client
.max_height
= client
.min_height
;
1215 if (sizehint
.flags
& PResizeInc
) {
1216 client
.width_inc
= sizehint
.width_inc
;
1217 client
.height_inc
= sizehint
.height_inc
;
1220 #if 0 // we do not support this at the moment
1221 if (sizehint
.flags
& PAspect
) {
1222 client
.min_aspect_x
= sizehint
.min_aspect
.x
;
1223 client
.min_aspect_y
= sizehint
.min_aspect
.y
;
1224 client
.max_aspect_x
= sizehint
.max_aspect
.x
;
1225 client
.max_aspect_y
= sizehint
.max_aspect
.y
;
1229 if (sizehint
.flags
& PBaseSize
) {
1230 client
.base_width
= sizehint
.base_width
;
1231 client
.base_height
= sizehint
.base_height
;
1234 if (sizehint
.flags
& PWinGravity
)
1235 client
.win_gravity
= sizehint
.win_gravity
;
1240 * Gets the NETWM hints for the class' contained window.
1242 void BlackboxWindow::getNetWMHints(void) {
1243 unsigned long workspace
;
1245 if (xatom
->getValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1247 if (workspace
== 0xffffffff)
1250 blackbox_attrib
.workspace
= workspace
;
1253 unsigned long *state
;
1254 unsigned long num
= (unsigned) -1;
1255 if (xatom
->getValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
1259 for (unsigned long i
= 0; i
< num
; ++i
) {
1260 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
))
1262 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_shaded
))
1263 flags
.shaded
= True
;
1264 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
))
1265 flags
.skip_taskbar
= True
;
1266 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_pager
))
1267 flags
.skip_pager
= True
;
1268 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_fullscreen
))
1269 flags
.fullscreen
= True
;
1270 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_hidden
))
1271 setState(IconicState
);
1272 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_vert
))
1274 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_horz
))
1278 flags
.maximized
= 1;
1280 flags
.maximized
= 2;
1282 flags
.maximized
= 3;
1290 * Gets the MWM hints for the class' contained window.
1291 * This is used while initializing the window to its first state, and not
1293 * Returns: true if the MWM hints are successfully retreived and applied;
1294 * false if they are not.
1296 void BlackboxWindow::getMWMHints(void) {
1300 num
= PropMwmHintsElements
;
1301 if (! xatom
->getValue(client
.window
, XAtom::motif_wm_hints
,
1302 XAtom::motif_wm_hints
, num
,
1303 (unsigned long **)&mwm_hint
))
1305 if (num
< PropMwmHintsElements
) {
1310 if (mwm_hint
->flags
& MwmHintsDecorations
) {
1311 if (mwm_hint
->decorations
& MwmDecorAll
) {
1312 mwm_decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
1313 Decor_Iconify
| Decor_Maximize
;
1315 mwm_decorations
= 0;
1317 if (mwm_hint
->decorations
& MwmDecorBorder
)
1318 mwm_decorations
|= Decor_Border
;
1319 if (mwm_hint
->decorations
& MwmDecorHandle
)
1320 mwm_decorations
|= Decor_Handle
;
1321 if (mwm_hint
->decorations
& MwmDecorTitle
)
1322 mwm_decorations
|= Decor_Titlebar
;
1323 if (mwm_hint
->decorations
& MwmDecorIconify
)
1324 mwm_decorations
|= Decor_Iconify
;
1325 if (mwm_hint
->decorations
& MwmDecorMaximize
)
1326 mwm_decorations
|= Decor_Maximize
;
1330 if (mwm_hint
->flags
& MwmHintsFunctions
) {
1331 if (mwm_hint
->functions
& MwmFuncAll
) {
1332 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
|
1337 if (mwm_hint
->functions
& MwmFuncResize
)
1338 functions
|= Func_Resize
;
1339 if (mwm_hint
->functions
& MwmFuncMove
)
1340 functions
|= Func_Move
;
1341 if (mwm_hint
->functions
& MwmFuncIconify
)
1342 functions
|= Func_Iconify
;
1343 if (mwm_hint
->functions
& MwmFuncMaximize
)
1344 functions
|= Func_Maximize
;
1345 if (mwm_hint
->functions
& MwmFuncClose
)
1346 functions
|= Func_Close
;
1354 * Gets the blackbox hints from the class' contained window.
1355 * This is used while initializing the window to its first state, and not
1357 * Returns: true if the hints are successfully retreived and applied; false if
1360 bool BlackboxWindow::getBlackboxHints(void) {
1362 BlackboxHints
*blackbox_hint
;
1364 num
= PropBlackboxHintsElements
;
1365 if (! xatom
->getValue(client
.window
, XAtom::blackbox_hints
,
1366 XAtom::blackbox_hints
, num
,
1367 (unsigned long **)&blackbox_hint
))
1369 if (num
< PropBlackboxHintsElements
) {
1370 delete [] blackbox_hint
;
1374 if (blackbox_hint
->flags
& AttribShaded
)
1375 flags
.shaded
= (blackbox_hint
->attrib
& AttribShaded
);
1377 if ((blackbox_hint
->flags
& AttribMaxHoriz
) &&
1378 (blackbox_hint
->flags
& AttribMaxVert
))
1379 flags
.maximized
= (blackbox_hint
->attrib
&
1380 (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1381 else if (blackbox_hint
->flags
& AttribMaxVert
)
1382 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxVert
) ? 2 : 0;
1383 else if (blackbox_hint
->flags
& AttribMaxHoriz
)
1384 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1386 if (blackbox_hint
->flags
& AttribOmnipresent
)
1387 flags
.stuck
= (blackbox_hint
->attrib
& AttribOmnipresent
);
1389 if (blackbox_hint
->flags
& AttribWorkspace
)
1390 blackbox_attrib
.workspace
= blackbox_hint
->workspace
;
1392 // if (blackbox_hint->flags & AttribStack)
1393 // don't yet have always on top/bottom for blackbox yet... working
1396 if (blackbox_hint
->flags
& AttribDecoration
) {
1397 switch (blackbox_hint
->decoration
) {
1399 blackbox_attrib
.decoration
= DecorNone
;
1406 // blackbox_attrib.decoration defaults to DecorNormal
1411 delete [] blackbox_hint
;
1417 void BlackboxWindow::getTransientInfo(void) {
1418 if (client
.transient_for
&&
1419 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1420 // reset transient_for in preparation of looking for a new owner
1421 client
.transient_for
->client
.transientList
.remove(this);
1424 // we have no transient_for until we find a new one
1425 client
.transient_for
= (BlackboxWindow
*) 0;
1428 if (! XGetTransientForHint(blackbox
->getXDisplay(), client
.window
,
1430 // transient_for hint not set
1434 if (trans_for
== client
.window
) {
1435 // wierd client... treat this window as a normal window
1439 if (trans_for
== None
|| trans_for
== screen
->getRootWindow()) {
1440 // this is an undocumented interpretation of the ICCCM. a transient
1441 // associated with None/Root/itself is assumed to be a modal root
1442 // transient. we don't support the concept of a global transient,
1443 // so we just associate this transient with nothing, and perhaps
1444 // we will add support later for global modality.
1445 client
.transient_for
= (BlackboxWindow
*) ~0ul;
1450 client
.transient_for
= blackbox
->searchWindow(trans_for
);
1451 if (! client
.transient_for
&&
1452 client
.window_group
&& trans_for
== client
.window_group
) {
1453 // no direct transient_for, perhaps this is a group transient?
1454 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1455 if (group
) client
.transient_for
= group
->find(screen
);
1458 if (! client
.transient_for
|| client
.transient_for
== this) {
1459 // no transient_for found, or we have a wierd client that wants to be
1460 // a transient for itself, so we treat this window as a normal window
1461 client
.transient_for
= (BlackboxWindow
*) 0;
1465 // Check for a circular transient state: this can lock up Blackbox
1466 // when it tries to find the non-transient window for a transient.
1467 BlackboxWindow
*w
= this;
1468 while(w
->client
.transient_for
&&
1469 w
->client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1470 if(w
->client
.transient_for
== this) {
1471 client
.transient_for
= (BlackboxWindow
*) 0;
1474 w
= w
->client
.transient_for
;
1477 if (client
.transient_for
&&
1478 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1479 // register ourselves with our new transient_for
1480 client
.transient_for
->client
.transientList
.push_back(this);
1481 flags
.stuck
= client
.transient_for
->flags
.stuck
;
1486 BlackboxWindow
*BlackboxWindow::getTransientFor(void) const {
1487 if (client
.transient_for
&&
1488 client
.transient_for
!= (BlackboxWindow
*) ~0ul)
1489 return client
.transient_for
;
1495 * This function is responsible for updating both the client and the frame
1497 * According to the ICCCM a client message is not sent for a resize, only a
1500 void BlackboxWindow::configure(int dx
, int dy
,
1501 unsigned int dw
, unsigned int dh
) {
1502 bool send_event
= ((frame
.rect
.x() != dx
|| frame
.rect
.y() != dy
) &&
1505 if (dw
!= frame
.rect
.width() || dh
!= frame
.rect
.height()) {
1506 frame
.rect
.setRect(dx
, dy
, dw
, dh
);
1507 frame
.inside_w
= frame
.rect
.width() - (frame
.border_w
* 2);
1508 frame
.inside_h
= frame
.rect
.height() - (frame
.border_w
* 2);
1510 if (frame
.rect
.right() <= 0 || frame
.rect
.bottom() <= 0)
1511 frame
.rect
.setPos(0, 0);
1513 client
.rect
.setCoords(frame
.rect
.left() + frame
.margin
.left
,
1514 frame
.rect
.top() + frame
.margin
.top
,
1515 frame
.rect
.right() - frame
.margin
.right
,
1516 frame
.rect
.bottom() - frame
.margin
.bottom
);
1519 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
1526 redrawWindowFrame();
1528 frame
.rect
.setPos(dx
, dy
);
1530 XMoveWindow(blackbox
->getXDisplay(), frame
.window
,
1531 frame
.rect
.x(), frame
.rect
.y());
1533 we may have been called just after an opaque window move, so even though
1534 the old coords match the new ones no ConfigureNotify has been sent yet.
1535 There are likely other times when this will be relevant as well.
1537 if (! flags
.moving
) send_event
= True
;
1541 // if moving, the update and event will occur when the move finishes
1542 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1543 frame
.rect
.top() + frame
.margin
.top
);
1546 event
.type
= ConfigureNotify
;
1548 event
.xconfigure
.display
= blackbox
->getXDisplay();
1549 event
.xconfigure
.event
= client
.window
;
1550 event
.xconfigure
.window
= client
.window
;
1551 event
.xconfigure
.x
= client
.rect
.x();
1552 event
.xconfigure
.y
= client
.rect
.y();
1553 event
.xconfigure
.width
= client
.rect
.width();
1554 event
.xconfigure
.height
= client
.rect
.height();
1555 event
.xconfigure
.border_width
= client
.old_bw
;
1556 event
.xconfigure
.above
= frame
.window
;
1557 event
.xconfigure
.override_redirect
= False
;
1559 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1560 StructureNotifyMask
, &event
);
1561 screen
->updateNetizenConfigNotify(&event
);
1562 XFlush(blackbox
->getXDisplay());
1568 void BlackboxWindow::configureShape(void) {
1569 XShapeCombineShape(blackbox
->getXDisplay(), frame
.window
, ShapeBounding
,
1570 frame
.margin
.left
- frame
.border_w
,
1571 frame
.margin
.top
- frame
.border_w
,
1572 client
.window
, ShapeBounding
, ShapeSet
);
1575 XRectangle xrect
[2];
1577 if (decorations
& Decor_Titlebar
) {
1578 xrect
[0].x
= xrect
[0].y
= -frame
.border_w
;
1579 xrect
[0].width
= frame
.rect
.width();
1580 xrect
[0].height
= frame
.title_h
+ (frame
.border_w
* 2);
1584 if (decorations
& Decor_Handle
) {
1585 xrect
[1].x
= -frame
.border_w
;
1586 xrect
[1].y
= frame
.rect
.height() - frame
.margin
.bottom
+
1587 frame
.mwm_border_w
- frame
.border_w
;
1588 xrect
[1].width
= frame
.rect
.width();
1589 xrect
[1].height
= frame
.handle_h
+ (frame
.border_w
* 2);
1593 XShapeCombineRectangles(blackbox
->getXDisplay(), frame
.window
,
1594 ShapeBounding
, 0, 0, xrect
, num
,
1595 ShapeUnion
, Unsorted
);
1600 bool BlackboxWindow::setInputFocus(void) {
1601 if (flags
.focused
) return True
;
1603 assert(flags
.stuck
|| // window must be on the current workspace or sticky
1604 blackbox_attrib
.workspace
== screen
->getCurrentWorkspaceID());
1607 We only do this check for normal windows and dialogs because other windows
1608 do this on purpose, such as kde's kicker, and we don't want to go moving
1611 if (window_type
== Type_Normal
|| window_type
== Type_Dialog
)
1612 if (! frame
.rect
.intersects(screen
->getRect())) {
1613 // client is outside the screen, move it to the center
1614 configure((screen
->getWidth() - frame
.rect
.width()) / 2,
1615 (screen
->getHeight() - frame
.rect
.height()) / 2,
1616 frame
.rect
.width(), frame
.rect
.height());
1619 if (client
.transientList
.size() > 0) {
1620 // transfer focus to any modal transients
1621 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1622 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1623 if ((*it
)->flags
.modal
) return (*it
)->setInputFocus();
1627 if (focus_mode
== F_LocallyActive
|| focus_mode
== F_Passive
) {
1628 XSetInputFocus(blackbox
->getXDisplay(), client
.window
,
1629 RevertToPointerRoot
, CurrentTime
);
1631 /* we could set the focus to none, since the window doesn't accept focus,
1632 * but we shouldn't set focus to nothing since this would surely make
1638 if (flags
.send_focus_message
) {
1640 ce
.xclient
.type
= ClientMessage
;
1641 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1642 ce
.xclient
.display
= blackbox
->getXDisplay();
1643 ce
.xclient
.window
= client
.window
;
1644 ce
.xclient
.format
= 32;
1645 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_take_focus
);
1646 ce
.xclient
.data
.l
[1] = blackbox
->getLastTime();
1647 ce
.xclient
.data
.l
[2] = 0l;
1648 ce
.xclient
.data
.l
[3] = 0l;
1649 ce
.xclient
.data
.l
[4] = 0l;
1650 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1652 XFlush(blackbox
->getXDisplay());
1659 void BlackboxWindow::iconify(void) {
1660 if (flags
.iconic
) return;
1662 // We don't need to worry about resizing because resizing always grabs the X
1663 // server. This should only ever happen if using opaque moving.
1667 if (windowmenu
) windowmenu
->hide();
1670 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1671 * we need to clear the event mask on client.window for a split second.
1672 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1673 * split second, leaving us with a ghost window... so, we need to do this
1674 * while the X server is grabbed
1676 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1677 StructureNotifyMask
;
1678 XGrabServer(blackbox
->getXDisplay());
1679 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1680 event_mask
& ~StructureNotifyMask
);
1681 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1682 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1683 XUngrabServer(blackbox
->getXDisplay());
1685 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1686 flags
.visible
= False
;
1687 flags
.iconic
= True
;
1689 setState(IconicState
);
1691 screen
->getWorkspace(blackbox_attrib
.workspace
)->removeWindow(this);
1693 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
1694 if (i
!= blackbox_attrib
.workspace
)
1695 screen
->getWorkspace(i
)->removeWindow(this, True
);
1698 if (isTransient()) {
1699 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1700 ! client
.transient_for
->flags
.iconic
) {
1701 // iconify our transient_for
1702 client
.transient_for
->iconify();
1706 screen
->addIcon(this);
1708 if (client
.transientList
.size() > 0) {
1709 // iconify all transients
1710 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1711 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1712 if (! (*it
)->flags
.iconic
) (*it
)->iconify();
1715 screen
->updateStackingList();
1719 void BlackboxWindow::show(void) {
1720 flags
.visible
= True
;
1721 flags
.iconic
= False
;
1723 current_state
= (flags
.shaded
) ? IconicState
: NormalState
;
1724 setState(current_state
);
1726 XMapWindow(blackbox
->getXDisplay(), client
.window
);
1727 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
1728 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
1733 XTranslateCoordinates(blackbox
->getXDisplay(), client
.window
,
1734 screen
->getRootWindow(),
1735 0, 0, &real_x
, &real_y
, &child
);
1736 fprintf(stderr
, "%s -- assumed: (%d, %d), real: (%d, %d)\n", getTitle(),
1737 client
.rect
.left(), client
.rect
.top(), real_x
, real_y
);
1738 assert(client
.rect
.left() == real_x
&& client
.rect
.top() == real_y
);
1743 void BlackboxWindow::deiconify(bool reassoc
, bool raise
) {
1744 if (flags
.iconic
|| reassoc
)
1745 screen
->reassociateWindow(this, BSENTINEL
, False
);
1746 else if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID())
1751 // reassociate and deiconify all transients
1752 if (reassoc
&& client
.transientList
.size() > 0) {
1753 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1754 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1755 (*it
)->deiconify(True
, False
);
1759 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1763 void BlackboxWindow::close(void) {
1765 ce
.xclient
.type
= ClientMessage
;
1766 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1767 ce
.xclient
.display
= blackbox
->getXDisplay();
1768 ce
.xclient
.window
= client
.window
;
1769 ce
.xclient
.format
= 32;
1770 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_delete_window
);
1771 ce
.xclient
.data
.l
[1] = CurrentTime
;
1772 ce
.xclient
.data
.l
[2] = 0l;
1773 ce
.xclient
.data
.l
[3] = 0l;
1774 ce
.xclient
.data
.l
[4] = 0l;
1775 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
, NoEventMask
, &ce
);
1776 XFlush(blackbox
->getXDisplay());
1780 void BlackboxWindow::withdraw(void) {
1781 // We don't need to worry about resizing because resizing always grabs the X
1782 // server. This should only ever happen if using opaque moving.
1786 flags
.visible
= False
;
1787 flags
.iconic
= False
;
1789 setState(current_state
);
1791 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1793 XGrabServer(blackbox
->getXDisplay());
1795 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1796 StructureNotifyMask
;
1797 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1798 event_mask
& ~StructureNotifyMask
);
1799 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1800 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1802 XUngrabServer(blackbox
->getXDisplay());
1804 if (windowmenu
) windowmenu
->hide();
1808 void BlackboxWindow::maximize(unsigned int button
) {
1809 // We don't need to worry about resizing because resizing always grabs the X
1810 // server. This should only ever happen if using opaque moving.
1814 // handle case where menu is open then the max button is used instead
1815 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
1817 if (flags
.maximized
) {
1818 flags
.maximized
= 0;
1820 blackbox_attrib
.flags
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1821 blackbox_attrib
.attrib
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1824 when a resize finishes, maximize(0) is called to clear any maximization
1825 flags currently set. Otherwise it still thinks it is maximized.
1826 so we do not need to call configure() because resizing will handle it
1828 if (! flags
.resizing
)
1829 configure(blackbox_attrib
.premax_x
, blackbox_attrib
.premax_y
,
1830 blackbox_attrib
.premax_w
, blackbox_attrib
.premax_h
);
1832 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
1833 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
1835 redrawAllButtons(); // in case it is not called in configure()
1836 setState(current_state
);
1840 blackbox_attrib
.premax_x
= frame
.rect
.x();
1841 blackbox_attrib
.premax_y
= frame
.rect
.y();
1842 blackbox_attrib
.premax_w
= frame
.rect
.width();
1843 // use client.rect so that clients can be restored even if shaded
1844 blackbox_attrib
.premax_h
=
1845 client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
;
1848 if (screen
->isXineramaActive() && blackbox
->doXineramaMaximizing()) {
1849 // find the area to use
1850 RectList availableAreas
= screen
->allAvailableAreas();
1851 RectList::iterator it
, end
= availableAreas
.end();
1853 for (it
= availableAreas
.begin(); it
!= end
; ++it
)
1854 if (it
->intersects(frame
.rect
)) break;
1855 if (it
== end
) // the window isn't inside an area
1856 it
= availableAreas
.begin(); // so just default to the first one
1858 frame
.changing
= *it
;
1861 frame
.changing
= screen
->availableArea();
1865 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1866 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1870 blackbox_attrib
.flags
|= AttribMaxVert
;
1871 blackbox_attrib
.attrib
|= AttribMaxVert
;
1873 frame
.changing
.setX(frame
.rect
.x());
1874 frame
.changing
.setWidth(frame
.rect
.width());
1878 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1879 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1881 frame
.changing
.setY(frame
.rect
.y());
1882 frame
.changing
.setHeight(frame
.rect
.height());
1889 blackbox_attrib
.flags
^= AttribShaded
;
1890 blackbox_attrib
.attrib
^= AttribShaded
;
1891 flags
.shaded
= False
;
1894 flags
.maximized
= button
;
1896 configure(frame
.changing
.x(), frame
.changing
.y(),
1897 frame
.changing
.width(), frame
.changing
.height());
1899 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1900 redrawAllButtons(); // in case it is not called in configure()
1901 setState(current_state
);
1905 // re-maximizes the window to take into account availableArea changes
1906 void BlackboxWindow::remaximize(void) {
1908 // we only update the window's attributes otherwise we lose the shade bit
1909 switch(flags
.maximized
) {
1911 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1912 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1916 blackbox_attrib
.flags
|= AttribMaxVert
;
1917 blackbox_attrib
.attrib
|= AttribMaxVert
;
1921 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1922 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1928 // save the original dimensions because maximize will wipe them out
1929 int premax_x
= blackbox_attrib
.premax_x
,
1930 premax_y
= blackbox_attrib
.premax_y
,
1931 premax_w
= blackbox_attrib
.premax_w
,
1932 premax_h
= blackbox_attrib
.premax_h
;
1934 unsigned int button
= flags
.maximized
;
1935 flags
.maximized
= 0; // trick maximize() into working
1938 // restore saved values
1939 blackbox_attrib
.premax_x
= premax_x
;
1940 blackbox_attrib
.premax_y
= premax_y
;
1941 blackbox_attrib
.premax_w
= premax_w
;
1942 blackbox_attrib
.premax_h
= premax_h
;
1946 void BlackboxWindow::setWorkspace(unsigned int n
) {
1947 blackbox_attrib
.flags
|= AttribWorkspace
;
1948 blackbox_attrib
.workspace
= n
;
1949 if (n
== BSENTINEL
) { // iconified window
1951 we set the workspace to 'all workspaces' so that taskbars will show the
1952 window. otherwise, it made uniconifying a window imposible without the
1953 blackbox workspace menu
1957 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
, n
);
1961 void BlackboxWindow::shade(void) {
1963 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1964 frame
.inside_w
, frame
.inside_h
);
1965 flags
.shaded
= False
;
1966 blackbox_attrib
.flags
^= AttribShaded
;
1967 blackbox_attrib
.attrib
^= AttribShaded
;
1969 setState(NormalState
);
1971 // set the frame rect to the normal size
1972 frame
.rect
.setHeight(client
.rect
.height() + frame
.margin
.top
+
1973 frame
.margin
.bottom
);
1975 if (! (decorations
& Decor_Titlebar
))
1976 return; // can't shade it without a titlebar!
1978 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1979 frame
.inside_w
, frame
.title_h
);
1980 flags
.shaded
= True
;
1981 blackbox_attrib
.flags
|= AttribShaded
;
1982 blackbox_attrib
.attrib
|= AttribShaded
;
1984 setState(IconicState
);
1986 // set the frame rect to the shaded size
1987 frame
.rect
.setHeight(frame
.title_h
+ (frame
.border_w
* 2));
1993 * (Un)Sticks a window and its relatives.
1995 void BlackboxWindow::stick(void) {
1997 blackbox_attrib
.flags
^= AttribOmnipresent
;
1998 blackbox_attrib
.attrib
^= AttribOmnipresent
;
2000 flags
.stuck
= False
;
2002 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
2003 if (i
!= blackbox_attrib
.workspace
)
2004 screen
->getWorkspace(i
)->removeWindow(this, True
);
2007 screen
->reassociateWindow(this, BSENTINEL
, True
);
2008 // temporary fix since sticky windows suck. set the hint to what we
2009 // actually hold in our data.
2010 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
2011 blackbox_attrib
.workspace
);
2013 setState(current_state
);
2017 blackbox_attrib
.flags
|= AttribOmnipresent
;
2018 blackbox_attrib
.attrib
|= AttribOmnipresent
;
2020 // temporary fix since sticky windows suck. set the hint to a different
2021 // value than that contained in the class' data.
2022 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
2025 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
2026 if (i
!= blackbox_attrib
.workspace
)
2027 screen
->getWorkspace(i
)->addWindow(this, False
, True
);
2029 setState(current_state
);
2032 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
2033 client
.transient_for
->isStuck() != flags
.stuck
)
2034 client
.transient_for
->stick();
2035 // go down the chain
2036 BlackboxWindowList::iterator it
;
2037 const BlackboxWindowList::iterator end
= client
.transientList
.end();
2038 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
2039 if ((*it
)->isStuck() != flags
.stuck
)
2044 void BlackboxWindow::redrawWindowFrame(void) const {
2045 if (decorations
& Decor_Titlebar
) {
2046 if (flags
.focused
) {
2048 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2049 frame
.title
, frame
.ftitle
);
2051 XSetWindowBackground(blackbox
->getXDisplay(),
2052 frame
.title
, frame
.ftitle_pixel
);
2055 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2056 frame
.title
, frame
.utitle
);
2058 XSetWindowBackground(blackbox
->getXDisplay(),
2059 frame
.title
, frame
.utitle_pixel
);
2061 XClearWindow(blackbox
->getXDisplay(), frame
.title
);
2067 if (decorations
& Decor_Handle
) {
2068 if (flags
.focused
) {
2070 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2071 frame
.handle
, frame
.fhandle
);
2073 XSetWindowBackground(blackbox
->getXDisplay(),
2074 frame
.handle
, frame
.fhandle_pixel
);
2077 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2078 frame
.left_grip
, frame
.fgrip
);
2079 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2080 frame
.right_grip
, frame
.fgrip
);
2082 XSetWindowBackground(blackbox
->getXDisplay(),
2083 frame
.left_grip
, frame
.fgrip_pixel
);
2084 XSetWindowBackground(blackbox
->getXDisplay(),
2085 frame
.right_grip
, frame
.fgrip_pixel
);
2089 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2090 frame
.handle
, frame
.uhandle
);
2092 XSetWindowBackground(blackbox
->getXDisplay(),
2093 frame
.handle
, frame
.uhandle_pixel
);
2096 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2097 frame
.left_grip
, frame
.ugrip
);
2098 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2099 frame
.right_grip
, frame
.ugrip
);
2101 XSetWindowBackground(blackbox
->getXDisplay(),
2102 frame
.left_grip
, frame
.ugrip_pixel
);
2103 XSetWindowBackground(blackbox
->getXDisplay(),
2104 frame
.right_grip
, frame
.ugrip_pixel
);
2107 XClearWindow(blackbox
->getXDisplay(), frame
.handle
);
2108 XClearWindow(blackbox
->getXDisplay(), frame
.left_grip
);
2109 XClearWindow(blackbox
->getXDisplay(), frame
.right_grip
);
2112 if (decorations
& Decor_Border
) {
2114 XSetWindowBorder(blackbox
->getXDisplay(),
2115 frame
.plate
, frame
.fborder_pixel
);
2117 XSetWindowBorder(blackbox
->getXDisplay(),
2118 frame
.plate
, frame
.uborder_pixel
);
2123 void BlackboxWindow::setFocusFlag(bool focus
) {
2124 // only focus a window if it is visible
2125 if (focus
&& ! flags
.visible
)
2128 flags
.focused
= focus
;
2130 redrawWindowFrame();
2133 blackbox
->setFocusedWindow(this);
2135 if (! flags
.iconic
) {
2136 // iconic windows arent in a workspace menu!
2138 screen
->getCurrentWorkspace()->setFocused(this, isFocused());
2140 screen
->getWorkspace(blackbox_attrib
.workspace
)->
2141 setFocused(this, flags
.focused
);
2146 void BlackboxWindow::installColormap(bool install
) {
2147 int i
= 0, ncmap
= 0;
2148 Colormap
*cmaps
= XListInstalledColormaps(blackbox
->getXDisplay(),
2149 client
.window
, &ncmap
);
2151 XWindowAttributes wattrib
;
2152 if (XGetWindowAttributes(blackbox
->getXDisplay(),
2153 client
.window
, &wattrib
)) {
2155 // install the window's colormap
2156 for (i
= 0; i
< ncmap
; i
++) {
2157 if (*(cmaps
+ i
) == wattrib
.colormap
)
2158 // this window is using an installed color map... do not install
2161 // otherwise, install the window's colormap
2163 XInstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2165 // uninstall the window's colormap
2166 for (i
= 0; i
< ncmap
; i
++) {
2167 if (*(cmaps
+ i
) == wattrib
.colormap
)
2168 // we found the colormap to uninstall
2169 XUninstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2179 void BlackboxWindow::setAllowedActions(void) {
2183 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_shade
);
2184 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_change_desktop
);
2185 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_close
);
2187 if (functions
& Func_Move
)
2188 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_move
);
2189 if (functions
& Func_Resize
)
2190 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_resize
);
2191 if (functions
& Func_Maximize
) {
2192 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_horz
);
2193 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_vert
);
2196 xatom
->setValue(client
.window
, XAtom::net_wm_allowed_actions
, XAtom::atom
,
2201 void BlackboxWindow::setState(unsigned long new_state
) {
2202 current_state
= new_state
;
2204 unsigned long state
[2];
2205 state
[0] = current_state
;
2207 xatom
->setValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
, state
, 2);
2209 xatom
->setValue(client
.window
, XAtom::blackbox_attributes
,
2210 XAtom::blackbox_attributes
, (unsigned long *)&blackbox_attrib
,
2211 PropBlackboxAttributesElements
);
2216 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_modal
);
2218 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_shaded
);
2220 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_hidden
);
2221 if (flags
.skip_taskbar
)
2222 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
);
2223 if (flags
.skip_pager
)
2224 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_pager
);
2225 if (flags
.fullscreen
)
2226 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_fullscreen
);
2227 if (flags
.maximized
== 1 || flags
.maximized
== 2)
2228 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_vert
);
2229 if (flags
.maximized
== 1 || flags
.maximized
== 3)
2230 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_horz
);
2231 xatom
->setValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
2236 bool BlackboxWindow::getState(void) {
2237 bool ret
= xatom
->getValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
,
2239 if (! ret
) current_state
= 0;
2244 void BlackboxWindow::restoreAttributes(void) {
2245 unsigned long num
= PropBlackboxAttributesElements
;
2246 BlackboxAttributes
*net
;
2247 if (! xatom
->getValue(client
.window
, XAtom::blackbox_attributes
,
2248 XAtom::blackbox_attributes
, num
,
2249 (unsigned long **)&net
))
2251 if (num
< PropBlackboxAttributesElements
) {
2256 if (net
->flags
& AttribShaded
&& net
->attrib
& AttribShaded
) {
2257 flags
.shaded
= False
;
2258 unsigned long orig_state
= current_state
;
2262 At this point in the life of a window, current_state should only be set
2263 to IconicState if the window was an *icon*, not if it was shaded.
2265 if (orig_state
!= IconicState
)
2266 current_state
= WithdrawnState
;
2269 if (net
->workspace
!= screen
->getCurrentWorkspaceID() &&
2270 net
->workspace
< screen
->getWorkspaceCount())
2271 screen
->reassociateWindow(this, net
->workspace
, True
);
2273 if ((blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID()) &&
2274 (blackbox_attrib
.workspace
< screen
->getWorkspaceCount())) {
2275 // set to WithdrawnState so it will be mapped on the new workspace
2276 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2277 } else if (current_state
== WithdrawnState
) {
2278 // the window is on this workspace and is Withdrawn, so it is waiting to
2280 current_state
= NormalState
;
2283 if (net
->flags
& AttribOmnipresent
&& net
->attrib
& AttribOmnipresent
&&
2287 // if the window was on another workspace, it was going to be hidden. this
2288 // specifies that the window should be mapped since it is sticky.
2289 if (current_state
== WithdrawnState
) current_state
= NormalState
;
2292 if (net
->flags
& AttribMaxHoriz
|| net
->flags
& AttribMaxVert
) {
2293 int x
= net
->premax_x
, y
= net
->premax_y
;
2294 unsigned int w
= net
->premax_w
, h
= net
->premax_h
;
2295 flags
.maximized
= 0;
2298 if ((net
->flags
& AttribMaxHoriz
) &&
2299 (net
->flags
& AttribMaxVert
))
2300 m
= (net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
2301 else if (net
->flags
& AttribMaxVert
)
2302 m
= (net
->attrib
& AttribMaxVert
) ? 2 : 0;
2303 else if (net
->flags
& AttribMaxHoriz
)
2304 m
= (net
->attrib
& AttribMaxHoriz
) ? 3 : 0;
2308 blackbox_attrib
.premax_x
= x
;
2309 blackbox_attrib
.premax_y
= y
;
2310 blackbox_attrib
.premax_w
= w
;
2311 blackbox_attrib
.premax_h
= h
;
2314 if (net
->flags
& AttribDecoration
) {
2315 switch (net
->decoration
) {
2320 /* since tools only let you toggle this anyways, we'll just make that all
2321 it supports for now.
2332 // with the state set it will then be the map event's job to read the
2333 // window's state and behave accordingly
2340 * Positions the Rect r according the the client window position and
2343 void BlackboxWindow::applyGravity(Rect
&r
) {
2344 // apply horizontal window gravity
2345 switch (client
.win_gravity
) {
2347 case NorthWestGravity
:
2348 case SouthWestGravity
:
2350 r
.setX(client
.rect
.x());
2356 r
.setX(client
.rect
.x() - (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2359 case NorthEastGravity
:
2360 case SouthEastGravity
:
2362 r
.setX(client
.rect
.x() - frame
.margin
.left
- frame
.margin
.right
+ 2);
2367 r
.setX(client
.rect
.x() - frame
.margin
.left
);
2371 // apply vertical window gravity
2372 switch (client
.win_gravity
) {
2374 case NorthWestGravity
:
2375 case NorthEastGravity
:
2377 r
.setY(client
.rect
.y());
2383 r
.setY(client
.rect
.y() - (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2386 case SouthWestGravity
:
2387 case SouthEastGravity
:
2389 r
.setY(client
.rect
.y() - frame
.margin
.top
- frame
.margin
.bottom
+ 2);
2394 r
.setY(client
.rect
.y() - frame
.margin
.top
);
2401 * The reverse of the applyGravity function.
2403 * Positions the Rect r according to the frame window position and
2406 void BlackboxWindow::restoreGravity(Rect
&r
) {
2407 // restore horizontal window gravity
2408 switch (client
.win_gravity
) {
2410 case NorthWestGravity
:
2411 case SouthWestGravity
:
2413 r
.setX(frame
.rect
.x());
2419 r
.setX(frame
.rect
.x() + (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2422 case NorthEastGravity
:
2423 case SouthEastGravity
:
2425 r
.setX(frame
.rect
.x() + frame
.margin
.left
+ frame
.margin
.right
- 2);
2430 r
.setX(frame
.rect
.x() + frame
.margin
.left
);
2434 // restore vertical window gravity
2435 switch (client
.win_gravity
) {
2437 case NorthWestGravity
:
2438 case NorthEastGravity
:
2440 r
.setY(frame
.rect
.y());
2446 r
.setY(frame
.rect
.y() + (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2449 case SouthWestGravity
:
2450 case SouthEastGravity
:
2452 r
.setY(frame
.rect
.y() + frame
.margin
.top
+ frame
.margin
.bottom
- 2);
2457 r
.setY(frame
.rect
.y() + frame
.margin
.top
);
2463 void BlackboxWindow::redrawLabel(void) const {
2464 if (flags
.focused
) {
2466 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2467 frame
.label
, frame
.flabel
);
2469 XSetWindowBackground(blackbox
->getXDisplay(),
2470 frame
.label
, frame
.flabel_pixel
);
2473 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2474 frame
.label
, frame
.ulabel
);
2476 XSetWindowBackground(blackbox
->getXDisplay(),
2477 frame
.label
, frame
.ulabel_pixel
);
2479 XClearWindow(blackbox
->getXDisplay(), frame
.label
);
2481 WindowStyle
*style
= screen
->getWindowStyle();
2483 int pos
= frame
.bevel_w
* 2;
2484 style
->doJustify(client
.title
.c_str(), pos
, frame
.label_w
, frame
.bevel_w
* 4);
2485 style
->font
->drawString(frame
.label
, pos
, 1,
2486 (flags
.focused
? style
->l_text_focus
:
2487 style
->l_text_unfocus
),
2492 void BlackboxWindow::redrawAllButtons(void) const {
2493 if (frame
.iconify_button
) redrawIconifyButton(False
);
2494 if (frame
.maximize_button
) redrawMaximizeButton(flags
.maximized
);
2495 if (frame
.close_button
) redrawCloseButton(False
);
2499 void BlackboxWindow::redrawIconifyButton(bool pressed
) const {
2501 if (flags
.focused
) {
2503 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2504 frame
.iconify_button
, frame
.fbutton
);
2506 XSetWindowBackground(blackbox
->getXDisplay(),
2507 frame
.iconify_button
, frame
.fbutton_pixel
);
2510 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2511 frame
.iconify_button
, frame
.ubutton
);
2513 XSetWindowBackground(blackbox
->getXDisplay(), frame
.iconify_button
,
2514 frame
.ubutton_pixel
);
2518 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2519 frame
.iconify_button
, frame
.pbutton
);
2521 XSetWindowBackground(blackbox
->getXDisplay(),
2522 frame
.iconify_button
, frame
.pbutton_pixel
);
2524 XClearWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
2526 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2527 screen
->getWindowStyle()->b_pic_unfocus
);
2528 XDrawRectangle(blackbox
->getXDisplay(), frame
.iconify_button
, pen
.gc(),
2529 2, (frame
.button_w
- 5), (frame
.button_w
- 5), 2);
2533 void BlackboxWindow::redrawMaximizeButton(bool pressed
) const {
2535 if (flags
.focused
) {
2537 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2538 frame
.maximize_button
, frame
.fbutton
);
2540 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2541 frame
.fbutton_pixel
);
2544 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2545 frame
.maximize_button
, frame
.ubutton
);
2547 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2548 frame
.ubutton_pixel
);
2552 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2553 frame
.maximize_button
, frame
.pbutton
);
2555 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2556 frame
.pbutton_pixel
);
2558 XClearWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
2560 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2561 screen
->getWindowStyle()->b_pic_unfocus
);
2562 XDrawRectangle(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2563 2, 2, (frame
.button_w
- 5), (frame
.button_w
- 5));
2564 XDrawLine(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2565 2, 3, (frame
.button_w
- 3), 3);
2569 void BlackboxWindow::redrawCloseButton(bool pressed
) const {
2571 if (flags
.focused
) {
2573 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2576 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2577 frame
.fbutton_pixel
);
2580 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2583 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2584 frame
.ubutton_pixel
);
2588 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2589 frame
.close_button
, frame
.pbutton
);
2591 XSetWindowBackground(blackbox
->getXDisplay(),
2592 frame
.close_button
, frame
.pbutton_pixel
);
2594 XClearWindow(blackbox
->getXDisplay(), frame
.close_button
);
2596 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2597 screen
->getWindowStyle()->b_pic_unfocus
);
2598 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2599 2, 2, (frame
.button_w
- 3), (frame
.button_w
- 3));
2600 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2601 2, (frame
.button_w
- 3), (frame
.button_w
- 3), 2);
2605 void BlackboxWindow::mapRequestEvent(const XMapRequestEvent
*re
) {
2606 if (re
->window
!= client
.window
)
2610 fprintf(stderr
, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2615 Even though the window wants to be shown, if it is not on the current
2616 workspace, then it isn't going to be shown right now.
2618 if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID() &&
2619 blackbox_attrib
.workspace
< screen
->getWorkspaceCount())
2620 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2622 switch (current_state
) {
2627 case WithdrawnState
:
2636 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2638 if (! blackbox
->isStartup()) {
2639 XSync(blackbox
->getXDisplay(), False
); // make sure the frame is mapped
2640 if (screen
->doFocusNew() || (isTransient() && getTransientFor() &&
2641 getTransientFor()->isFocused())) {
2644 if (screen
->getPlacementPolicy() == BScreen::ClickMousePlacement
) {
2648 XQueryPointer(blackbox
->getXDisplay(), screen
->getRootWindow(),
2649 &r
, &c
, &rx
, &ry
, &x
, &y
, &m
);
2659 void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent
*ue
) {
2660 if (ue
->window
!= client
.window
)
2664 fprintf(stderr
, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2668 screen
->unmanageWindow(this, False
);
2672 void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent
*de
) {
2673 if (de
->window
!= client
.window
)
2677 fprintf(stderr
, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2681 screen
->unmanageWindow(this, False
);
2685 void BlackboxWindow::reparentNotifyEvent(const XReparentEvent
*re
) {
2686 if (re
->window
!= client
.window
|| re
->parent
== frame
.plate
)
2690 fprintf(stderr
, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2691 "0x%lx.\n", client
.window
, re
->parent
);
2696 XPutBackEvent(blackbox
->getXDisplay(), &ev
);
2697 screen
->unmanageWindow(this, True
);
2701 void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent
*pe
) {
2702 if (pe
->state
== PropertyDelete
)
2706 fprintf(stderr
, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n",
2712 case XA_WM_CLIENT_MACHINE
:
2716 case XA_WM_TRANSIENT_FOR
: {
2717 bool s
= flags
.stuck
;
2719 // determine if this is a transient window
2722 // adjust the window decorations based on transience
2723 if (isTransient()) {
2724 functions
&= ~Func_Maximize
;
2725 setAllowedActions();
2727 if (flags
.stuck
!= s
) stick();
2738 case XA_WM_ICON_NAME
:
2740 if (flags
.iconic
) screen
->propagateWindowName(this);
2743 case XAtom::net_wm_name
:
2747 if (decorations
& Decor_Titlebar
)
2750 screen
->propagateWindowName(this);
2753 case XA_WM_NORMAL_HINTS
: {
2756 if ((client
.normal_hint_flags
& PMinSize
) &&
2757 (client
.normal_hint_flags
& PMaxSize
)) {
2758 // the window now can/can't resize itself, so the buttons need to be
2761 if (client
.max_width
<= client
.min_width
&&
2762 client
.max_height
<= client
.min_height
) {
2763 functions
&= ~(Func_Resize
| Func_Maximize
);
2765 if (! isTransient())
2766 functions
|= Func_Maximize
;
2767 functions
|= Func_Resize
;
2770 setAllowedActions();
2774 Rect old_rect
= frame
.rect
;
2778 if (old_rect
!= frame
.rect
)
2785 if (pe
->atom
== xatom
->getAtom(XAtom::wm_protocols
)) {
2788 if ((decorations
& Decor_Close
) && (! frame
.close_button
)) {
2789 createCloseButton();
2790 if (decorations
& Decor_Titlebar
) {
2791 positionButtons(True
);
2792 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
2794 if (windowmenu
) windowmenu
->reconfigure();
2796 } else if (pe
->atom
== xatom
->getAtom(XAtom::net_wm_strut
)) {
2805 void BlackboxWindow::exposeEvent(const XExposeEvent
*ee
) {
2807 fprintf(stderr
, "BlackboxWindow::exposeEvent() for 0x%lx\n", client
.window
);
2810 if (frame
.label
== ee
->window
&& (decorations
& Decor_Titlebar
))
2812 else if (frame
.close_button
== ee
->window
)
2813 redrawCloseButton(False
);
2814 else if (frame
.maximize_button
== ee
->window
)
2815 redrawMaximizeButton(flags
.maximized
);
2816 else if (frame
.iconify_button
== ee
->window
)
2817 redrawIconifyButton(False
);
2821 void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent
*cr
) {
2822 if (cr
->window
!= client
.window
|| flags
.iconic
)
2825 if (cr
->value_mask
& CWBorderWidth
)
2826 client
.old_bw
= cr
->border_width
;
2828 if (cr
->value_mask
& (CWX
| CWY
| CWWidth
| CWHeight
)) {
2829 Rect req
= frame
.rect
;
2831 if (cr
->value_mask
& (CWX
| CWY
)) {
2832 if (cr
->value_mask
& CWX
)
2833 client
.rect
.setX(cr
->x
);
2834 if (cr
->value_mask
& CWY
)
2835 client
.rect
.setY(cr
->y
);
2840 if (cr
->value_mask
& CWWidth
)
2841 req
.setWidth(cr
->width
+ frame
.margin
.left
+ frame
.margin
.right
);
2843 if (cr
->value_mask
& CWHeight
)
2844 req
.setHeight(cr
->height
+ frame
.margin
.top
+ frame
.margin
.bottom
);
2846 configure(req
.x(), req
.y(), req
.width(), req
.height());
2849 if (cr
->value_mask
& CWStackMode
&& !isDesktop()) {
2850 switch (cr
->detail
) {
2853 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2859 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2866 void BlackboxWindow::buttonPressEvent(const XButtonEvent
*be
) {
2868 fprintf(stderr
, "BlackboxWindow::buttonPressEvent() for 0x%lx\n",
2872 if (frame
.maximize_button
== be
->window
&& be
->button
<= 3) {
2873 redrawMaximizeButton(True
);
2874 } else if (be
->button
== 1 || (be
->button
== 3 && be
->state
== mod_mask
)) {
2875 if (! flags
.focused
)
2878 if (frame
.iconify_button
== be
->window
) {
2879 redrawIconifyButton(True
);
2880 } else if (frame
.close_button
== be
->window
) {
2881 redrawCloseButton(True
);
2882 } else if (frame
.plate
== be
->window
) {
2883 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2885 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2887 XAllowEvents(blackbox
->getXDisplay(), ReplayPointer
, be
->time
);
2889 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
2890 if (((be
->time
- lastButtonPressTime
) <=
2891 blackbox
->getDoubleClickInterval()) ||
2892 (be
->state
== ControlMask
)) {
2893 lastButtonPressTime
= 0;
2896 lastButtonPressTime
= be
->time
;
2900 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2902 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2904 } else if (be
->button
== 2 && (be
->window
!= frame
.iconify_button
) &&
2905 (be
->window
!= frame
.close_button
)) {
2906 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2907 } else if (windowmenu
&& be
->button
== 3 &&
2908 (frame
.title
== be
->window
|| frame
.label
== be
->window
||
2909 frame
.handle
== be
->window
|| frame
.window
== be
->window
)) {
2910 if (windowmenu
->isVisible()) {
2913 int mx
= be
->x_root
- windowmenu
->getWidth() / 2,
2914 my
= be
->y_root
- windowmenu
->getHeight() / 2;
2916 // snap the window menu into a corner/side if necessary
2917 int left_edge
, right_edge
, top_edge
, bottom_edge
;
2920 the " + (frame.border_w * 2) - 1" bits are to get the proper width
2921 and height of the menu, as the sizes returned by it do not include
2924 left_edge
= frame
.rect
.x();
2925 right_edge
= frame
.rect
.right() -
2926 (windowmenu
->getWidth() + (frame
.border_w
* 2) - 1);
2927 top_edge
= client
.rect
.top() - (frame
.border_w
+ frame
.mwm_border_w
);
2928 bottom_edge
= client
.rect
.bottom() -
2929 (windowmenu
->getHeight() + (frame
.border_w
* 2) - 1) +
2930 (frame
.border_w
+ frame
.mwm_border_w
);
2934 if (mx
> right_edge
)
2938 if (my
> bottom_edge
)
2941 windowmenu
->move(mx
, my
);
2943 XRaiseWindow(blackbox
->getXDisplay(), windowmenu
->getWindowID());
2944 XRaiseWindow(blackbox
->getXDisplay(),
2945 windowmenu
->getSendToMenu()->getWindowID());
2948 } else if (be
->button
== 4) {
2949 if ((be
->window
== frame
.label
||
2950 be
->window
== frame
.title
||
2951 be
->window
== frame
.maximize_button
||
2952 be
->window
== frame
.iconify_button
||
2953 be
->window
== frame
.close_button
) &&
2957 } else if (be
->button
== 5) {
2958 if ((be
->window
== frame
.label
||
2959 be
->window
== frame
.title
||
2960 be
->window
== frame
.maximize_button
||
2961 be
->window
== frame
.iconify_button
||
2962 be
->window
== frame
.close_button
) &&
2969 void BlackboxWindow::buttonReleaseEvent(const XButtonEvent
*re
) {
2971 fprintf(stderr
, "BlackboxWindow::buttonReleaseEvent() for 0x%lx\n",
2975 if (re
->window
== frame
.maximize_button
&&
2976 re
->button
>= 1 && re
->button
<= 3) {
2977 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2978 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2979 maximize(re
->button
);
2981 redrawMaximizeButton(flags
.maximized
);
2983 } else if (re
->window
== frame
.iconify_button
&& re
->button
== 1) {
2984 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2985 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2988 redrawIconifyButton(False
);
2990 } else if (re
->window
== frame
.close_button
& re
->button
== 1) {
2991 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2992 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
)))
2994 redrawCloseButton(False
);
2995 } else if (flags
.moving
) {
2997 } else if (flags
.resizing
) {
2999 } else if (re
->window
== frame
.window
) {
3000 if (re
->button
== 2 && re
->state
== mod_mask
)
3001 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3007 void BlackboxWindow::beginMove(int x_root
, int y_root
) {
3008 assert(! (flags
.resizing
|| flags
.moving
));
3011 Only one window can be moved/resized at a time. If another window is already
3012 being moved or resized, then stop it before whating to work with this one.
3014 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3015 if (changing
&& changing
!= this) {
3016 if (changing
->flags
.moving
)
3017 changing
->endMove();
3018 else // if (changing->flags.resizing)
3019 changing
->endResize();
3022 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3023 PointerMotionMask
| ButtonReleaseMask
,
3024 GrabModeAsync
, GrabModeAsync
,
3025 None
, blackbox
->getMoveCursor(), CurrentTime
);
3027 if (windowmenu
&& windowmenu
->isVisible())
3030 flags
.moving
= True
;
3031 blackbox
->setChangingWindow(this);
3033 if (! screen
->doOpaqueMove()) {
3034 XGrabServer(blackbox
->getXDisplay());
3036 frame
.changing
= frame
.rect
;
3037 screen
->showPosition(frame
.changing
.x(), frame
.changing
.y());
3039 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3043 frame
.changing
.width() - 1,
3044 frame
.changing
.height() - 1);
3047 frame
.grab_x
= x_root
- frame
.rect
.x() - frame
.border_w
;
3048 frame
.grab_y
= y_root
- frame
.rect
.y() - frame
.border_w
;
3052 void BlackboxWindow::doMove(int x_root
, int y_root
) {
3053 assert(flags
.moving
);
3054 assert(blackbox
->getChangingWindow() == this);
3056 int dx
= x_root
- frame
.grab_x
, dy
= y_root
- frame
.grab_y
;
3057 dx
-= frame
.border_w
;
3058 dy
-= frame
.border_w
;
3060 if (screen
->doWorkspaceWarping())
3061 if (doWorkspaceWarping(x_root
, y_root
, dx
, dy
))
3064 doWindowSnapping(dx
, dy
);
3066 if (screen
->doOpaqueMove()) {
3067 configure(dx
, dy
, frame
.rect
.width(), frame
.rect
.height());
3069 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3073 frame
.changing
.width() - 1,
3074 frame
.changing
.height() - 1);
3076 frame
.changing
.setPos(dx
, dy
);
3078 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3082 frame
.changing
.width() - 1,
3083 frame
.changing
.height() - 1);
3086 screen
->showPosition(dx
, dy
);
3090 bool BlackboxWindow::doWorkspaceWarping(int x_root
, int y_root
,
3092 // workspace warping
3094 unsigned int dest
= screen
->getCurrentWorkspaceID();
3098 if (dest
> 0) dest
--;
3099 else dest
= screen
->getNumberOfWorkspaces() - 1;
3101 } else if (x_root
>= screen
->getRect().right()) {
3104 if (dest
< screen
->getNumberOfWorkspaces() - 1) dest
++;
3111 bool focus
= flags
.focused
; // had focus while moving?
3113 screen
->reassociateWindow(this, dest
, False
);
3114 screen
->changeWorkspaceID(dest
);
3119 We grab the X server here because we are moving the window and then the
3120 mouse cursor. When one moves, it could end up putting the mouse cursor
3121 over another window for a moment. This can cause the warp to iniate a
3122 move on another window.
3124 XGrabServer(blackbox
->getXDisplay());
3127 dest_x
= screen
->getRect().right() - 1;
3128 configure(dx
+ (screen
->getRect().width() - 1), dy
,
3129 frame
.rect
.width(), frame
.rect
.height());
3132 configure(dx
- (screen
->getRect().width() - 1), dy
,
3133 frame
.rect
.width(), frame
.rect
.height());
3135 XWarpPointer(blackbox
->getXDisplay(), None
,
3136 screen
->getRootWindow(), 0, 0, 0, 0,
3138 XUngrabServer(blackbox
->getXDisplay());
3140 beginMove(dest_x
, y_root
);
3145 void BlackboxWindow::doWindowSnapping(int &dx
, int &dy
) {
3146 // how much resistance to edges to provide
3147 const int resistance_size
= screen
->getResistanceSize();
3149 // how far away to snap
3150 const int snap_distance
= screen
->getSnapThreshold();
3152 // how to snap windows
3153 const int snap_to_windows
= screen
->getWindowToWindowSnap();
3154 const int snap_to_edges
= screen
->getWindowToEdgeSnap();
3155 // the amount of space away from the edge to provide resistance/snap
3156 const int snap_offset
= screen
->getSnapOffset();
3158 // find the geomeetery where the moving window currently is
3159 const Rect
&moving
= screen
->doOpaqueMove() ? frame
.rect
: frame
.changing
;
3162 const int wleft
= dx
,
3163 wright
= dx
+ frame
.rect
.width() - 1,
3165 wbottom
= dy
+ frame
.rect
.height() - 1;
3167 if (snap_to_windows
) {
3170 Workspace
*w
= screen
->getWorkspace(getWorkspaceNumber());
3173 // add windows on the workspace to the rect list
3174 const BlackboxWindowList
& stack_list
= w
->getStackingList();
3175 BlackboxWindowList::const_iterator st_it
, st_end
= stack_list
.end();
3176 for (st_it
= stack_list
.begin(); st_it
!= st_end
; ++st_it
)
3177 if (*st_it
!= this) // don't snap to ourself
3178 rectlist
.push_back( (*st_it
)->frameRect() );
3180 // add the toolbar and the slit to the rect list.
3181 // (only if they are not hidden)
3182 Toolbar
*tbar
= screen
->getToolbar();
3183 Slit
*slit
= screen
->getSlit();
3184 Rect tbar_rect
, slit_rect
;
3185 unsigned int bwidth
= screen
->getBorderWidth() * 2;
3187 if (! (screen
->doHideToolbar() || tbar
->isHidden())) {
3188 tbar_rect
.setRect(tbar
->getX(), tbar
->getY(), tbar
->getWidth() + bwidth
,
3189 tbar
->getHeight() + bwidth
);
3190 rectlist
.push_back(tbar_rect
);
3193 if (! slit
->isHidden()) {
3194 slit_rect
.setRect(slit
->getX(), slit
->getY(), slit
->getWidth() + bwidth
,
3195 slit
->getHeight() + bwidth
);
3196 rectlist
.push_back(slit_rect
);
3199 RectList::const_iterator it
, end
= rectlist
.end();
3200 for (it
= rectlist
.begin(); it
!= end
; ++it
) {
3201 bool snapped
= False
;
3202 const Rect
&winrect
= *it
;
3204 offsetrect
.setCoords(winrect
.left() - snap_offset
,
3205 winrect
.top() - snap_offset
,
3206 winrect
.right() + snap_offset
,
3207 winrect
.bottom() + snap_offset
);
3209 if (snap_to_windows
== BScreen::WindowResistance
)
3210 // if the window is already over top of this snap target, then
3211 // resistance is futile, so just ignore it
3212 if (winrect
.intersects(moving
))
3215 int dleft
, dright
, dtop
, dbottom
;
3217 // if the windows are in the same plane vertically
3218 if (wtop
>= (signed)(winrect
.y() - frame
.rect
.height() + 1) &&
3219 wtop
< (signed)(winrect
.y() + winrect
.height() - 1)) {
3221 if (snap_to_windows
== BScreen::WindowResistance
) {
3222 dleft
= wright
- offsetrect
.left();
3223 dright
= offsetrect
.right() - wleft
;
3225 // snap left of other window?
3226 if (dleft
>= 0 && dleft
< resistance_size
&&
3227 dleft
< (wright
- wleft
)) {
3228 dx
= offsetrect
.left() - frame
.rect
.width();
3231 // snap right of other window?
3232 else if (dright
>= 0 && dright
< resistance_size
&&
3233 dright
< (wright
- wleft
)) {
3234 dx
= offsetrect
.right() + 1;
3237 } else { // BScreen::WindowSnap
3238 dleft
= abs(wright
- offsetrect
.left());
3239 dright
= abs(wleft
- offsetrect
.right());
3241 // snap left of other window?
3242 if (dleft
< snap_distance
&& dleft
<= dright
) {
3243 dx
= offsetrect
.left() - frame
.rect
.width();
3246 // snap right of other window?
3247 else if (dright
< snap_distance
) {
3248 dx
= offsetrect
.right() + 1;
3254 if (screen
->getWindowCornerSnap()) {
3255 // try corner-snap to its other sides
3256 if (snap_to_windows
== BScreen::WindowResistance
) {
3257 dtop
= winrect
.top() - wtop
;
3258 dbottom
= wbottom
- winrect
.bottom();
3259 if (dtop
> 0 && dtop
< resistance_size
) {
3260 // if we're already past the top edge, then don't provide
3262 if (moving
.top() >= winrect
.top())
3264 } else if (dbottom
> 0 && dbottom
< resistance_size
) {
3265 // if we're already past the bottom edge, then don't provide
3267 if (moving
.bottom() <= winrect
.bottom())
3268 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
3270 } else { // BScreen::WindowSnap
3271 dtop
= abs(wtop
- winrect
.top());
3272 dbottom
= abs(wbottom
- winrect
.bottom());
3273 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3275 else if (dbottom
< snap_distance
)
3276 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
3284 // if the windows are on the same plane horizontally
3285 if (wleft
>= (signed)(winrect
.x() - frame
.rect
.width() + 1) &&
3286 wleft
< (signed)(winrect
.x() + winrect
.width() - 1)) {
3288 if (snap_to_windows
== BScreen::WindowResistance
) {
3289 dtop
= wbottom
- offsetrect
.top();
3290 dbottom
= offsetrect
.bottom() - wtop
;
3292 // snap top of other window?
3293 if (dtop
>= 0 && dtop
< resistance_size
&& dtop
< (wbottom
- wtop
)) {
3294 dy
= offsetrect
.top() - frame
.rect
.height();
3297 // snap bottom of other window?
3298 else if (dbottom
>= 0 && dbottom
< resistance_size
&&
3299 dbottom
< (wbottom
- wtop
)) {
3300 dy
= offsetrect
.bottom() + 1;
3303 } else { // BScreen::WindowSnap
3304 dtop
= abs(wbottom
- offsetrect
.top());
3305 dbottom
= abs(wtop
- offsetrect
.bottom());
3307 // snap top of other window?
3308 if (dtop
< snap_distance
&& dtop
<= dbottom
) {
3309 dy
= offsetrect
.top() - frame
.rect
.height();
3312 // snap bottom of other window?
3313 else if (dbottom
< snap_distance
) {
3314 dy
= offsetrect
.bottom() + 1;
3321 if (screen
->getWindowCornerSnap()) {
3322 // try corner-snap to its other sides
3323 if (snap_to_windows
== BScreen::WindowResistance
) {
3324 dleft
= winrect
.left() - wleft
;
3325 dright
= wright
- winrect
.right();
3326 if (dleft
> 0 && dleft
< resistance_size
) {
3327 // if we're already past the left edge, then don't provide
3329 if (moving
.left() >= winrect
.left())
3330 dx
= winrect
.left();
3331 } else if (dright
> 0 && dright
< resistance_size
) {
3332 // if we're already past the right edge, then don't provide
3334 if (moving
.right() <= winrect
.right())
3335 dx
= winrect
.right() - frame
.rect
.width() + 1;
3337 } else { // BScreen::WindowSnap
3338 dleft
= abs(wleft
- winrect
.left());
3339 dright
= abs(wright
- winrect
.right());
3340 if (dleft
< snap_distance
&& dleft
<= dright
)
3341 dx
= winrect
.left();
3342 else if (dright
< snap_distance
)
3343 dx
= winrect
.right() - frame
.rect
.width() + 1;
3353 if (snap_to_edges
) {
3356 // snap to the screen edges (and screen boundaries for xinerama)
3358 if (screen
->isXineramaActive() && blackbox
->doXineramaSnapping()) {
3359 rectlist
.insert(rectlist
.begin(),
3360 screen
->getXineramaAreas().begin(),
3361 screen
->getXineramaAreas().end());
3364 rectlist
.push_back(screen
->getRect());
3366 RectList::const_iterator it
, end
= rectlist
.end();
3367 for (it
= rectlist
.begin(); it
!= end
; ++it
) {
3368 const Rect
&srect
= *it
;
3370 offsetrect
.setCoords(srect
.left() + snap_offset
,
3371 srect
.top() + snap_offset
,
3372 srect
.right() - snap_offset
,
3373 srect
.bottom() - snap_offset
);
3375 if (snap_to_edges
== BScreen::WindowResistance
) {
3376 // if we're not in the rectangle then don't snap to it.
3377 if (! srect
.contains(moving
))
3379 } else { // BScreen::WindowSnap
3380 // if we're not in the rectangle then don't snap to it.
3381 if (! srect
.intersects(Rect(wleft
, wtop
, frame
.rect
.width(),
3382 frame
.rect
.height())))
3386 if (snap_to_edges
== BScreen::WindowResistance
) {
3387 int dleft
= offsetrect
.left() - wleft
,
3388 dright
= wright
- offsetrect
.right(),
3389 dtop
= offsetrect
.top() - wtop
,
3390 dbottom
= wbottom
- offsetrect
.bottom();
3393 if (dleft
> 0 && dleft
< resistance_size
)
3394 dx
= offsetrect
.left();
3396 else if (dright
> 0 && dright
< resistance_size
)
3397 dx
= offsetrect
.right() - frame
.rect
.width() + 1;
3400 if (dtop
> 0 && dtop
< resistance_size
)
3401 dy
= offsetrect
.top();
3403 else if (dbottom
> 0 && dbottom
< resistance_size
)
3404 dy
= offsetrect
.bottom() - frame
.rect
.height() + 1;
3405 } else { // BScreen::WindowSnap
3406 int dleft
= abs(wleft
- offsetrect
.left()),
3407 dright
= abs(wright
- offsetrect
.right()),
3408 dtop
= abs(wtop
- offsetrect
.top()),
3409 dbottom
= abs(wbottom
- offsetrect
.bottom());
3412 if (dleft
< snap_distance
&& dleft
<= dright
)
3413 dx
= offsetrect
.left();
3415 else if (dright
< snap_distance
)
3416 dx
= offsetrect
.right() - frame
.rect
.width() + 1;
3419 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3420 dy
= offsetrect
.top();
3422 else if (dbottom
< snap_distance
)
3423 dy
= offsetrect
.bottom() - frame
.rect
.height() + 1;
3430 void BlackboxWindow::endMove(void) {
3431 assert(flags
.moving
);
3432 assert(blackbox
->getChangingWindow() == this);
3434 flags
.moving
= False
;
3435 blackbox
->setChangingWindow(0);
3437 if (! screen
->doOpaqueMove()) {
3438 /* when drawing the rubber band, we need to make sure we only draw inside
3439 * the frame... frame.changing_* contain the new coords for the window,
3440 * so we need to subtract 1 from changing_w/changing_h every where we
3441 * draw the rubber band (for both moving and resizing)
3443 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3444 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3445 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3446 XUngrabServer(blackbox
->getXDisplay());
3448 configure(frame
.changing
.x(), frame
.changing
.y(),
3449 frame
.changing
.width(), frame
.changing
.height());
3451 configure(frame
.rect
.x(), frame
.rect
.y(),
3452 frame
.rect
.width(), frame
.rect
.height());
3454 screen
->hideGeometry();
3456 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3458 // if there are any left over motions from the move, drop them now
3459 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3461 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3466 void BlackboxWindow::beginResize(int x_root
, int y_root
, Corner dir
) {
3467 assert(! (flags
.resizing
|| flags
.moving
));
3470 Only one window can be moved/resized at a time. If another window is already
3471 being moved or resized, then stop it before whating to work with this one.
3473 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3474 if (changing
&& changing
!= this) {
3475 if (changing
->flags
.moving
)
3476 changing
->endMove();
3477 else // if (changing->flags.resizing)
3478 changing
->endResize();
3486 switch (resize_dir
) {
3489 cursor
= blackbox
->getLowerLeftAngleCursor();
3494 cursor
= blackbox
->getLowerRightAngleCursor();
3498 anchor
= BottomRight
;
3499 cursor
= blackbox
->getUpperLeftAngleCursor();
3503 anchor
= BottomLeft
;
3504 cursor
= blackbox
->getUpperRightAngleCursor();
3508 assert(false); // unhandled Corner
3509 return; // unreachable, for the compiler
3512 XGrabServer(blackbox
->getXDisplay());
3513 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3514 PointerMotionMask
| ButtonReleaseMask
,
3515 GrabModeAsync
, GrabModeAsync
, None
, cursor
, CurrentTime
);
3517 flags
.resizing
= True
;
3518 blackbox
->setChangingWindow(this);
3520 unsigned int gw
, gh
;
3521 frame
.changing
= frame
.rect
;
3523 constrain(anchor
, &gw
, &gh
);
3525 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3526 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3527 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3529 screen
->showGeometry(gw
, gh
);
3531 frame
.grab_x
= x_root
;
3532 frame
.grab_y
= y_root
;
3536 void BlackboxWindow::doResize(int x_root
, int y_root
) {
3537 assert(flags
.resizing
);
3538 assert(blackbox
->getChangingWindow() == this);
3540 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3541 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3542 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3544 unsigned int gw
, gh
;
3547 switch (resize_dir
) {
3550 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3551 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3555 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3556 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3559 anchor
= BottomRight
;
3560 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3561 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3564 anchor
= BottomLeft
;
3565 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3566 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3570 assert(false); // unhandled Corner
3571 return; // unreachable, for the compiler
3574 constrain(anchor
, &gw
, &gh
);
3576 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3577 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3578 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3580 screen
->showGeometry(gw
, gh
);
3584 void BlackboxWindow::endResize(void) {
3585 assert(flags
.resizing
);
3586 assert(blackbox
->getChangingWindow() == this);
3588 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3589 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3590 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3591 XUngrabServer(blackbox
->getXDisplay());
3593 // unset maximized state after resized when fully maximized
3594 if (flags
.maximized
== 1)
3597 flags
.resizing
= False
;
3598 blackbox
->setChangingWindow(0);
3600 configure(frame
.changing
.x(), frame
.changing
.y(),
3601 frame
.changing
.width(), frame
.changing
.height());
3602 screen
->hideGeometry();
3604 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3606 // if there are any left over motions from the resize, drop them now
3607 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3609 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3614 void BlackboxWindow::motionNotifyEvent(const XMotionEvent
*me
) {
3616 fprintf(stderr
, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n",
3621 doMove(me
->x_root
, me
->y_root
);
3622 } else if (flags
.resizing
) {
3623 doResize(me
->x_root
, me
->y_root
);
3625 if ((functions
& Func_Move
) &&
3626 (me
->state
& Button1Mask
) &&
3627 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3628 frame
.handle
== me
->window
|| frame
.window
== me
->window
)) {
3629 beginMove(me
->x_root
, me
->y_root
);
3630 } else if ((functions
& Func_Resize
) &&
3631 ((me
->state
& Button1Mask
) && (me
->window
== frame
.right_grip
||
3632 me
->window
== frame
.left_grip
)) ||
3633 ((me
->state
& Button3Mask
) && (me
->state
& mod_mask
) &&
3634 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3635 frame
.handle
== me
->window
|| frame
.window
== me
->window
))) {
3636 unsigned int zones
= screen
->getResizeZones();
3639 if (me
->window
== frame
.left_grip
) {
3640 corner
= BottomLeft
;
3641 } else if (me
->window
== frame
.right_grip
|| zones
== 1) {
3642 corner
= BottomRight
;
3645 bool left
= (me
->x_root
- frame
.rect
.x() <=
3646 static_cast<signed>(frame
.rect
.width() / 2));
3649 else // (zones == 4)
3650 top
= (me
->y_root
- frame
.rect
.y() <=
3651 static_cast<signed>(frame
.rect
.height() / 2));
3652 corner
= (top
? (left
? TopLeft
: TopRight
) :
3653 (left
? BottomLeft
: BottomRight
));
3656 beginResize(me
->x_root
, me
->y_root
, corner
);
3662 void BlackboxWindow::enterNotifyEvent(const XCrossingEvent
* ce
) {
3663 if (! (screen
->isSloppyFocus() && isVisible() && isNormal()))
3667 bool leave
= False
, inferior
= False
;
3669 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), ce
->window
,
3671 if (e
.type
== LeaveNotify
&& e
.xcrossing
.mode
== NotifyNormal
) {
3673 inferior
= (e
.xcrossing
.detail
== NotifyInferior
);
3677 if ((! leave
|| inferior
) && ! isFocused()) {
3678 bool success
= setInputFocus();
3679 if (success
) // if focus succeeded install the colormap
3680 installColormap(True
); // XXX: shouldnt we honour no install?
3683 if (screen
->doAutoRaise())
3688 void BlackboxWindow::leaveNotifyEvent(const XCrossingEvent
*) {
3689 if (! (screen
->isSloppyFocus() && screen
->doAutoRaise() && isNormal()))
3692 installColormap(False
);
3694 if (timer
->isTiming())
3700 void BlackboxWindow::shapeEvent(XShapeEvent
*) {
3701 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
3708 bool BlackboxWindow::validateClient(void) const {
3709 XSync(blackbox
->getXDisplay(), False
);
3712 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3713 DestroyNotify
, &e
) ||
3714 XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3716 XPutBackEvent(blackbox
->getXDisplay(), &e
);
3725 void BlackboxWindow::restore(bool remap
) {
3726 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeDelete
);
3727 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
3728 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, NoEventMask
);
3730 // do not leave a shaded window as an icon unless it was an icon
3731 if (flags
.shaded
&& ! flags
.iconic
)
3732 setState(NormalState
);
3734 // erase the netwm stuff that we read when a window maps, so that it
3735 // doesn't persist between mappings.
3736 // (these are the ones read in getNetWMFlags().)
3737 xatom
->eraseValue(client
.window
, XAtom::net_wm_desktop
);
3738 xatom
->eraseValue(client
.window
, XAtom::net_wm_state
);
3740 restoreGravity(client
.rect
);
3742 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
3743 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
3745 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, client
.old_bw
);
3748 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3749 ReparentNotify
, &ev
)) {
3752 // according to the ICCCM - if the client doesn't reparent to
3753 // root, then we have to do it for them
3754 XReparentWindow(blackbox
->getXDisplay(), client
.window
,
3755 screen
->getRootWindow(),
3756 client
.rect
.x(), client
.rect
.y());
3759 if (remap
) XMapWindow(blackbox
->getXDisplay(), client
.window
);
3763 // timer for autoraise
3764 void BlackboxWindow::timeout(void) {
3765 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3769 void BlackboxWindow::changeBlackboxHints(const BlackboxHints
*net
) {
3770 if ((net
->flags
& AttribShaded
) &&
3771 ((blackbox_attrib
.attrib
& AttribShaded
) !=
3772 (net
->attrib
& AttribShaded
)))
3775 if (flags
.visible
&& // watch out for requests when we can not be seen
3776 (net
->flags
& (AttribMaxVert
| AttribMaxHoriz
)) &&
3777 ((blackbox_attrib
.attrib
& (AttribMaxVert
| AttribMaxHoriz
)) !=
3778 (net
->attrib
& (AttribMaxVert
| AttribMaxHoriz
)))) {
3779 if (flags
.maximized
) {
3784 if ((net
->flags
& AttribMaxHoriz
) && (net
->flags
& AttribMaxVert
))
3785 button
= ((net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0);
3786 else if (net
->flags
& AttribMaxVert
)
3787 button
= ((net
->attrib
& AttribMaxVert
) ? 2 : 0);
3788 else if (net
->flags
& AttribMaxHoriz
)
3789 button
= ((net
->attrib
& AttribMaxHoriz
) ? 3 : 0);
3795 if ((net
->flags
& AttribOmnipresent
) &&
3796 ((blackbox_attrib
.attrib
& AttribOmnipresent
) !=
3797 (net
->attrib
& AttribOmnipresent
)))
3800 if ((net
->flags
& AttribWorkspace
) &&
3801 (blackbox_attrib
.workspace
!= net
->workspace
)) {
3802 screen
->reassociateWindow(this, net
->workspace
, True
);
3804 if (screen
->getCurrentWorkspaceID() != net
->workspace
) {
3808 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3812 if (net
->flags
& AttribDecoration
) {
3813 switch (net
->decoration
) {
3830 * Set the sizes of all components of the window frame
3831 * (the window decorations).
3832 * These values are based upon the current style settings and the client
3833 * window's dimensions.
3835 void BlackboxWindow::upsize(void) {
3836 frame
.bevel_w
= screen
->getBevelWidth();
3838 if (decorations
& Decor_Border
) {
3839 frame
.border_w
= screen
->getBorderWidth();
3840 if (! isTransient())
3841 frame
.mwm_border_w
= screen
->getFrameWidth();
3843 frame
.mwm_border_w
= 0;
3845 frame
.mwm_border_w
= frame
.border_w
= 0;
3848 if (decorations
& Decor_Titlebar
) {
3849 // the height of the titlebar is based upon the height of the font being
3850 // used to display the window's title
3851 WindowStyle
*style
= screen
->getWindowStyle();
3852 frame
.title_h
= style
->font
->height() + (frame
.bevel_w
* 2) + 2;
3854 frame
.label_h
= frame
.title_h
- (frame
.bevel_w
* 2);
3855 frame
.button_w
= (frame
.label_h
- 2);
3857 // set the top frame margin
3858 frame
.margin
.top
= frame
.border_w
+ frame
.title_h
+
3859 frame
.border_w
+ frame
.mwm_border_w
;
3865 // set the top frame margin
3866 frame
.margin
.top
= frame
.border_w
+ frame
.mwm_border_w
;
3869 // set the left/right frame margin
3870 frame
.margin
.left
= frame
.margin
.right
= frame
.border_w
+ frame
.mwm_border_w
;
3872 if (decorations
& Decor_Handle
) {
3873 frame
.grip_w
= frame
.button_w
* 2;
3874 frame
.handle_h
= screen
->getHandleWidth();
3876 // set the bottom frame margin
3877 frame
.margin
.bottom
= frame
.border_w
+ frame
.handle_h
+
3878 frame
.border_w
+ frame
.mwm_border_w
;
3883 // set the bottom frame margin
3884 frame
.margin
.bottom
= frame
.border_w
+ frame
.mwm_border_w
;
3888 We first get the normal dimensions and use this to define the inside_w/h
3889 then we modify the height if shading is in effect.
3890 If the shade state is not considered then frame.rect gets reset to the
3891 normal window size on a reconfigure() call resulting in improper
3892 dimensions appearing in move/resize and other events.
3895 height
= client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
,
3896 width
= client
.rect
.width() + frame
.margin
.left
+ frame
.margin
.right
;
3898 frame
.inside_w
= width
- (frame
.border_w
* 2);
3899 frame
.inside_h
= height
- (frame
.border_w
* 2);
3902 height
= frame
.title_h
+ (frame
.border_w
* 2);
3903 frame
.rect
.setSize(width
, height
);
3908 * Calculate the size of the client window and constrain it to the
3909 * size specified by the size hints of the client window.
3911 * The logical width and height are placed into pw and ph, if they
3912 * are non-zero. Logical size refers to the users perception of
3913 * the window size (for example an xterm resizes in cells, not in pixels).
3914 * pw and ph are then used to display the geometry during window moves, resize,
3917 * The physical geometry is placed into frame.changing_{x,y,width,height}.
3918 * Physical geometry refers to the geometry of the window in pixels.
3920 void BlackboxWindow::constrain(Corner anchor
,
3921 unsigned int *pw
, unsigned int *ph
) {
3922 // frame.changing represents the requested frame size, we need to
3923 // strip the frame margin off and constrain the client size
3924 frame
.changing
.setCoords(frame
.changing
.left() + frame
.margin
.left
,
3925 frame
.changing
.top() + frame
.margin
.top
,
3926 frame
.changing
.right() - frame
.margin
.right
,
3927 frame
.changing
.bottom() - frame
.margin
.bottom
);
3929 unsigned int dw
= frame
.changing
.width(), dh
= frame
.changing
.height(),
3930 base_width
= (client
.base_width
) ? client
.base_width
: client
.min_width
,
3931 base_height
= (client
.base_height
) ? client
.base_height
:
3935 if (dw
< client
.min_width
) dw
= client
.min_width
;
3936 if (dh
< client
.min_height
) dh
= client
.min_height
;
3937 if (dw
> client
.max_width
) dw
= client
.max_width
;
3938 if (dh
> client
.max_height
) dh
= client
.max_height
;
3940 assert(dw
>= base_width
&& dh
>= base_height
);
3942 if (client
.width_inc
> 1) {
3944 dw
/= client
.width_inc
;
3946 if (client
.height_inc
> 1) {
3948 dh
/= client
.height_inc
;
3957 if (client
.width_inc
> 1) {
3958 dw
*= client
.width_inc
;
3961 if (client
.height_inc
> 1) {
3962 dh
*= client
.height_inc
;
3966 frame
.changing
.setSize(dw
, dh
);
3968 // add the frame margin back onto frame.changing
3969 frame
.changing
.setCoords(frame
.changing
.left() - frame
.margin
.left
,
3970 frame
.changing
.top() - frame
.margin
.top
,
3971 frame
.changing
.right() + frame
.margin
.right
,
3972 frame
.changing
.bottom() + frame
.margin
.bottom
);
3974 // move frame.changing to the specified anchor
3982 dx
= frame
.rect
.right() - frame
.changing
.right();
3986 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3990 dx
= frame
.rect
.right() - frame
.changing
.right();
3991 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3995 assert(false); // unhandled corner
3997 frame
.changing
.setPos(frame
.changing
.x() + dx
, frame
.changing
.y() + dy
);
4001 void WindowStyle::doJustify(const std::string
&text
, int &start_pos
,
4002 unsigned int max_length
,
4003 unsigned int modifier
) const {
4004 size_t text_len
= text
.size();
4005 unsigned int length
;
4008 length
= font
->measureString(string(text
, 0, text_len
)) + modifier
;
4009 } while (length
> max_length
&& text_len
-- > 0);
4013 start_pos
+= max_length
- length
;
4017 start_pos
+= (max_length
- length
) / 2;
4027 BWindowGroup::BWindowGroup(Blackbox
*b
, Window _group
)
4028 : blackbox(b
), group(_group
) {
4029 XWindowAttributes wattrib
;
4030 if (! XGetWindowAttributes(blackbox
->getXDisplay(), group
, &wattrib
)) {
4031 // group window doesn't seem to exist anymore
4036 XSelectInput(blackbox
->getXDisplay(), group
,
4037 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
4039 blackbox
->saveGroupSearch(group
, this);
4043 BWindowGroup::~BWindowGroup(void) {
4044 blackbox
->removeGroupSearch(group
);
4049 BWindowGroup::find(BScreen
*screen
, bool allow_transients
) const {
4050 BlackboxWindow
*ret
= blackbox
->getFocusedWindow();
4052 // does the focus window match (or any transient_fors)?
4053 for (; ret
; ret
= ret
->getTransientFor()) {
4054 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
&&
4055 (! ret
->isTransient() || allow_transients
))
4059 if (ret
) return ret
;
4061 // the focus window didn't match, look in the group's window list
4062 BlackboxWindowList::const_iterator it
, end
= windowList
.end();
4063 for (it
= windowList
.begin(); it
!= end
; ++it
) {
4065 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
&&
4066 (! ret
->isTransient() || allow_transients
))