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
46 #include "blackbox.hh"
49 #include "Iconmenu.hh"
55 #include "Windowmenu.hh"
56 #include "Workspace.hh"
62 * Initializes the class with default values/the window's set initial values.
64 BlackboxWindow::BlackboxWindow(Blackbox
*b
, Window w
, BScreen
*s
) {
65 // fprintf(stderr, "BlackboxWindow size: %d bytes\n",
66 // sizeof(BlackboxWindow));
69 fprintf(stderr
, "BlackboxWindow::BlackboxWindow(): creating 0x%lx\n", w
);
73 set timer to zero... it is initialized properly later, so we check
74 if timer is zero in the destructor, and assume that the window is not
75 fully constructed if timer is zero...
81 xatom
= blackbox
->getXAtom();
83 if (! validateClient()) {
88 // set the eventmask early in the game so that we make sure we get
89 // all the events we are interested in
90 XSetWindowAttributes attrib_set
;
91 attrib_set
.event_mask
= PropertyChangeMask
| FocusChangeMask
|
93 attrib_set
.do_not_propagate_mask
= ButtonPressMask
| ButtonReleaseMask
|
95 XChangeWindowAttributes(blackbox
->getXDisplay(), client
.window
,
96 CWEventMask
|CWDontPropagate
, &attrib_set
);
98 // fetch client size and placement
99 XWindowAttributes wattrib
;
100 if ((! XGetWindowAttributes(blackbox
->getXDisplay(),
101 client
.window
, &wattrib
)) ||
102 (! wattrib
.screen
) || wattrib
.override_redirect
) {
105 "BlackboxWindow::BlackboxWindow(): XGetWindowAttributes failed\n");
112 flags
.moving
= flags
.resizing
= flags
.shaded
= flags
.visible
=
113 flags
.iconic
= flags
.focused
= flags
.stuck
= flags
.modal
=
114 flags
.send_focus_message
= flags
.shaped
= flags
.skip_taskbar
=
115 flags
.skip_pager
= flags
.fullscreen
= False
;
118 blackbox_attrib
.workspace
= window_number
= BSENTINEL
;
120 blackbox_attrib
.flags
= blackbox_attrib
.attrib
= blackbox_attrib
.stack
121 = blackbox_attrib
.decoration
= 0l;
122 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
123 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
126 frame
.window
= frame
.plate
= frame
.title
= frame
.handle
= None
;
127 frame
.close_button
= frame
.iconify_button
= frame
.maximize_button
= None
;
128 frame
.right_grip
= frame
.left_grip
= None
;
130 frame
.ulabel_pixel
= frame
.flabel_pixel
= frame
.utitle_pixel
=
131 frame
.ftitle_pixel
= frame
.uhandle_pixel
= frame
.fhandle_pixel
=
132 frame
.ubutton_pixel
= frame
.fbutton_pixel
= frame
.pbutton_pixel
=
133 frame
.uborder_pixel
= frame
.fborder_pixel
= frame
.ugrip_pixel
=
134 frame
.fgrip_pixel
= 0;
135 frame
.utitle
= frame
.ftitle
= frame
.uhandle
= frame
.fhandle
= None
;
136 frame
.ulabel
= frame
.flabel
= frame
.ubutton
= frame
.fbutton
= None
;
137 frame
.pbutton
= frame
.ugrip
= frame
.fgrip
= None
;
139 decorations
= Decor_Titlebar
| Decor_Border
| Decor_Handle
|
140 Decor_Iconify
| Decor_Maximize
;
141 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
143 client
.wm_hint_flags
= client
.normal_hint_flags
= 0;
144 client
.window_group
= None
;
145 client
.transient_for
= 0;
148 get the initial size and location of client window (relative to the
149 _root window_). This position is the reference point used with the
150 window's gravity to find the window's initial position.
152 client
.rect
.setRect(wattrib
.x
, wattrib
.y
, wattrib
.width
, wattrib
.height
);
153 client
.old_bw
= wattrib
.border_width
;
156 lastButtonPressTime
= 0;
158 timer
= new BTimer(blackbox
, this);
159 timer
->setTimeout(blackbox
->getAutoRaiseDelay());
161 if (! getBlackboxHints()) {
166 // get size, aspect, minimum/maximum size and other hints set by the
172 if (client
.initial_state
== WithdrawnState
) {
173 screen
->getSlit()->addClient(client
.window
);
178 if (isKDESystrayWindow()) {
179 screen
->addSystrayWindow(client
.window
);
184 frame
.window
= createToplevelWindow();
185 frame
.plate
= createChildWindow(frame
.window
);
186 associateClientWindow();
188 blackbox
->saveWindowSearch(frame
.window
, this);
189 blackbox
->saveWindowSearch(frame
.plate
, this);
190 blackbox
->saveWindowSearch(client
.window
, this);
192 screen
->addStrut(&client
.strut
);
195 // determine if this is a transient window
198 // determine the window's type, so we can decide its decorations and
199 // functionality, or if we should not manage it at all
202 // adjust the window decorations/behavior based on the window type
203 switch (window_type
) {
205 // desktop windows are not managed by us, we just make sure they stay on the
210 // docks (such as kicker) cannot be moved, and appear on all workspaces
211 functions
&= ~(Func_Move
);
216 // these windows have minimal decorations, only a titlebar, and cannot
217 // be resized or iconified
218 decorations
&= ~(Decor_Maximize
| Decor_Handle
| Decor_Border
|
220 functions
&= ~(Func_Resize
| Func_Maximize
| Func_Iconify
);
224 // splash screens have no functionality or decorations, they are left up
225 // to the application which created them
231 // dialogs cannot be maximized, and don't display a handle
232 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
233 functions
&= ~Func_Maximize
;
237 // normal windows retain all of the possible decorations and functionality
241 // further adjeust the window's decorations/behavior based on window sizes
242 if ((client
.normal_hint_flags
& PMinSize
) &&
243 (client
.normal_hint_flags
& PMaxSize
) &&
244 client
.max_width
<= client
.min_width
&&
245 client
.max_height
<= client
.min_height
) {
246 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
247 functions
&= ~(Func_Resize
| Func_Maximize
);
253 bool place_window
= True
;
254 if (blackbox
->isStartup() || isTransient() ||
255 client
.normal_hint_flags
& (PPosition
|USPosition
)) {
256 applyGravity(frame
.rect
);
258 if (blackbox
->isStartup() ||
259 client
.rect
.intersects(screen
->availableArea()))
260 place_window
= False
;
263 if (decorations
& Decor_Titlebar
)
266 if (decorations
& Decor_Handle
)
270 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
277 windowmenu
= new Windowmenu(this);
279 if (blackbox_attrib
.workspace
>= screen
->getWorkspaceCount())
280 screen
->getCurrentWorkspace()->addWindow(this, place_window
);
282 screen
->getWorkspace(blackbox_attrib
.workspace
)->
283 addWindow(this, place_window
);
285 if (! place_window
) {
286 // don't need to call configure if we are letting the workspace
288 configure(frame
.rect
.x(), frame
.rect
.y(),
289 frame
.rect
.width(), frame
.rect
.height());
292 // preserve the window's initial state on first map, and its current state
295 if (client
.wm_hint_flags
& StateHint
)
296 current_state
= client
.initial_state
;
298 current_state
= NormalState
;
301 // get sticky state from our parent window if we've got one
302 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
303 client
.transient_for
->isStuck() != flags
.stuck
)
307 flags
.shaded
= False
;
308 unsigned long orig_state
= current_state
;
312 At this point in the life of a window, current_state should only be set
313 to IconicState if the window was an *icon*, not if it was shaded.
315 if (orig_state
!= IconicState
)
316 current_state
= NormalState
;
324 if (flags
.maximized
&& (functions
& Func_Maximize
)) {
329 When the window is mapped (and also when its attributes are restored), the
330 current_state that was set here will be used.
331 It is set to Normal if the window is to be mapped or it is set to Iconic
332 if the window is to be iconified.
333 *Note* that for sticky windows, the same rules apply here, they are in
334 fact never set to Iconic since there is no way for us to tell if a sticky
335 window was iconified previously.
341 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
347 BlackboxWindow::~BlackboxWindow(void) {
349 fprintf(stderr
, "BlackboxWindow::~BlackboxWindow: destroying 0x%lx\n",
353 if (! timer
) // window not managed...
356 screen
->removeStrut(&client
.strut
);
357 screen
->updateAvailableArea();
359 // We don't need to worry about resizing because resizing always grabs the X
360 // server. This should only ever happen if using opaque moving.
368 if (client
.window_group
) {
369 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
370 if (group
) group
->removeWindow(this);
373 // remove ourselves from our transient_for
375 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
376 client
.transient_for
->client
.transientList
.remove(this);
378 client
.transient_for
= (BlackboxWindow
*) 0;
381 if (client
.transientList
.size() > 0) {
382 // reset transient_for for all transients
383 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
384 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
385 (*it
)->client
.transient_for
= (BlackboxWindow
*) 0;
396 blackbox
->removeWindowSearch(frame
.plate
);
397 XDestroyWindow(blackbox
->getXDisplay(), frame
.plate
);
401 blackbox
->removeWindowSearch(frame
.window
);
402 XDestroyWindow(blackbox
->getXDisplay(), frame
.window
);
405 blackbox
->removeWindowSearch(client
.window
);
410 * Creates a new top level window, with a given location, size, and border
412 * Returns: the newly created window
414 Window
BlackboxWindow::createToplevelWindow(void) {
415 XSetWindowAttributes attrib_create
;
416 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
| CWColormap
|
417 CWOverrideRedirect
| CWEventMask
;
419 attrib_create
.background_pixmap
= None
;
420 attrib_create
.colormap
= screen
->getColormap();
421 attrib_create
.override_redirect
= True
;
422 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
423 ButtonMotionMask
| EnterWindowMask
;
425 return XCreateWindow(blackbox
->getXDisplay(), screen
->getRootWindow(),
426 -1, -1, 1, 1, frame
.border_w
, screen
->getDepth(),
427 InputOutput
, screen
->getVisual(), create_mask
,
433 * Creates a child window, and optionally associates a given cursor with
436 Window
BlackboxWindow::createChildWindow(Window parent
, Cursor cursor
) {
437 XSetWindowAttributes attrib_create
;
438 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
|
441 attrib_create
.background_pixmap
= None
;
442 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
443 ButtonMotionMask
| ExposureMask
;
446 create_mask
|= CWCursor
;
447 attrib_create
.cursor
= cursor
;
450 return XCreateWindow(blackbox
->getXDisplay(), parent
, 0, 0, 1, 1, 0,
451 screen
->getDepth(), InputOutput
, screen
->getVisual(),
452 create_mask
, &attrib_create
);
456 void BlackboxWindow::associateClientWindow(void) {
457 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, 0);
461 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeInsert
);
463 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, SubstructureRedirectMask
);
465 XGrabServer(blackbox
->getXDisplay());
466 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
467 XReparentWindow(blackbox
->getXDisplay(), client
.window
, frame
.plate
, 0, 0);
468 XSelectInput(blackbox
->getXDisplay(), client
.window
,
469 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
470 XUngrabServer(blackbox
->getXDisplay());
472 XRaiseWindow(blackbox
->getXDisplay(), frame
.plate
);
473 XMapSubwindows(blackbox
->getXDisplay(), frame
.plate
);
477 if (blackbox
->hasShapeExtensions()) {
478 XShapeSelectInput(blackbox
->getXDisplay(), client
.window
,
485 XShapeQueryExtents(blackbox
->getXDisplay(), client
.window
, &shaped
,
486 &foo
, &foo
, &ufoo
, &ufoo
, &foo
, &foo
, &foo
,
488 flags
.shaped
= shaped
;
494 void BlackboxWindow::decorate(void) {
497 texture
= &(screen
->getWindowStyle()->b_focus
);
498 frame
.fbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
501 frame
.fbutton_pixel
= texture
->color().pixel();
503 texture
= &(screen
->getWindowStyle()->b_unfocus
);
504 frame
.ubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
507 frame
.ubutton_pixel
= texture
->color().pixel();
509 texture
= &(screen
->getWindowStyle()->b_pressed
);
510 frame
.pbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
513 frame
.pbutton_pixel
= texture
->color().pixel();
515 if (decorations
& Decor_Titlebar
) {
516 texture
= &(screen
->getWindowStyle()->t_focus
);
517 frame
.ftitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
520 frame
.ftitle_pixel
= texture
->color().pixel();
522 texture
= &(screen
->getWindowStyle()->t_unfocus
);
523 frame
.utitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
526 frame
.utitle_pixel
= texture
->color().pixel();
528 XSetWindowBorder(blackbox
->getXDisplay(), frame
.title
,
529 screen
->getBorderColor()->pixel());
534 if (decorations
& Decor_Border
) {
535 frame
.fborder_pixel
= screen
->getWindowStyle()->f_focus
.pixel();
536 frame
.uborder_pixel
= screen
->getWindowStyle()->f_unfocus
.pixel();
537 blackbox_attrib
.flags
|= AttribDecoration
;
538 blackbox_attrib
.decoration
= DecorNormal
;
540 blackbox_attrib
.flags
|= AttribDecoration
;
541 blackbox_attrib
.decoration
= DecorNone
;
544 if (decorations
& Decor_Handle
) {
545 texture
= &(screen
->getWindowStyle()->h_focus
);
546 frame
.fhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
549 frame
.fhandle_pixel
= texture
->color().pixel();
551 texture
= &(screen
->getWindowStyle()->h_unfocus
);
552 frame
.uhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
555 frame
.uhandle_pixel
= texture
->color().pixel();
557 texture
= &(screen
->getWindowStyle()->g_focus
);
558 frame
.fgrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.fgrip
);
560 frame
.fgrip_pixel
= texture
->color().pixel();
562 texture
= &(screen
->getWindowStyle()->g_unfocus
);
563 frame
.ugrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.ugrip
);
565 frame
.ugrip_pixel
= texture
->color().pixel();
567 XSetWindowBorder(blackbox
->getXDisplay(), frame
.handle
,
568 screen
->getBorderColor()->pixel());
569 XSetWindowBorder(blackbox
->getXDisplay(), frame
.left_grip
,
570 screen
->getBorderColor()->pixel());
571 XSetWindowBorder(blackbox
->getXDisplay(), frame
.right_grip
,
572 screen
->getBorderColor()->pixel());
575 XSetWindowBorder(blackbox
->getXDisplay(), frame
.window
,
576 screen
->getBorderColor()->pixel());
580 void BlackboxWindow::decorateLabel(void) {
583 texture
= &(screen
->getWindowStyle()->l_focus
);
584 frame
.flabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.flabel
);
586 frame
.flabel_pixel
= texture
->color().pixel();
588 texture
= &(screen
->getWindowStyle()->l_unfocus
);
589 frame
.ulabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.ulabel
);
591 frame
.ulabel_pixel
= texture
->color().pixel();
595 void BlackboxWindow::createHandle(void) {
596 frame
.handle
= createChildWindow(frame
.window
);
597 blackbox
->saveWindowSearch(frame
.handle
, this);
600 createChildWindow(frame
.handle
, blackbox
->getLowerLeftAngleCursor());
601 blackbox
->saveWindowSearch(frame
.left_grip
, this);
604 createChildWindow(frame
.handle
, blackbox
->getLowerRightAngleCursor());
605 blackbox
->saveWindowSearch(frame
.right_grip
, this);
609 void BlackboxWindow::destroyHandle(void) {
611 screen
->getImageControl()->removeImage(frame
.fhandle
);
614 screen
->getImageControl()->removeImage(frame
.uhandle
);
617 screen
->getImageControl()->removeImage(frame
.fgrip
);
620 screen
->getImageControl()->removeImage(frame
.ugrip
);
622 blackbox
->removeWindowSearch(frame
.left_grip
);
623 blackbox
->removeWindowSearch(frame
.right_grip
);
625 XDestroyWindow(blackbox
->getXDisplay(), frame
.left_grip
);
626 XDestroyWindow(blackbox
->getXDisplay(), frame
.right_grip
);
627 frame
.left_grip
= frame
.right_grip
= None
;
629 blackbox
->removeWindowSearch(frame
.handle
);
630 XDestroyWindow(blackbox
->getXDisplay(), frame
.handle
);
635 void BlackboxWindow::createTitlebar(void) {
636 frame
.title
= createChildWindow(frame
.window
);
637 frame
.label
= createChildWindow(frame
.title
);
638 blackbox
->saveWindowSearch(frame
.title
, this);
639 blackbox
->saveWindowSearch(frame
.label
, this);
641 if (decorations
& Decor_Iconify
) createIconifyButton();
642 if (decorations
& Decor_Maximize
) createMaximizeButton();
643 if (decorations
& Decor_Close
) createCloseButton();
647 void BlackboxWindow::destroyTitlebar(void) {
648 if (frame
.close_button
)
649 destroyCloseButton();
651 if (frame
.iconify_button
)
652 destroyIconifyButton();
654 if (frame
.maximize_button
)
655 destroyMaximizeButton();
658 screen
->getImageControl()->removeImage(frame
.ftitle
);
661 screen
->getImageControl()->removeImage(frame
.utitle
);
664 screen
->getImageControl()->removeImage(frame
.flabel
);
667 screen
->getImageControl()->removeImage(frame
.ulabel
);
670 screen
->getImageControl()->removeImage(frame
.fbutton
);
673 screen
->getImageControl()->removeImage(frame
.ubutton
);
676 screen
->getImageControl()->removeImage(frame
.pbutton
);
678 blackbox
->removeWindowSearch(frame
.title
);
679 blackbox
->removeWindowSearch(frame
.label
);
681 XDestroyWindow(blackbox
->getXDisplay(), frame
.label
);
682 XDestroyWindow(blackbox
->getXDisplay(), frame
.title
);
683 frame
.title
= frame
.label
= None
;
687 void BlackboxWindow::createCloseButton(void) {
688 if (frame
.title
!= None
) {
689 frame
.close_button
= createChildWindow(frame
.title
);
690 blackbox
->saveWindowSearch(frame
.close_button
, this);
695 void BlackboxWindow::destroyCloseButton(void) {
696 blackbox
->removeWindowSearch(frame
.close_button
);
697 XDestroyWindow(blackbox
->getXDisplay(), frame
.close_button
);
698 frame
.close_button
= None
;
702 void BlackboxWindow::createIconifyButton(void) {
703 if (frame
.title
!= None
) {
704 frame
.iconify_button
= createChildWindow(frame
.title
);
705 blackbox
->saveWindowSearch(frame
.iconify_button
, this);
710 void BlackboxWindow::destroyIconifyButton(void) {
711 blackbox
->removeWindowSearch(frame
.iconify_button
);
712 XDestroyWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
713 frame
.iconify_button
= None
;
717 void BlackboxWindow::createMaximizeButton(void) {
718 if (frame
.title
!= None
) {
719 frame
.maximize_button
= createChildWindow(frame
.title
);
720 blackbox
->saveWindowSearch(frame
.maximize_button
, this);
725 void BlackboxWindow::destroyMaximizeButton(void) {
726 blackbox
->removeWindowSearch(frame
.maximize_button
);
727 XDestroyWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
728 frame
.maximize_button
= None
;
732 void BlackboxWindow::positionButtons(bool redecorate_label
) {
733 string layout
= blackbox
->getTitlebarLayout();
736 bool hasclose
, hasiconify
, hasmaximize
, haslabel
;
737 hasclose
= hasiconify
= hasmaximize
= haslabel
= false;
739 string::const_iterator it
, end
;
740 for (it
= layout
.begin(), end
= layout
.end(); it
!= end
; ++it
) {
743 if (! hasclose
&& (decorations
& Decor_Close
)) {
749 if (! hasiconify
&& (decorations
& Decor_Iconify
)) {
755 if (! hasmaximize
&& (decorations
& Decor_Maximize
)) {
767 if (! hasclose
&& frame
.close_button
)
768 destroyCloseButton();
769 if (! hasiconify
&& frame
.iconify_button
)
770 destroyIconifyButton();
771 if (! hasmaximize
&& frame
.maximize_button
)
772 destroyMaximizeButton();
774 parsed
+= 'L'; // require that the label be in the layout
776 const unsigned int bsep
= frame
.bevel_w
+ 1; // separation between elements
777 const unsigned int by
= frame
.bevel_w
+ 1;
778 const unsigned int ty
= frame
.bevel_w
;
780 frame
.label_w
= frame
.inside_w
- bsep
* 2 -
781 (frame
.button_w
+ bsep
) * (parsed
.size() - 1);
783 unsigned int x
= bsep
;
784 for (it
= parsed
.begin(), end
= parsed
.end(); it
!= end
; ++it
) {
787 if (! frame
.close_button
) createCloseButton();
788 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.close_button
, x
, by
,
789 frame
.button_w
, frame
.button_w
);
790 x
+= frame
.button_w
+ bsep
;
793 if (! frame
.iconify_button
) createIconifyButton();
794 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.iconify_button
, x
, by
,
795 frame
.button_w
, frame
.button_w
);
796 x
+= frame
.button_w
+ bsep
;
799 if (! frame
.maximize_button
) createMaximizeButton();
800 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.maximize_button
, x
, by
,
801 frame
.button_w
, frame
.button_w
);
802 x
+= frame
.button_w
+ bsep
;
805 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.label
, x
, ty
,
806 frame
.label_w
, frame
.label_h
);
807 x
+= frame
.label_w
+ bsep
;
812 if (redecorate_label
) decorateLabel();
818 void BlackboxWindow::reconfigure(void) {
827 windowmenu
->move(windowmenu
->getX(), frame
.rect
.y() + frame
.title_h
);
828 windowmenu
->reconfigure();
833 void BlackboxWindow::grabButtons(void) {
834 if ((! screen
->isSloppyFocus()) || screen
->doClickRaise())
835 // grab button 1 for changing focus/raising
836 blackbox
->grabButton(Button1
, 0, frame
.plate
, True
, ButtonPressMask
,
837 GrabModeSync
, GrabModeSync
, frame
.plate
, None
);
839 if (functions
& Func_Move
)
840 blackbox
->grabButton(Button1
, Mod1Mask
, frame
.window
, True
,
841 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
842 GrabModeAsync
, frame
.window
,
843 blackbox
->getMoveCursor());
844 if (functions
& Func_Resize
)
845 blackbox
->grabButton(Button3
, Mod1Mask
, frame
.window
, True
,
846 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
847 GrabModeAsync
, frame
.window
,
848 blackbox
->getLowerRightAngleCursor());
852 void BlackboxWindow::ungrabButtons(void) {
853 if ((! screen
->isSloppyFocus()) || screen
->doClickRaise())
854 blackbox
->ungrabButton(Button1
, 0, frame
.plate
);
856 blackbox
->ungrabButton(Button1
, Mod1Mask
, frame
.window
);
857 blackbox
->ungrabButton(Button3
, Mod1Mask
, frame
.window
);
861 void BlackboxWindow::positionWindows(void) {
862 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.window
,
863 frame
.rect
.x(), frame
.rect
.y(), frame
.inside_w
,
864 (flags
.shaded
) ? frame
.title_h
: frame
.inside_h
);
865 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.window
,
867 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.plate
,
869 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.plate
,
870 frame
.margin
.left
- frame
.mwm_border_w
- frame
.border_w
,
871 frame
.margin
.top
- frame
.mwm_border_w
- frame
.border_w
,
872 client
.rect
.width(), client
.rect
.height());
873 XMoveResizeWindow(blackbox
->getXDisplay(), client
.window
,
874 0, 0, client
.rect
.width(), client
.rect
.height());
875 // ensure client.rect contains the real location
876 client
.rect
.setCoords(frame
.rect
.left() + frame
.margin
.left
,
877 frame
.rect
.top() + frame
.margin
.top
,
878 frame
.rect
.right() - frame
.margin
.right
,
879 frame
.rect
.bottom() - frame
.margin
.bottom
);
881 if (decorations
& Decor_Titlebar
) {
882 if (frame
.title
== None
) createTitlebar();
884 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.title
,
886 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.title
, -frame
.border_w
,
887 -frame
.border_w
, frame
.inside_w
, frame
.title_h
);
890 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
891 XMapWindow(blackbox
->getXDisplay(), frame
.title
);
892 } else if (frame
.title
) {
895 if (decorations
& Decor_Handle
) {
896 if (frame
.handle
== None
) createHandle();
897 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.handle
,
899 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.left_grip
,
901 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.right_grip
,
904 // use client.rect here so the value is correct even if shaded
905 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.handle
,
907 client
.rect
.height() + frame
.margin
.top
+
908 frame
.mwm_border_w
- frame
.border_w
,
909 frame
.inside_w
, frame
.handle_h
);
910 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.left_grip
,
911 -frame
.border_w
, -frame
.border_w
,
912 frame
.grip_w
, frame
.handle_h
);
913 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.right_grip
,
914 frame
.inside_w
- frame
.grip_w
- frame
.border_w
,
915 -frame
.border_w
, frame
.grip_w
, frame
.handle_h
);
917 XMapSubwindows(blackbox
->getXDisplay(), frame
.handle
);
918 XMapWindow(blackbox
->getXDisplay(), frame
.handle
);
919 } else if (frame
.handle
) {
925 void BlackboxWindow::updateStrut(void) {
926 unsigned long num
= 4;
928 if (! xatom
->getValue(client
.window
, XAtom::net_wm_strut
, XAtom::cardinal
,
933 client
.strut
.left
= data
[0];
934 client
.strut
.right
= data
[1];
935 client
.strut
.top
= data
[2];
936 client
.strut
.bottom
= data
[3];
938 screen
->updateAvailableArea();
945 void BlackboxWindow::getWindowType(void) {
947 if (xatom
->getValue(client
.window
, XAtom::net_wm_window_type
, XAtom::atom
,
949 if (val
== xatom
->getAtom(XAtom::net_wm_window_type_desktop
))
950 window_type
= Type_Desktop
;
951 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_dock
))
952 window_type
= Type_Dock
;
953 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_toolbar
))
954 window_type
= Type_Toolbar
;
955 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_menu
))
956 window_type
= Type_Menu
;
957 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_utility
))
958 window_type
= Type_Utility
;
959 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_splash
))
960 window_type
= Type_Splash
;
961 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_dialog
))
962 window_type
= Type_Dialog
;
963 else //if (val[0] == xatom->getAtom(XAtom::net_wm_window_type_normal))
964 window_type
= Type_Normal
;
969 * the window type hint was not set, which means we either classify ourself
970 * as a normal window or a dialog, depending on if we are a transient.
973 window_type
= Type_Dialog
;
975 window_type
= Type_Normal
;
979 void BlackboxWindow::getWMName(void) {
980 if (xatom
->getValue(client
.window
, XAtom::net_wm_name
,
981 XAtom::utf8
, client
.title
) &&
982 !client
.title
.empty()) {
983 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
986 //fall through to using WM_NAME
987 if (xatom
->getValue(client
.window
, XAtom::wm_name
, XAtom::ansi
, client
.title
)
988 && !client
.title
.empty()) {
989 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
992 // fall back to an internal default
993 client
.title
= i18n(WindowSet
, WindowUnnamed
, "Unnamed");
994 xatom
->setValue(client
.window
, XAtom::net_wm_visible_name
, XAtom::utf8
,
999 void BlackboxWindow::getWMIconName(void) {
1000 if (xatom
->getValue(client
.window
, XAtom::net_wm_icon_name
,
1001 XAtom::utf8
, client
.icon_title
) &&
1002 !client
.icon_title
.empty()) {
1003 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1006 //fall through to using WM_ICON_NAME
1007 if (xatom
->getValue(client
.window
, XAtom::wm_icon_name
, XAtom::ansi
,
1008 client
.icon_title
) &&
1009 !client
.icon_title
.empty()) {
1010 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1013 // fall back to using the main name
1014 client
.icon_title
= client
.title
;
1015 xatom
->setValue(client
.window
, XAtom::net_wm_visible_icon_name
, XAtom::utf8
,
1021 * Retrieve which WM Protocols are supported by the client window.
1022 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
1023 * window's decorations and allow the close behavior.
1024 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
1027 void BlackboxWindow::getWMProtocols(void) {
1031 if (XGetWMProtocols(blackbox
->getXDisplay(), client
.window
,
1032 &proto
, &num_return
)) {
1033 for (int i
= 0; i
< num_return
; ++i
) {
1034 if (proto
[i
] == xatom
->getAtom(XAtom::wm_delete_window
)) {
1035 decorations
|= Decor_Close
;
1036 functions
|= Func_Close
;
1037 } else if (proto
[i
] == xatom
->getAtom(XAtom::wm_take_focus
))
1038 flags
.send_focus_message
= True
;
1039 else if (proto
[i
] == xatom
->getAtom(XAtom::blackbox_structure_messages
))
1040 screen
->addNetizen(new Netizen(screen
, client
.window
));
1049 * Gets the value of the WM_HINTS property.
1050 * If the property is not set, then use a set of default values.
1052 void BlackboxWindow::getWMHints(void) {
1053 focus_mode
= F_Passive
;
1054 client
.initial_state
= NormalState
;
1056 // remove from current window group
1057 if (client
.window_group
) {
1058 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1059 if (group
) group
->removeWindow(this);
1061 client
.window_group
= None
;
1063 XWMHints
*wmhint
= XGetWMHints(blackbox
->getXDisplay(), client
.window
);
1068 if (wmhint
->flags
& InputHint
) {
1069 if (wmhint
->input
== True
) {
1070 if (flags
.send_focus_message
)
1071 focus_mode
= F_LocallyActive
;
1073 if (flags
.send_focus_message
)
1074 focus_mode
= F_GloballyActive
;
1076 focus_mode
= F_NoInput
;
1080 if (wmhint
->flags
& StateHint
)
1081 client
.initial_state
= wmhint
->initial_state
;
1083 if (wmhint
->flags
& WindowGroupHint
) {
1084 client
.window_group
= wmhint
->window_group
;
1086 // add window to the appropriate group
1087 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1088 if (! group
) // no group found, create it!
1089 group
= new BWindowGroup(blackbox
, client
.window_group
);
1090 group
->addWindow(this);
1093 client
.wm_hint_flags
= wmhint
->flags
;
1099 * Gets the value of the WM_NORMAL_HINTS property.
1100 * If the property is not set, then use a set of default values.
1102 void BlackboxWindow::getWMNormalHints(void) {
1104 XSizeHints sizehint
;
1106 client
.min_width
= client
.min_height
=
1107 client
.width_inc
= client
.height_inc
= 1;
1108 client
.base_width
= client
.base_height
= 0;
1111 use the full screen, not the strut modified size. otherwise when the
1112 availableArea changes max_width/height will be incorrect and lead to odd
1115 const Rect
& screen_area
= screen
->getRect();
1116 client
.max_width
= screen_area
.width();
1118 client
.max_height
= screen_area
.height();
1119 client
.min_aspect_x
= client
.min_aspect_y
=
1120 client
.max_aspect_x
= client
.max_aspect_y
= 1;
1121 client
.win_gravity
= NorthWestGravity
;
1123 if (! XGetWMNormalHints(blackbox
->getXDisplay(), client
.window
,
1124 &sizehint
, &icccm_mask
))
1127 client
.normal_hint_flags
= sizehint
.flags
;
1129 if (sizehint
.flags
& PMinSize
) {
1130 client
.min_width
= sizehint
.min_width
;
1131 client
.min_height
= sizehint
.min_height
;
1134 if (sizehint
.flags
& PMaxSize
) {
1135 client
.max_width
= sizehint
.max_width
;
1136 client
.max_height
= sizehint
.max_height
;
1139 if (sizehint
.flags
& PResizeInc
) {
1140 client
.width_inc
= sizehint
.width_inc
;
1141 client
.height_inc
= sizehint
.height_inc
;
1144 if (sizehint
.flags
& PAspect
) {
1145 client
.min_aspect_x
= sizehint
.min_aspect
.x
;
1146 client
.min_aspect_y
= sizehint
.min_aspect
.y
;
1147 client
.max_aspect_x
= sizehint
.max_aspect
.x
;
1148 client
.max_aspect_y
= sizehint
.max_aspect
.y
;
1151 if (sizehint
.flags
& PBaseSize
) {
1152 client
.base_width
= sizehint
.base_width
;
1153 client
.base_height
= sizehint
.base_height
;
1156 if (sizehint
.flags
& PWinGravity
)
1157 client
.win_gravity
= sizehint
.win_gravity
;
1162 * Gets the NETWM hints for the class' contained window.
1164 void BlackboxWindow::getNetWMHints(void) {
1165 unsigned long workspace
;
1167 if (xatom
->getValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1169 if (workspace
== 0xffffffff)
1172 blackbox_attrib
.workspace
= workspace
;
1175 unsigned long *state
;
1176 unsigned long num
= (unsigned) -1;
1177 if (xatom
->getValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
1181 for (unsigned long i
= 0; i
< num
; ++i
) {
1182 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
))
1184 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_shaded
))
1185 flags
.shaded
= True
;
1186 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
))
1187 flags
.skip_taskbar
= True
;
1188 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_pager
))
1189 flags
.skip_pager
= True
;
1190 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_fullscreen
))
1191 flags
.fullscreen
= True
;
1192 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_hidden
))
1193 setState(IconicState
);
1194 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_vert
))
1196 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_horz
))
1200 flags
.maximized
= 1;
1202 flags
.maximized
= 2;
1204 flags
.maximized
= 3;
1212 * Gets the MWM hints for the class' contained window.
1213 * This is used while initializing the window to its first state, and not
1215 * Returns: true if the MWM hints are successfully retreived and applied;
1216 * false if they are not.
1218 void BlackboxWindow::getMWMHints(void) {
1222 num
= PropMwmHintsElements
;
1223 if (! xatom
->getValue(client
.window
, XAtom::motif_wm_hints
,
1224 XAtom::motif_wm_hints
, num
,
1225 (unsigned long **)&mwm_hint
))
1227 if (num
< PropMwmHintsElements
) {
1232 if (mwm_hint
->flags
& MwmHintsDecorations
) {
1233 if (mwm_hint
->decorations
& MwmDecorAll
) {
1234 decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
1235 Decor_Iconify
| Decor_Maximize
| Decor_Close
;
1239 if (mwm_hint
->decorations
& MwmDecorBorder
)
1240 decorations
|= Decor_Border
;
1241 if (mwm_hint
->decorations
& MwmDecorHandle
)
1242 decorations
|= Decor_Handle
;
1243 if (mwm_hint
->decorations
& MwmDecorTitle
)
1244 decorations
|= Decor_Titlebar
;
1245 if (mwm_hint
->decorations
& MwmDecorIconify
)
1246 decorations
|= Decor_Iconify
;
1247 if (mwm_hint
->decorations
& MwmDecorMaximize
)
1248 decorations
|= Decor_Maximize
;
1252 if (mwm_hint
->flags
& MwmHintsFunctions
) {
1253 if (mwm_hint
->functions
& MwmFuncAll
) {
1254 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
|
1259 if (mwm_hint
->functions
& MwmFuncResize
)
1260 functions
|= Func_Resize
;
1261 if (mwm_hint
->functions
& MwmFuncMove
)
1262 functions
|= Func_Move
;
1263 if (mwm_hint
->functions
& MwmFuncIconify
)
1264 functions
|= Func_Iconify
;
1265 if (mwm_hint
->functions
& MwmFuncMaximize
)
1266 functions
|= Func_Maximize
;
1267 if (mwm_hint
->functions
& MwmFuncClose
)
1268 functions
|= Func_Close
;
1276 * Gets the blackbox hints from the class' contained window.
1277 * This is used while initializing the window to its first state, and not
1279 * Returns: true if the hints are successfully retreived and applied; false if
1282 bool BlackboxWindow::getBlackboxHints(void) {
1284 BlackboxHints
*blackbox_hint
;
1286 num
= PropBlackboxHintsElements
;
1287 if (! xatom
->getValue(client
.window
, XAtom::blackbox_hints
,
1288 XAtom::blackbox_hints
, num
,
1289 (unsigned long **)&blackbox_hint
))
1291 if (num
< PropBlackboxHintsElements
) {
1292 delete [] blackbox_hint
;
1296 if (blackbox_hint
->flags
& AttribShaded
)
1297 flags
.shaded
= (blackbox_hint
->attrib
& AttribShaded
);
1299 if ((blackbox_hint
->flags
& AttribMaxHoriz
) &&
1300 (blackbox_hint
->flags
& AttribMaxVert
))
1301 flags
.maximized
= (blackbox_hint
->attrib
&
1302 (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1303 else if (blackbox_hint
->flags
& AttribMaxVert
)
1304 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxVert
) ? 2 : 0;
1305 else if (blackbox_hint
->flags
& AttribMaxHoriz
)
1306 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1308 if (blackbox_hint
->flags
& AttribOmnipresent
)
1309 flags
.stuck
= (blackbox_hint
->attrib
& AttribOmnipresent
);
1311 if (blackbox_hint
->flags
& AttribWorkspace
)
1312 blackbox_attrib
.workspace
= blackbox_hint
->workspace
;
1314 // if (blackbox_hint->flags & AttribStack)
1315 // don't yet have always on top/bottom for blackbox yet... working
1318 if (blackbox_hint
->flags
& AttribDecoration
) {
1319 switch (blackbox_hint
->decoration
) {
1321 // clear all decorations except close
1322 decorations
&= Decor_Close
;
1323 // clear all functions except close
1324 functions
&= Func_Close
;
1329 decorations
|= Decor_Titlebar
| Decor_Iconify
;
1330 decorations
&= ~(Decor_Border
| Decor_Handle
| Decor_Maximize
);
1331 functions
|= Func_Move
| Func_Iconify
;
1332 functions
&= ~(Func_Resize
| Func_Maximize
);
1337 decorations
|= Decor_Titlebar
;
1338 decorations
&= ~(Decor_Iconify
| Decor_Border
| Decor_Handle
);
1339 functions
|= Func_Move
;
1340 functions
&= ~(Func_Resize
| Func_Maximize
| Func_Iconify
);
1346 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Handle
|
1347 Decor_Iconify
| Decor_Maximize
;
1348 functions
|= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
1356 delete [] blackbox_hint
;
1362 void BlackboxWindow::getTransientInfo(void) {
1363 if (client
.transient_for
&&
1364 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1365 // the transient for hint was removed, so we need to tell our
1366 // previous transient_for that we are going away
1367 client
.transient_for
->client
.transientList
.remove(this);
1370 // we have no transient_for until we find a new one
1371 client
.transient_for
= 0;
1374 if (! XGetTransientForHint(blackbox
->getXDisplay(), client
.window
,
1376 // transient_for hint not set
1380 if (trans_for
== client
.window
) {
1381 // wierd client... treat this window as a normal window
1385 if (trans_for
== None
|| trans_for
== screen
->getRootWindow()) {
1386 // this is an undocumented interpretation of the ICCCM. a transient
1387 // associated with None/Root/itself is assumed to be a modal root
1388 // transient. we don't support the concept of a global transient,
1389 // so we just associate this transient with nothing, and perhaps
1390 // we will add support later for global modality.
1391 client
.transient_for
= (BlackboxWindow
*) ~0ul;
1396 client
.transient_for
= blackbox
->searchWindow(trans_for
);
1397 if (! client
.transient_for
&&
1398 client
.window_group
&& trans_for
== client
.window_group
) {
1399 // no direct transient_for, perhaps this is a group transient?
1400 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1401 if (group
) client
.transient_for
= group
->find(screen
);
1404 if (! client
.transient_for
|| client
.transient_for
== this) {
1405 // no transient_for found, or we have a wierd client that wants to be
1406 // a transient for itself, so we treat this window as a normal window
1407 client
.transient_for
= (BlackboxWindow
*) 0;
1411 // register ourselves with our new transient_for
1412 client
.transient_for
->client
.transientList
.push_back(this);
1413 flags
.stuck
= client
.transient_for
->flags
.stuck
;
1417 bool BlackboxWindow::isKDESystrayWindow(void) {
1419 if (xatom
->getValue(client
.window
, XAtom::kde_net_wm_system_tray_window_for
,
1420 XAtom::window
, systray
) && systray
)
1426 BlackboxWindow
*BlackboxWindow::getTransientFor(void) const {
1427 if (client
.transient_for
&&
1428 client
.transient_for
!= (BlackboxWindow
*) ~0ul)
1429 return client
.transient_for
;
1435 * This function is responsible for updating both the client and the frame
1437 * According to the ICCCM a client message is not sent for a resize, only a
1440 void BlackboxWindow::configure(int dx
, int dy
,
1441 unsigned int dw
, unsigned int dh
) {
1442 bool send_event
= (frame
.rect
.x() != dx
|| frame
.rect
.y() != dy
);
1444 if (dw
!= frame
.rect
.width() || dh
!= frame
.rect
.height()) {
1445 frame
.rect
.setRect(dx
, dy
, dw
, dh
);
1446 frame
.inside_w
= frame
.rect
.width() - (frame
.border_w
* 2);
1447 frame
.inside_h
= frame
.rect
.height() - (frame
.border_w
* 2);
1449 if (frame
.rect
.right() <= 0 || frame
.rect
.bottom() <= 0)
1450 frame
.rect
.setPos(0, 0);
1452 client
.rect
.setCoords(frame
.rect
.left() + frame
.margin
.left
,
1453 frame
.rect
.top() + frame
.margin
.top
,
1454 frame
.rect
.right() - frame
.margin
.right
,
1455 frame
.rect
.bottom() - frame
.margin
.bottom
);
1458 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
1465 redrawWindowFrame();
1467 frame
.rect
.setPos(dx
, dy
);
1469 XMoveWindow(blackbox
->getXDisplay(), frame
.window
,
1470 frame
.rect
.x(), frame
.rect
.y());
1473 if (send_event
&& ! flags
.moving
) {
1474 // if moving, the update and event will occur when the move finishes
1475 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1476 frame
.rect
.top() + frame
.margin
.top
);
1479 event
.type
= ConfigureNotify
;
1481 event
.xconfigure
.display
= blackbox
->getXDisplay();
1482 event
.xconfigure
.event
= client
.window
;
1483 event
.xconfigure
.window
= client
.window
;
1484 event
.xconfigure
.x
= client
.rect
.x();
1485 event
.xconfigure
.y
= client
.rect
.y();
1486 event
.xconfigure
.width
= client
.rect
.width();
1487 event
.xconfigure
.height
= client
.rect
.height();
1488 event
.xconfigure
.border_width
= client
.old_bw
;
1489 event
.xconfigure
.above
= frame
.window
;
1490 event
.xconfigure
.override_redirect
= False
;
1492 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1493 StructureNotifyMask
, &event
);
1494 screen
->updateNetizenConfigNotify(&event
);
1500 void BlackboxWindow::configureShape(void) {
1501 XShapeCombineShape(blackbox
->getXDisplay(), frame
.window
, ShapeBounding
,
1502 frame
.margin
.left
- frame
.border_w
,
1503 frame
.margin
.top
- frame
.border_w
,
1504 client
.window
, ShapeBounding
, ShapeSet
);
1507 XRectangle xrect
[2];
1509 if (decorations
& Decor_Titlebar
) {
1510 xrect
[0].x
= xrect
[0].y
= -frame
.border_w
;
1511 xrect
[0].width
= frame
.rect
.width();
1512 xrect
[0].height
= frame
.title_h
+ (frame
.border_w
* 2);
1516 if (decorations
& Decor_Handle
) {
1517 xrect
[1].x
= -frame
.border_w
;
1518 xrect
[1].y
= frame
.rect
.height() - frame
.margin
.bottom
+
1519 frame
.mwm_border_w
- frame
.border_w
;
1520 xrect
[1].width
= frame
.rect
.width();
1521 xrect
[1].height
= frame
.handle_h
+ (frame
.border_w
* 2);
1525 XShapeCombineRectangles(blackbox
->getXDisplay(), frame
.window
,
1526 ShapeBounding
, 0, 0, xrect
, num
,
1527 ShapeUnion
, Unsorted
);
1532 bool BlackboxWindow::setInputFocus(void) {
1533 if (flags
.focused
) return True
;
1535 assert(! flags
.iconic
&&
1536 (flags
.stuck
|| // window must be on the current workspace or sticky
1537 blackbox_attrib
.workspace
== screen
->getCurrentWorkspaceID()));
1539 // if the window is not visible, mark the window as wanting focus rather
1540 // than give it focus.
1541 if (! flags
.visible
) {
1542 Workspace
*wkspc
= screen
->getWorkspace(blackbox_attrib
.workspace
);
1543 wkspc
->setLastFocusedWindow(this);
1547 if (! frame
.rect
.intersects(screen
->getRect())) {
1548 // client is outside the screen, move it to the center
1549 configure((screen
->getWidth() - frame
.rect
.width()) / 2,
1550 (screen
->getHeight() - frame
.rect
.height()) / 2,
1551 frame
.rect
.width(), frame
.rect
.height());
1554 if (client
.transientList
.size() > 0) {
1555 // transfer focus to any modal transients
1556 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1557 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1558 if ((*it
)->flags
.modal
) return (*it
)->setInputFocus();
1563 if (focus_mode
== F_LocallyActive
|| focus_mode
== F_Passive
) {
1564 XSetInputFocus(blackbox
->getXDisplay(), client
.window
,
1565 RevertToPointerRoot
, CurrentTime
);
1567 blackbox
->setFocusedWindow(this);
1569 /* we could set the focus to none, since the window doesn't accept focus,
1570 * but we shouldn't set focus to nothing since this would surely make
1576 if (flags
.send_focus_message
) {
1578 ce
.xclient
.type
= ClientMessage
;
1579 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1580 ce
.xclient
.display
= blackbox
->getXDisplay();
1581 ce
.xclient
.window
= client
.window
;
1582 ce
.xclient
.format
= 32;
1583 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_take_focus
);
1584 ce
.xclient
.data
.l
[1] = blackbox
->getLastTime();
1585 ce
.xclient
.data
.l
[2] = 0l;
1586 ce
.xclient
.data
.l
[3] = 0l;
1587 ce
.xclient
.data
.l
[4] = 0l;
1588 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1596 void BlackboxWindow::iconify(void) {
1597 if (flags
.iconic
) return;
1599 // We don't need to worry about resizing because resizing always grabs the X
1600 // server. This should only ever happen if using opaque moving.
1604 if (windowmenu
) windowmenu
->hide();
1607 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1608 * we need to clear the event mask on client.window for a split second.
1609 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1610 * split second, leaving us with a ghost window... so, we need to do this
1611 * while the X server is grabbed
1613 XGrabServer(blackbox
->getXDisplay());
1614 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
1615 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1616 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1617 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
1618 XUngrabServer(blackbox
->getXDisplay());
1620 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1621 flags
.visible
= False
;
1622 flags
.iconic
= True
;
1624 setState(IconicState
);
1626 screen
->getWorkspace(blackbox_attrib
.workspace
)->removeWindow(this);
1628 if (isTransient()) {
1629 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1630 ! client
.transient_for
->flags
.iconic
) {
1631 // iconify our transient_for
1632 client
.transient_for
->iconify();
1636 screen
->addIcon(this);
1638 if (client
.transientList
.size() > 0) {
1639 // iconify all transients
1640 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1641 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1642 if (! (*it
)->flags
.iconic
) (*it
)->iconify();
1648 void BlackboxWindow::show(void) {
1649 flags
.visible
= True
;
1650 flags
.iconic
= False
;
1652 current_state
= (flags
.shaded
) ? IconicState
: NormalState
;
1653 setState(current_state
);
1655 XMapWindow(blackbox
->getXDisplay(), client
.window
);
1656 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
1657 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
1662 XTranslateCoordinates(blackbox
->getXDisplay(), client
.window
,
1663 screen
->getRootWindow(),
1664 0, 0, &real_x
, &real_y
, &child
);
1665 fprintf(stderr
, "%s -- assumed: (%d, %d), real: (%d, %d)\n", getTitle(),
1666 client
.rect
.left(), client
.rect
.top(), real_x
, real_y
);
1667 assert(client
.rect
.left() == real_x
&& client
.rect
.top() == real_y
);
1672 void BlackboxWindow::deiconify(bool reassoc
, bool raise
) {
1673 if (flags
.iconic
|| reassoc
)
1674 screen
->reassociateWindow(this, BSENTINEL
, False
);
1675 else if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID())
1680 // reassociate and deiconify all transients
1681 if (reassoc
&& client
.transientList
.size() > 0) {
1682 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1683 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1684 (*it
)->deiconify(True
, False
);
1689 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1693 void BlackboxWindow::close(void) {
1695 ce
.xclient
.type
= ClientMessage
;
1696 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1697 ce
.xclient
.display
= blackbox
->getXDisplay();
1698 ce
.xclient
.window
= client
.window
;
1699 ce
.xclient
.format
= 32;
1700 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_delete_window
);
1701 ce
.xclient
.data
.l
[1] = CurrentTime
;
1702 ce
.xclient
.data
.l
[2] = 0l;
1703 ce
.xclient
.data
.l
[3] = 0l;
1704 ce
.xclient
.data
.l
[4] = 0l;
1705 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
, NoEventMask
, &ce
);
1709 void BlackboxWindow::withdraw(void) {
1710 // We don't need to worry about resizing because resizing always grabs the X
1711 // server. This should only ever happen if using opaque moving.
1715 flags
.visible
= False
;
1716 flags
.iconic
= False
;
1718 setState(current_state
);
1720 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1722 XGrabServer(blackbox
->getXDisplay());
1724 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
1725 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1726 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1727 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
1729 XUngrabServer(blackbox
->getXDisplay());
1731 if (windowmenu
) windowmenu
->hide();
1735 void BlackboxWindow::maximize(unsigned int button
) {
1736 // We don't need to worry about resizing because resizing always grabs the X
1737 // server. This should only ever happen if using opaque moving.
1741 // handle case where menu is open then the max button is used instead
1742 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
1744 if (flags
.maximized
) {
1745 flags
.maximized
= 0;
1747 blackbox_attrib
.flags
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1748 blackbox_attrib
.attrib
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1751 when a resize finishes, maximize(0) is called to clear any maximization
1752 flags currently set. Otherwise it still thinks it is maximized.
1753 so we do not need to call configure() because resizing will handle it
1755 if (! flags
.resizing
)
1756 configure(blackbox_attrib
.premax_x
, blackbox_attrib
.premax_y
,
1757 blackbox_attrib
.premax_w
, blackbox_attrib
.premax_h
);
1759 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
1760 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
1762 redrawAllButtons(); // in case it is not called in configure()
1763 setState(current_state
);
1767 blackbox_attrib
.premax_x
= frame
.rect
.x();
1768 blackbox_attrib
.premax_y
= frame
.rect
.y();
1769 blackbox_attrib
.premax_w
= frame
.rect
.width();
1770 // use client.rect so that clients can be restored even if shaded
1771 blackbox_attrib
.premax_h
=
1772 client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
;
1774 const Rect
&screen_area
= screen
->availableArea();
1775 frame
.changing
= screen_area
;
1779 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1780 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1784 blackbox_attrib
.flags
|= AttribMaxVert
;
1785 blackbox_attrib
.attrib
|= AttribMaxVert
;
1787 frame
.changing
.setX(frame
.rect
.x());
1788 frame
.changing
.setWidth(frame
.rect
.width());
1792 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1793 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1795 frame
.changing
.setY(frame
.rect
.y());
1796 frame
.changing
.setHeight(frame
.rect
.height());
1803 blackbox_attrib
.flags
^= AttribShaded
;
1804 blackbox_attrib
.attrib
^= AttribShaded
;
1805 flags
.shaded
= False
;
1808 flags
.maximized
= button
;
1810 configure(frame
.changing
.x(), frame
.changing
.y(),
1811 frame
.changing
.width(), frame
.changing
.height());
1813 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1814 redrawAllButtons(); // in case it is not called in configure()
1815 setState(current_state
);
1819 // re-maximizes the window to take into account availableArea changes
1820 void BlackboxWindow::remaximize(void) {
1821 // save the original dimensions because maximize will wipe them out
1822 int premax_x
= blackbox_attrib
.premax_x
,
1823 premax_y
= blackbox_attrib
.premax_y
,
1824 premax_w
= blackbox_attrib
.premax_w
,
1825 premax_h
= blackbox_attrib
.premax_h
;
1827 unsigned int button
= flags
.maximized
;
1828 flags
.maximized
= 0; // trick maximize() into working
1831 // restore saved values
1832 blackbox_attrib
.premax_x
= premax_x
;
1833 blackbox_attrib
.premax_y
= premax_y
;
1834 blackbox_attrib
.premax_w
= premax_w
;
1835 blackbox_attrib
.premax_h
= premax_h
;
1839 void BlackboxWindow::setWorkspace(unsigned int n
) {
1840 blackbox_attrib
.flags
|= AttribWorkspace
;
1841 blackbox_attrib
.workspace
= n
;
1842 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
, n
);
1846 void BlackboxWindow::shade(void) {
1848 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1849 frame
.inside_w
, frame
.inside_h
);
1850 flags
.shaded
= False
;
1851 blackbox_attrib
.flags
^= AttribShaded
;
1852 blackbox_attrib
.attrib
^= AttribShaded
;
1854 setState(NormalState
);
1856 // set the frame rect to the normal size
1857 frame
.rect
.setHeight(client
.rect
.height() + frame
.margin
.top
+
1858 frame
.margin
.bottom
);
1860 if (! (decorations
& Decor_Titlebar
))
1861 return; // can't shade it without a titlebar!
1863 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1864 frame
.inside_w
, frame
.title_h
);
1865 flags
.shaded
= True
;
1866 blackbox_attrib
.flags
|= AttribShaded
;
1867 blackbox_attrib
.attrib
|= AttribShaded
;
1869 setState(IconicState
);
1871 // set the frame rect to the shaded size
1872 frame
.rect
.setHeight(frame
.title_h
+ (frame
.border_w
* 2));
1878 * (Un)Sticks a window and its relatives.
1880 void BlackboxWindow::stick(void) {
1882 blackbox_attrib
.flags
^= AttribOmnipresent
;
1883 blackbox_attrib
.attrib
^= AttribOmnipresent
;
1885 flags
.stuck
= False
;
1888 screen
->reassociateWindow(this, BSENTINEL
, True
);
1890 // temporary fix since sticky windows suck. set the hint to what we
1891 // actually hold in our data.
1892 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1893 blackbox_attrib
.workspace
);
1895 setState(current_state
);
1899 blackbox_attrib
.flags
|= AttribOmnipresent
;
1900 blackbox_attrib
.attrib
|= AttribOmnipresent
;
1902 // temporary fix since sticky windows suck. set the hint to a different
1903 // value than that contained in the class' data.
1904 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1907 setState(current_state
);
1910 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1911 client
.transient_for
->isStuck() != flags
.stuck
)
1912 client
.transient_for
->stick();
1913 // go down the chain
1914 BlackboxWindowList::iterator it
;
1915 const BlackboxWindowList::iterator end
= client
.transientList
.end();
1916 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1917 if ((*it
)->isStuck() != flags
.stuck
)
1922 void BlackboxWindow::redrawWindowFrame(void) const {
1923 if (decorations
& Decor_Titlebar
) {
1924 if (flags
.focused
) {
1926 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1927 frame
.title
, frame
.ftitle
);
1929 XSetWindowBackground(blackbox
->getXDisplay(),
1930 frame
.title
, frame
.ftitle_pixel
);
1933 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1934 frame
.title
, frame
.utitle
);
1936 XSetWindowBackground(blackbox
->getXDisplay(),
1937 frame
.title
, frame
.utitle_pixel
);
1939 XClearWindow(blackbox
->getXDisplay(), frame
.title
);
1945 if (decorations
& Decor_Handle
) {
1946 if (flags
.focused
) {
1948 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1949 frame
.handle
, frame
.fhandle
);
1951 XSetWindowBackground(blackbox
->getXDisplay(),
1952 frame
.handle
, frame
.fhandle_pixel
);
1955 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1956 frame
.left_grip
, frame
.fgrip
);
1957 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1958 frame
.right_grip
, frame
.fgrip
);
1960 XSetWindowBackground(blackbox
->getXDisplay(),
1961 frame
.left_grip
, frame
.fgrip_pixel
);
1962 XSetWindowBackground(blackbox
->getXDisplay(),
1963 frame
.right_grip
, frame
.fgrip_pixel
);
1967 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1968 frame
.handle
, frame
.uhandle
);
1970 XSetWindowBackground(blackbox
->getXDisplay(),
1971 frame
.handle
, frame
.uhandle_pixel
);
1974 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1975 frame
.left_grip
, frame
.ugrip
);
1976 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1977 frame
.right_grip
, frame
.ugrip
);
1979 XSetWindowBackground(blackbox
->getXDisplay(),
1980 frame
.left_grip
, frame
.ugrip_pixel
);
1981 XSetWindowBackground(blackbox
->getXDisplay(),
1982 frame
.right_grip
, frame
.ugrip_pixel
);
1985 XClearWindow(blackbox
->getXDisplay(), frame
.handle
);
1986 XClearWindow(blackbox
->getXDisplay(), frame
.left_grip
);
1987 XClearWindow(blackbox
->getXDisplay(), frame
.right_grip
);
1990 if (decorations
& Decor_Border
) {
1992 XSetWindowBorder(blackbox
->getXDisplay(),
1993 frame
.plate
, frame
.fborder_pixel
);
1995 XSetWindowBorder(blackbox
->getXDisplay(),
1996 frame
.plate
, frame
.uborder_pixel
);
2001 void BlackboxWindow::setFocusFlag(bool focus
) {
2002 // only focus a window if it is visible
2003 if (focus
&& !flags
.visible
)
2006 flags
.focused
= focus
;
2008 redrawWindowFrame();
2010 if (screen
->isSloppyFocus() && screen
->doAutoRaise()) {
2011 if (isFocused()) timer
->start();
2016 blackbox
->setFocusedWindow(this);
2020 void BlackboxWindow::installColormap(bool install
) {
2021 int i
= 0, ncmap
= 0;
2022 Colormap
*cmaps
= XListInstalledColormaps(blackbox
->getXDisplay(),
2023 client
.window
, &ncmap
);
2025 XWindowAttributes wattrib
;
2026 if (XGetWindowAttributes(blackbox
->getXDisplay(),
2027 client
.window
, &wattrib
)) {
2029 // install the window's colormap
2030 for (i
= 0; i
< ncmap
; i
++) {
2031 if (*(cmaps
+ i
) == wattrib
.colormap
)
2032 // this window is using an installed color map... do not install
2035 // otherwise, install the window's colormap
2037 XInstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2039 // uninstall the window's colormap
2040 for (i
= 0; i
< ncmap
; i
++) {
2041 if (*(cmaps
+ i
) == wattrib
.colormap
)
2042 // we found the colormap to uninstall
2043 XUninstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2053 void BlackboxWindow::setAllowedActions(void) {
2057 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_shade
);
2058 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_change_desktop
);
2059 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_close
);
2061 if (functions
& Func_Move
)
2062 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_move
);
2063 if (functions
& Func_Resize
)
2064 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_resize
);
2065 if (functions
& Func_Maximize
) {
2066 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_horz
);
2067 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_vert
);
2070 xatom
->setValue(client
.window
, XAtom::net_wm_allowed_actions
, XAtom::atom
,
2075 void BlackboxWindow::setState(unsigned long new_state
) {
2076 current_state
= new_state
;
2078 unsigned long state
[2];
2079 state
[0] = current_state
;
2081 xatom
->setValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
, state
, 2);
2083 xatom
->setValue(client
.window
, XAtom::blackbox_attributes
,
2084 XAtom::blackbox_attributes
, (unsigned long *)&blackbox_attrib
,
2085 PropBlackboxAttributesElements
);
2090 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_modal
);
2092 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_shaded
);
2094 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_hidden
);
2095 if (flags
.skip_taskbar
)
2096 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
);
2097 if (flags
.skip_pager
)
2098 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_pager
);
2099 if (flags
.fullscreen
)
2100 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_fullscreen
);
2101 if (flags
.maximized
== 1 || flags
.maximized
== 2)
2102 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_vert
);
2103 if (flags
.maximized
== 1 || flags
.maximized
== 3)
2104 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_horz
);
2105 xatom
->setValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
2110 bool BlackboxWindow::getState(void) {
2111 bool ret
= xatom
->getValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
,
2113 if (! ret
) current_state
= 0;
2118 void BlackboxWindow::restoreAttributes(void) {
2119 unsigned long num
= PropBlackboxAttributesElements
;
2120 BlackboxAttributes
*net
;
2121 if (! xatom
->getValue(client
.window
, XAtom::blackbox_attributes
,
2122 XAtom::blackbox_attributes
, num
,
2123 (unsigned long **)&net
))
2125 if (num
< PropBlackboxAttributesElements
) {
2130 if (net
->flags
& AttribShaded
&& net
->attrib
& AttribShaded
) {
2131 flags
.shaded
= False
;
2132 unsigned long orig_state
= current_state
;
2136 At this point in the life of a window, current_state should only be set
2137 to IconicState if the window was an *icon*, not if it was shaded.
2139 if (orig_state
!= IconicState
)
2140 current_state
= WithdrawnState
;
2143 if (net
->workspace
!= screen
->getCurrentWorkspaceID() &&
2144 net
->workspace
< screen
->getWorkspaceCount())
2145 screen
->reassociateWindow(this, net
->workspace
, True
);
2147 if ((blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID()) &&
2148 (blackbox_attrib
.workspace
< screen
->getWorkspaceCount())) {
2149 // set to WithdrawnState so it will be mapped on the new workspace
2150 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2151 } else if (current_state
== WithdrawnState
) {
2152 // the window is on this workspace and is Withdrawn, so it is waiting to
2154 current_state
= NormalState
;
2157 if (net
->flags
& AttribOmnipresent
&& net
->attrib
& AttribOmnipresent
) {
2158 flags
.stuck
= False
;
2161 // if the window was on another workspace, it was going to be hidden. this
2162 // specifies that the window should be mapped since it is sticky.
2163 if (current_state
== WithdrawnState
) current_state
= NormalState
;
2166 if (net
->flags
& AttribMaxHoriz
|| net
->flags
& AttribMaxVert
) {
2167 int x
= net
->premax_x
, y
= net
->premax_y
;
2168 unsigned int w
= net
->premax_w
, h
= net
->premax_h
;
2169 flags
.maximized
= 0;
2172 if ((net
->flags
& AttribMaxHoriz
) &&
2173 (net
->flags
& AttribMaxVert
))
2174 m
= (net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
2175 else if (net
->flags
& AttribMaxVert
)
2176 m
= (net
->attrib
& AttribMaxVert
) ? 2 : 0;
2177 else if (net
->flags
& AttribMaxHoriz
)
2178 m
= (net
->attrib
& AttribMaxHoriz
) ? 3 : 0;
2182 blackbox_attrib
.premax_x
= x
;
2183 blackbox_attrib
.premax_y
= y
;
2184 blackbox_attrib
.premax_w
= w
;
2185 blackbox_attrib
.premax_h
= h
;
2188 // with the state set it will then be the map event's job to read the
2189 // window's state and behave accordingly
2196 * Positions the Rect r according the the client window position and
2199 void BlackboxWindow::applyGravity(Rect
&r
) {
2200 // apply horizontal window gravity
2201 switch (client
.win_gravity
) {
2203 case NorthWestGravity
:
2204 case SouthWestGravity
:
2206 r
.setX(client
.rect
.x());
2212 r
.setX(client
.rect
.x() - (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2215 case NorthEastGravity
:
2216 case SouthEastGravity
:
2218 r
.setX(client
.rect
.x() - frame
.margin
.left
- frame
.margin
.right
);
2223 r
.setX(client
.rect
.x() - frame
.margin
.left
);
2227 // apply vertical window gravity
2228 switch (client
.win_gravity
) {
2230 case NorthWestGravity
:
2231 case NorthEastGravity
:
2233 r
.setY(client
.rect
.y());
2239 r
.setY(client
.rect
.y() - (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2242 case SouthWestGravity
:
2243 case SouthEastGravity
:
2245 r
.setY(client
.rect
.y() - frame
.margin
.top
- frame
.margin
.bottom
);
2250 r
.setY(client
.rect
.y() - frame
.margin
.top
);
2257 * The reverse of the applyGravity function.
2259 * Positions the Rect r according to the frame window position and
2262 void BlackboxWindow::restoreGravity(Rect
&r
) {
2263 // restore horizontal window gravity
2264 switch (client
.win_gravity
) {
2266 case NorthWestGravity
:
2267 case SouthWestGravity
:
2269 r
.setX(frame
.rect
.x());
2275 r
.setX(frame
.rect
.x() + (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2278 case NorthEastGravity
:
2279 case SouthEastGravity
:
2281 r
.setX(frame
.rect
.x() + frame
.margin
.left
+ frame
.margin
.right
);
2286 r
.setX(frame
.rect
.x() + frame
.margin
.left
);
2290 // restore vertical window gravity
2291 switch (client
.win_gravity
) {
2293 case NorthWestGravity
:
2294 case NorthEastGravity
:
2296 r
.setY(frame
.rect
.y());
2302 r
.setY(frame
.rect
.y() + (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2305 case SouthWestGravity
:
2306 case SouthEastGravity
:
2308 r
.setY(frame
.rect
.y() + frame
.margin
.top
+ frame
.margin
.bottom
);
2313 r
.setY(frame
.rect
.y() + frame
.margin
.top
);
2319 void BlackboxWindow::redrawLabel(void) const {
2320 if (flags
.focused
) {
2322 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2323 frame
.label
, frame
.flabel
);
2325 XSetWindowBackground(blackbox
->getXDisplay(),
2326 frame
.label
, frame
.flabel_pixel
);
2329 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2330 frame
.label
, frame
.ulabel
);
2332 XSetWindowBackground(blackbox
->getXDisplay(),
2333 frame
.label
, frame
.ulabel_pixel
);
2335 XClearWindow(blackbox
->getXDisplay(), frame
.label
);
2337 WindowStyle
*style
= screen
->getWindowStyle();
2339 int pos
= frame
.bevel_w
* 2;
2340 style
->doJustify(client
.title
.c_str(), pos
, frame
.label_w
, frame
.bevel_w
* 4);
2341 style
->font
->drawString(frame
.label
, pos
, 1,
2342 (flags
.focused
? style
->l_text_focus
:
2343 style
->l_text_unfocus
),
2348 void BlackboxWindow::redrawAllButtons(void) const {
2349 if (frame
.iconify_button
) redrawIconifyButton(False
);
2350 if (frame
.maximize_button
) redrawMaximizeButton(flags
.maximized
);
2351 if (frame
.close_button
) redrawCloseButton(False
);
2355 void BlackboxWindow::redrawIconifyButton(bool pressed
) const {
2357 if (flags
.focused
) {
2359 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2360 frame
.iconify_button
, frame
.fbutton
);
2362 XSetWindowBackground(blackbox
->getXDisplay(),
2363 frame
.iconify_button
, frame
.fbutton_pixel
);
2366 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2367 frame
.iconify_button
, frame
.ubutton
);
2369 XSetWindowBackground(blackbox
->getXDisplay(), frame
.iconify_button
,
2370 frame
.ubutton_pixel
);
2374 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2375 frame
.iconify_button
, frame
.pbutton
);
2377 XSetWindowBackground(blackbox
->getXDisplay(),
2378 frame
.iconify_button
, frame
.pbutton_pixel
);
2380 XClearWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
2382 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2383 screen
->getWindowStyle()->b_pic_unfocus
);
2384 XDrawRectangle(blackbox
->getXDisplay(), frame
.iconify_button
, pen
.gc(),
2385 2, (frame
.button_w
- 5), (frame
.button_w
- 5), 2);
2389 void BlackboxWindow::redrawMaximizeButton(bool pressed
) const {
2391 if (flags
.focused
) {
2393 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2394 frame
.maximize_button
, frame
.fbutton
);
2396 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2397 frame
.fbutton_pixel
);
2400 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2401 frame
.maximize_button
, frame
.ubutton
);
2403 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2404 frame
.ubutton_pixel
);
2408 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2409 frame
.maximize_button
, frame
.pbutton
);
2411 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2412 frame
.pbutton_pixel
);
2414 XClearWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
2416 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2417 screen
->getWindowStyle()->b_pic_unfocus
);
2418 XDrawRectangle(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2419 2, 2, (frame
.button_w
- 5), (frame
.button_w
- 5));
2420 XDrawLine(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2421 2, 3, (frame
.button_w
- 3), 3);
2425 void BlackboxWindow::redrawCloseButton(bool pressed
) const {
2427 if (flags
.focused
) {
2429 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2432 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2433 frame
.fbutton_pixel
);
2436 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2439 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2440 frame
.ubutton_pixel
);
2444 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2445 frame
.close_button
, frame
.pbutton
);
2447 XSetWindowBackground(blackbox
->getXDisplay(),
2448 frame
.close_button
, frame
.pbutton_pixel
);
2450 XClearWindow(blackbox
->getXDisplay(), frame
.close_button
);
2452 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2453 screen
->getWindowStyle()->b_pic_unfocus
);
2454 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2455 2, 2, (frame
.button_w
- 3), (frame
.button_w
- 3));
2456 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2457 2, (frame
.button_w
- 3), (frame
.button_w
- 3), 2);
2461 void BlackboxWindow::mapRequestEvent(const XMapRequestEvent
*re
) {
2462 if (re
->window
!= client
.window
)
2466 fprintf(stderr
, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2470 switch (current_state
) {
2475 case WithdrawnState
:
2484 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2485 if (! blackbox
->isStartup() && (isTransient() || screen
->doFocusNew())) {
2486 XSync(blackbox
->getXDisplay(), False
); // make sure the frame is mapped..
2494 void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent
*ue
) {
2495 if (ue
->window
!= client
.window
)
2499 fprintf(stderr
, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2503 screen
->unmanageWindow(this, False
);
2507 void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent
*de
) {
2508 if (de
->window
!= client
.window
)
2512 fprintf(stderr
, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2516 screen
->unmanageWindow(this, False
);
2520 void BlackboxWindow::reparentNotifyEvent(const XReparentEvent
*re
) {
2521 if (re
->window
!= client
.window
|| re
->parent
== frame
.plate
)
2525 fprintf(stderr
, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2526 "0x%lx.\n", client
.window
, re
->parent
);
2531 XPutBackEvent(blackbox
->getXDisplay(), &ev
);
2532 screen
->unmanageWindow(this, True
);
2536 void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent
*pe
) {
2537 if (pe
->state
== PropertyDelete
)
2541 fprintf(stderr
, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n",
2547 case XA_WM_CLIENT_MACHINE
:
2551 case XA_WM_TRANSIENT_FOR
: {
2552 // determine if this is a transient window
2555 // adjust the window decorations based on transience
2556 if (isTransient()) {
2557 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2558 functions
&= ~Func_Maximize
;
2559 setAllowedActions();
2570 case XA_WM_ICON_NAME
:
2572 if (flags
.iconic
) screen
->propagateWindowName(this);
2575 case XAtom::net_wm_name
:
2579 if (decorations
& Decor_Titlebar
)
2582 screen
->propagateWindowName(this);
2585 case XA_WM_NORMAL_HINTS
: {
2588 if ((client
.normal_hint_flags
& PMinSize
) &&
2589 (client
.normal_hint_flags
& PMaxSize
)) {
2590 // the window now can/can't resize itself, so the buttons need to be
2593 if (client
.max_width
<= client
.min_width
&&
2594 client
.max_height
<= client
.min_height
) {
2595 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2596 functions
&= ~(Func_Resize
| Func_Maximize
);
2598 decorations
|= Decor_Maximize
| Decor_Handle
;
2599 functions
|= Func_Resize
| Func_Maximize
;
2602 setAllowedActions();
2605 Rect old_rect
= frame
.rect
;
2609 if (old_rect
!= frame
.rect
)
2616 if (pe
->atom
== xatom
->getAtom(XAtom::wm_protocols
)) {
2619 if ((decorations
& Decor_Close
) && (! frame
.close_button
)) {
2620 createCloseButton();
2621 if (decorations
& Decor_Titlebar
) {
2622 positionButtons(True
);
2623 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
2625 if (windowmenu
) windowmenu
->reconfigure();
2627 } else if (pe
->atom
== xatom
->getAtom(XAtom::net_wm_strut
)) {
2636 void BlackboxWindow::exposeEvent(const XExposeEvent
*ee
) {
2638 fprintf(stderr
, "BlackboxWindow::exposeEvent() for 0x%lx\n", client
.window
);
2641 if (frame
.label
== ee
->window
&& (decorations
& Decor_Titlebar
))
2643 else if (frame
.close_button
== ee
->window
)
2644 redrawCloseButton(False
);
2645 else if (frame
.maximize_button
== ee
->window
)
2646 redrawMaximizeButton(flags
.maximized
);
2647 else if (frame
.iconify_button
== ee
->window
)
2648 redrawIconifyButton(False
);
2652 void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent
*cr
) {
2653 if (cr
->window
!= client
.window
|| flags
.iconic
)
2656 if (cr
->value_mask
& CWBorderWidth
)
2657 client
.old_bw
= cr
->border_width
;
2659 if (cr
->value_mask
& (CWX
| CWY
| CWWidth
| CWHeight
)) {
2660 Rect req
= frame
.rect
;
2662 if (cr
->value_mask
& (CWX
| CWY
)) {
2663 if (cr
->value_mask
& CWX
)
2664 client
.rect
.setX(cr
->x
);
2665 if (cr
->value_mask
& CWY
)
2666 client
.rect
.setY(cr
->y
);
2671 if (cr
->value_mask
& CWWidth
)
2672 req
.setWidth(cr
->width
+ frame
.margin
.left
+ frame
.margin
.right
);
2674 if (cr
->value_mask
& CWHeight
)
2675 req
.setHeight(cr
->height
+ frame
.margin
.top
+ frame
.margin
.bottom
);
2677 configure(req
.x(), req
.y(), req
.width(), req
.height());
2680 if (cr
->value_mask
& CWStackMode
) {
2681 switch (cr
->detail
) {
2684 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2690 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2697 void BlackboxWindow::buttonPressEvent(const XButtonEvent
*be
) {
2699 fprintf(stderr
, "BlackboxWindow::buttonPressEvent() for 0x%lx\n",
2703 if (frame
.maximize_button
== be
->window
) {
2704 redrawMaximizeButton(True
);
2705 } else if (be
->button
== 1 || (be
->button
== 3 && be
->state
== Mod1Mask
)) {
2706 if (! flags
.focused
)
2709 if (frame
.iconify_button
== be
->window
) {
2710 redrawIconifyButton(True
);
2711 } else if (frame
.close_button
== be
->window
) {
2712 redrawCloseButton(True
);
2713 } else if (frame
.plate
== be
->window
) {
2714 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2716 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2718 XAllowEvents(blackbox
->getXDisplay(), ReplayPointer
, be
->time
);
2720 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
2721 if (((be
->time
- lastButtonPressTime
) <=
2722 blackbox
->getDoubleClickInterval()) ||
2723 (be
->state
& ControlMask
)) {
2724 lastButtonPressTime
= 0;
2727 lastButtonPressTime
= be
->time
;
2731 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2733 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2735 } else if (be
->button
== 2 && (be
->window
!= frame
.iconify_button
) &&
2736 (be
->window
!= frame
.close_button
)) {
2737 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2738 } else if (windowmenu
&& be
->button
== 3 &&
2739 (frame
.title
== be
->window
|| frame
.label
== be
->window
||
2740 frame
.handle
== be
->window
|| frame
.window
== be
->window
)) {
2741 if (windowmenu
->isVisible()) {
2744 int mx
= be
->x_root
- windowmenu
->getWidth() / 2,
2745 my
= be
->y_root
- windowmenu
->getHeight() / 2;
2747 // snap the window menu into a corner/side if necessary
2748 int left_edge
, right_edge
, top_edge
, bottom_edge
;
2751 the " + (frame.border_w * 2) - 1" bits are to get the proper width
2752 and height of the menu, as the sizes returned by it do not include
2755 left_edge
= frame
.rect
.x();
2756 right_edge
= frame
.rect
.right() -
2757 (windowmenu
->getWidth() + (frame
.border_w
* 2) - 1);
2758 top_edge
= client
.rect
.top() - (frame
.border_w
+ frame
.mwm_border_w
);
2759 bottom_edge
= client
.rect
.bottom() -
2760 (windowmenu
->getHeight() + (frame
.border_w
* 2) - 1) +
2761 (frame
.border_w
+ frame
.mwm_border_w
);
2765 if (mx
> right_edge
)
2769 if (my
> bottom_edge
)
2772 windowmenu
->move(mx
, my
);
2774 XRaiseWindow(blackbox
->getXDisplay(), windowmenu
->getWindowID());
2775 XRaiseWindow(blackbox
->getXDisplay(),
2776 windowmenu
->getSendToMenu()->getWindowID());
2779 } else if (be
->button
== 4) {
2780 if ((be
->window
== frame
.label
||
2781 be
->window
== frame
.title
) &&
2785 } else if (be
->button
== 5) {
2786 if ((be
->window
== frame
.label
||
2787 be
->window
== frame
.title
) &&
2794 void BlackboxWindow::buttonReleaseEvent(const XButtonEvent
*re
) {
2796 fprintf(stderr
, "BlackboxWindow::buttonReleaseEvent() for 0x%lx\n",
2800 if (re
->window
== frame
.maximize_button
) {
2801 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2802 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2803 maximize(re
->button
);
2805 redrawMaximizeButton(flags
.maximized
);
2807 } else if (re
->window
== frame
.iconify_button
) {
2808 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2809 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2812 redrawIconifyButton(False
);
2814 } else if (re
->window
== frame
.close_button
) {
2815 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2816 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
)))
2818 redrawCloseButton(False
);
2819 } else if (flags
.moving
) {
2821 } else if (flags
.resizing
) {
2828 void BlackboxWindow::beginMove(int x_root
, int y_root
) {
2829 assert(! (flags
.resizing
|| flags
.moving
));
2832 Only one window can be moved/resized at a time. If another window is already
2833 being moved or resized, then stop it before whating to work with this one.
2835 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
2836 if (changing
&& changing
!= this) {
2837 if (changing
->flags
.moving
)
2838 changing
->endMove();
2839 else // if (changing->flags.resizing)
2840 changing
->endResize();
2843 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
2844 PointerMotionMask
| ButtonReleaseMask
,
2845 GrabModeAsync
, GrabModeAsync
,
2846 None
, blackbox
->getMoveCursor(), CurrentTime
);
2848 if (windowmenu
&& windowmenu
->isVisible())
2851 flags
.moving
= True
;
2852 blackbox
->setChangingWindow(this);
2854 if (! screen
->doOpaqueMove()) {
2855 XGrabServer(blackbox
->getXDisplay());
2857 frame
.changing
= frame
.rect
;
2858 screen
->showPosition(frame
.changing
.x(), frame
.changing
.y());
2860 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
2864 frame
.changing
.width() - 1,
2865 frame
.changing
.height() - 1);
2868 frame
.grab_x
= x_root
- frame
.rect
.x() - frame
.border_w
;
2869 frame
.grab_y
= y_root
- frame
.rect
.y() - frame
.border_w
;
2873 void BlackboxWindow::doMove(int x_root
, int y_root
) {
2874 assert(flags
.moving
);
2875 assert(blackbox
->getChangingWindow() == this);
2877 int dx
= x_root
- frame
.grab_x
, dy
= y_root
- frame
.grab_y
;
2878 dx
-= frame
.border_w
;
2879 dy
-= frame
.border_w
;
2881 const int snap_distance
= screen
->getEdgeSnapThreshold();
2883 if (snap_distance
) {
2885 const int wleft
= dx
,
2886 wright
= dx
+ frame
.rect
.width() - 1,
2888 wbottom
= dy
+ frame
.rect
.height() - 1;
2890 if (screen
->getWindowToWindowSnap()) {
2891 Workspace
*w
= screen
->getWorkspace(getWorkspaceNumber());
2894 // try snap to another window
2895 for (unsigned int i
= 0, c
= w
->getCount(); i
< c
; ++i
) {
2896 BlackboxWindow
*snapwin
= w
->getWindow(i
);
2897 if (snapwin
== this)
2898 continue; // don't snap to self
2900 bool snapped
= False
;
2902 const Rect
&winrect
= snapwin
->frameRect();
2903 int dleft
= std::abs(wright
- winrect
.left()),
2904 dright
= std::abs(wleft
- winrect
.right()),
2905 dtop
= std::abs(wbottom
- winrect
.top()),
2906 dbottom
= std::abs(wtop
- winrect
.bottom());
2908 if (wtop
>= (signed)(winrect
.y() - frame
.rect
.height() + 1) &&
2909 wtop
< (signed)(winrect
.y() + winrect
.height() - 1)) {
2911 // snap left of other window?
2912 if (dleft
< snap_distance
&& dleft
<= dright
) {
2913 dx
= winrect
.left() - frame
.rect
.width();
2916 // snap right of other window?
2917 else if (dright
< snap_distance
) {
2918 dx
= winrect
.right() + 1;
2923 if (screen
->getWindowCornerSnap()) {
2924 // try corner-snap to its other sides
2925 dtop
= std::abs(wtop
- winrect
.top());
2926 dbottom
= std::abs(wbottom
- winrect
.bottom());
2927 if (dtop
< snap_distance
&& dtop
<= dbottom
)
2929 else if (dbottom
< snap_distance
)
2930 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
2937 if (wleft
>= (signed)(winrect
.x() - frame
.rect
.width() + 1) &&
2938 wleft
< (signed)(winrect
.x() + winrect
.width() - 1)) {
2940 // snap top of other window?
2941 if (dtop
< snap_distance
&& dtop
<= dbottom
) {
2942 dy
= winrect
.top() - frame
.rect
.height();
2945 // snap bottom of other window?
2946 else if (dbottom
< snap_distance
) {
2947 dy
= winrect
.bottom() + 1;
2952 if (screen
->getWindowCornerSnap()) {
2953 // try corner-snap to its other sides
2954 dleft
= std::abs(wleft
- winrect
.left());
2955 dright
= std::abs(wright
- winrect
.right());
2956 if (dleft
< snap_distance
&& dleft
<= dright
)
2957 dx
= winrect
.left();
2958 else if (dright
< snap_distance
)
2959 dx
= winrect
.right() - frame
.rect
.width() + 1;
2968 // try snap to the screen's available area
2969 Rect srect
= screen
->availableArea();
2971 int dleft
= std::abs(wleft
- srect
.left()),
2972 dright
= std::abs(wright
- srect
.right()),
2973 dtop
= std::abs(wtop
- srect
.top()),
2974 dbottom
= std::abs(wbottom
- srect
.bottom());
2977 if (dleft
< snap_distance
&& dleft
<= dright
)
2980 else if (dright
< snap_distance
)
2981 dx
= srect
.right() - frame
.rect
.width() + 1;
2984 if (dtop
< snap_distance
&& dtop
<= dbottom
)
2987 else if (dbottom
< snap_distance
)
2988 dy
= srect
.bottom() - frame
.rect
.height() + 1;
2990 srect
= screen
->getRect(); // now get the full screen
2992 dleft
= std::abs(wleft
- srect
.left()),
2993 dright
= std::abs(wright
- srect
.right()),
2994 dtop
= std::abs(wtop
- srect
.top()),
2995 dbottom
= std::abs(wbottom
- srect
.bottom());
2998 if (dleft
< snap_distance
&& dleft
<= dright
)
3001 else if (dright
< snap_distance
)
3002 dx
= srect
.right() - frame
.rect
.width() + 1;
3005 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3008 else if (dbottom
< snap_distance
)
3009 dy
= srect
.bottom() - frame
.rect
.height() + 1;
3012 if (screen
->doOpaqueMove()) {
3013 configure(dx
, dy
, frame
.rect
.width(), frame
.rect
.height());
3015 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3019 frame
.changing
.width() - 1,
3020 frame
.changing
.height() - 1);
3022 frame
.changing
.setPos(dx
, dy
);
3024 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3028 frame
.changing
.width() - 1,
3029 frame
.changing
.height() - 1);
3032 screen
->showPosition(dx
, dy
);
3036 void BlackboxWindow::endMove(void) {
3037 assert(flags
.moving
);
3038 assert(blackbox
->getChangingWindow() == this);
3040 flags
.moving
= False
;
3041 blackbox
->setChangingWindow(0);
3043 if (! screen
->doOpaqueMove()) {
3044 /* when drawing the rubber band, we need to make sure we only draw inside
3045 * the frame... frame.changing_* contain the new coords for the window,
3046 * so we need to subtract 1 from changing_w/changing_h every where we
3047 * draw the rubber band (for both moving and resizing)
3049 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3050 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3051 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3052 XUngrabServer(blackbox
->getXDisplay());
3054 configure(frame
.changing
.x(), frame
.changing
.y(),
3055 frame
.changing
.width(), frame
.changing
.height());
3057 configure(frame
.rect
.x(), frame
.rect
.y(),
3058 frame
.rect
.width(), frame
.rect
.height());
3060 screen
->hideGeometry();
3062 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3064 // if there are any left over motions from the move, drop them now
3065 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3067 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3072 void BlackboxWindow::beginResize(int x_root
, int y_root
, Corner dir
) {
3073 assert(! (flags
.resizing
|| flags
.moving
));
3076 Only one window can be moved/resized at a time. If another window is already
3077 being moved or resized, then stop it before whating to work with this one.
3079 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3080 if (changing
&& changing
!= this) {
3081 if (changing
->flags
.moving
)
3082 changing
->endMove();
3083 else // if (changing->flags.resizing)
3084 changing
->endResize();
3092 switch (resize_dir
) {
3095 cursor
= blackbox
->getLowerLeftAngleCursor();
3100 cursor
= blackbox
->getLowerRightAngleCursor();
3104 anchor
= BottomRight
;
3105 cursor
= blackbox
->getUpperLeftAngleCursor();
3109 anchor
= BottomLeft
;
3110 cursor
= blackbox
->getUpperRightAngleCursor();
3114 assert(false); // unhandled Corner
3117 XGrabServer(blackbox
->getXDisplay());
3118 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3119 PointerMotionMask
| ButtonReleaseMask
,
3120 GrabModeAsync
, GrabModeAsync
, None
, cursor
, CurrentTime
);
3122 flags
.resizing
= True
;
3123 blackbox
->setChangingWindow(this);
3126 frame
.changing
= frame
.rect
;
3128 constrain(anchor
, &gw
, &gh
);
3130 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3131 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3132 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3134 screen
->showGeometry(gw
, gh
);
3136 frame
.grab_x
= x_root
;
3137 frame
.grab_y
= y_root
;
3141 void BlackboxWindow::doResize(int x_root
, int y_root
) {
3142 assert(flags
.resizing
);
3143 assert(blackbox
->getChangingWindow() == this);
3145 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3146 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3147 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3152 switch (resize_dir
) {
3155 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3156 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3160 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3161 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3164 anchor
= BottomRight
;
3165 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3166 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3169 anchor
= BottomLeft
;
3170 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3171 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3175 assert(false); // unhandled Corner
3178 constrain(anchor
, &gw
, &gh
);
3180 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3181 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3182 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3184 screen
->showGeometry(gw
, gh
);
3188 void BlackboxWindow::endResize(void) {
3189 assert(flags
.resizing
);
3190 assert(blackbox
->getChangingWindow() == this);
3192 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3193 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3194 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3195 XUngrabServer(blackbox
->getXDisplay());
3197 // unset maximized state after resized when fully maximized
3198 if (flags
.maximized
== 1)
3201 flags
.resizing
= False
;
3202 blackbox
->setChangingWindow(0);
3204 configure(frame
.changing
.x(), frame
.changing
.y(),
3205 frame
.changing
.width(), frame
.changing
.height());
3206 screen
->hideGeometry();
3208 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3210 // if there are any left over motions from the resize, drop them now
3211 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3213 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3218 void BlackboxWindow::motionNotifyEvent(const XMotionEvent
*me
) {
3220 fprintf(stderr
, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n",
3225 doMove(me
->x_root
, me
->y_root
);
3226 } else if (flags
.resizing
) {
3227 doResize(me
->x_root
, me
->y_root
);
3229 if (! flags
.resizing
&& (me
->state
& Button1Mask
) &&
3230 (functions
& Func_Move
) &&
3231 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3232 frame
.handle
== me
->window
|| frame
.window
== me
->window
)) {
3233 beginMove(me
->x_root
, me
->y_root
);
3234 } else if ((functions
& Func_Resize
) &&
3235 (((me
->state
& Button1Mask
) &&
3236 (me
->window
== frame
.right_grip
||
3237 me
->window
== frame
.left_grip
)) ||
3238 (me
->state
& (Mod1Mask
| Button3Mask
) &&
3239 me
->window
== frame
.window
))) {
3240 beginResize(me
->x_root
, me
->y_root
,
3241 (me
->window
== frame
.left_grip
) ? BottomLeft
: BottomRight
);
3248 void BlackboxWindow::shapeEvent(XShapeEvent
*) {
3249 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
3256 bool BlackboxWindow::validateClient(void) const {
3257 XSync(blackbox
->getXDisplay(), False
);
3260 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3261 DestroyNotify
, &e
) ||
3262 XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3264 XPutBackEvent(blackbox
->getXDisplay(), &e
);
3273 void BlackboxWindow::restore(bool remap
) {
3274 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeDelete
);
3275 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
3276 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, NoEventMask
);
3278 // do not leave a shaded window as an icon unless it was an icon
3279 if (flags
.shaded
&& ! flags
.iconic
) setState(NormalState
);
3281 restoreGravity(client
.rect
);
3283 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
3284 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
3286 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, client
.old_bw
);
3289 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3290 ReparentNotify
, &ev
)) {
3293 // according to the ICCCM - if the client doesn't reparent to
3294 // root, then we have to do it for them
3295 XReparentWindow(blackbox
->getXDisplay(), client
.window
,
3296 screen
->getRootWindow(),
3297 client
.rect
.x(), client
.rect
.y());
3300 if (remap
) XMapWindow(blackbox
->getXDisplay(), client
.window
);
3304 // timer for autoraise
3305 void BlackboxWindow::timeout(void) {
3306 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3310 void BlackboxWindow::changeBlackboxHints(BlackboxHints
*net
) {
3311 if ((net
->flags
& AttribShaded
) &&
3312 ((blackbox_attrib
.attrib
& AttribShaded
) !=
3313 (net
->attrib
& AttribShaded
)))
3316 if (flags
.visible
&& // watch out for requests when we can not be seen
3317 (net
->flags
& (AttribMaxVert
| AttribMaxHoriz
)) &&
3318 ((blackbox_attrib
.attrib
& (AttribMaxVert
| AttribMaxHoriz
)) !=
3319 (net
->attrib
& (AttribMaxVert
| AttribMaxHoriz
)))) {
3320 if (flags
.maximized
) {
3325 if ((net
->flags
& AttribMaxHoriz
) && (net
->flags
& AttribMaxVert
))
3326 button
= ((net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0);
3327 else if (net
->flags
& AttribMaxVert
)
3328 button
= ((net
->attrib
& AttribMaxVert
) ? 2 : 0);
3329 else if (net
->flags
& AttribMaxHoriz
)
3330 button
= ((net
->attrib
& AttribMaxHoriz
) ? 3 : 0);
3336 if ((net
->flags
& AttribOmnipresent
) &&
3337 ((blackbox_attrib
.attrib
& AttribOmnipresent
) !=
3338 (net
->attrib
& AttribOmnipresent
)))
3341 if ((net
->flags
& AttribWorkspace
) &&
3342 (blackbox_attrib
.workspace
!= net
->workspace
)) {
3343 screen
->reassociateWindow(this, net
->workspace
, True
);
3345 if (screen
->getCurrentWorkspaceID() != net
->workspace
) {
3349 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3353 if (net
->flags
& AttribDecoration
) {
3354 switch (net
->decoration
) {
3356 // clear all decorations except close
3357 decorations
&= Decor_Close
;
3363 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Iconify
;
3365 decorations
= ((functions
& Func_Resize
) && !isTransient() ?
3366 decorations
| Decor_Handle
:
3367 decorations
&= ~Decor_Handle
);
3368 decorations
= (functions
& Func_Maximize
?
3369 decorations
| Decor_Maximize
:
3370 decorations
&= ~Decor_Maximize
);
3375 decorations
|= Decor_Titlebar
| Decor_Iconify
;
3376 decorations
&= ~(Decor_Border
| Decor_Handle
);
3378 decorations
= (functions
& Func_Maximize
?
3379 decorations
| Decor_Maximize
:
3380 decorations
&= ~Decor_Maximize
);
3385 decorations
|= Decor_Titlebar
;
3386 decorations
&= ~(Decor_Iconify
| Decor_Border
);
3388 decorations
= ((functions
& Func_Resize
) && !isTransient() ?
3389 decorations
| Decor_Handle
:
3390 decorations
&= ~Decor_Handle
);
3391 decorations
= (functions
& Func_Maximize
?
3392 decorations
| Decor_Maximize
:
3393 decorations
&= ~Decor_Maximize
);
3398 // we can not be shaded if we lack a titlebar
3399 if (flags
.shaded
&& ! (decorations
& Decor_Titlebar
))
3402 if (flags
.visible
&& frame
.window
) {
3403 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
3404 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
3408 setState(current_state
);
3414 * Set the sizes of all components of the window frame
3415 * (the window decorations).
3416 * These values are based upon the current style settings and the client
3417 * window's dimensions.
3419 void BlackboxWindow::upsize(void) {
3420 frame
.bevel_w
= screen
->getBevelWidth();
3422 if (decorations
& Decor_Border
) {
3423 frame
.border_w
= screen
->getBorderWidth();
3424 if (! isTransient())
3425 frame
.mwm_border_w
= screen
->getFrameWidth();
3427 frame
.mwm_border_w
= 0;
3429 frame
.mwm_border_w
= frame
.border_w
= 0;
3432 if (decorations
& Decor_Titlebar
) {
3433 // the height of the titlebar is based upon the height of the font being
3434 // used to display the window's title
3435 WindowStyle
*style
= screen
->getWindowStyle();
3436 frame
.title_h
= style
->font
->height() + (frame
.bevel_w
* 2) + 2;
3438 frame
.label_h
= frame
.title_h
- (frame
.bevel_w
* 2);
3439 frame
.button_w
= (frame
.label_h
- 2);
3441 // set the top frame margin
3442 frame
.margin
.top
= frame
.border_w
+ frame
.title_h
+
3443 frame
.border_w
+ frame
.mwm_border_w
;
3449 // set the top frame margin
3450 frame
.margin
.top
= frame
.border_w
+ frame
.mwm_border_w
;
3453 // set the left/right frame margin
3454 frame
.margin
.left
= frame
.margin
.right
= frame
.border_w
+ frame
.mwm_border_w
;
3456 if (decorations
& Decor_Handle
) {
3457 frame
.grip_w
= frame
.button_w
* 2;
3458 frame
.handle_h
= screen
->getHandleWidth();
3460 // set the bottom frame margin
3461 frame
.margin
.bottom
= frame
.border_w
+ frame
.handle_h
+
3462 frame
.border_w
+ frame
.mwm_border_w
;
3467 // set the bottom frame margin
3468 frame
.margin
.bottom
= frame
.border_w
+ frame
.mwm_border_w
;
3472 We first get the normal dimensions and use this to define the inside_w/h
3473 then we modify the height if shading is in effect.
3474 If the shade state is not considered then frame.rect gets reset to the
3475 normal window size on a reconfigure() call resulting in improper
3476 dimensions appearing in move/resize and other events.
3479 height
= client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
,
3480 width
= client
.rect
.width() + frame
.margin
.left
+ frame
.margin
.right
;
3482 frame
.inside_w
= width
- (frame
.border_w
* 2);
3483 frame
.inside_h
= height
- (frame
.border_w
* 2);
3486 height
= frame
.title_h
+ (frame
.border_w
* 2);
3487 frame
.rect
.setSize(width
, height
);
3492 * Calculate the size of the client window and constrain it to the
3493 * size specified by the size hints of the client window.
3495 * The logical width and height are placed into pw and ph, if they
3496 * are non-zero. Logical size refers to the users perception of
3497 * the window size (for example an xterm resizes in cells, not in pixels).
3499 * The physical geometry is placed into frame.changing_{x,y,width,height}.
3500 * Physical geometry refers to the geometry of the window in pixels.
3502 void BlackboxWindow::constrain(Corner anchor
, int *pw
, int *ph
) {
3503 // frame.changing represents the requested frame size, we need to
3504 // strip the frame margin off and constrain the client size
3505 frame
.changing
.setCoords(frame
.changing
.left() + frame
.margin
.left
,
3506 frame
.changing
.top() + frame
.margin
.top
,
3507 frame
.changing
.right() - frame
.margin
.right
,
3508 frame
.changing
.bottom() - frame
.margin
.bottom
);
3510 int dw
= frame
.changing
.width(), dh
= frame
.changing
.height(),
3511 base_width
= (client
.base_width
) ? client
.base_width
: client
.min_width
,
3512 base_height
= (client
.base_height
) ? client
.base_height
:
3516 if (dw
< static_cast<signed>(client
.min_width
)) dw
= client
.min_width
;
3517 if (dh
< static_cast<signed>(client
.min_height
)) dh
= client
.min_height
;
3518 if (dw
> static_cast<signed>(client
.max_width
)) dw
= client
.max_width
;
3519 if (dh
> static_cast<signed>(client
.max_height
)) dh
= client
.max_height
;
3522 dw
/= client
.width_inc
;
3524 dh
/= client
.height_inc
;
3527 if (client
.width_inc
== 1)
3528 *pw
= dw
+ base_width
;
3533 if (client
.height_inc
== 1)
3534 *ph
= dh
+ base_height
;
3539 dw
*= client
.width_inc
;
3541 dh
*= client
.height_inc
;
3544 frame
.changing
.setSize(dw
, dh
);
3546 // add the frame margin back onto frame.changing
3547 frame
.changing
.setCoords(frame
.changing
.left() - frame
.margin
.left
,
3548 frame
.changing
.top() - frame
.margin
.top
,
3549 frame
.changing
.right() + frame
.margin
.right
,
3550 frame
.changing
.bottom() + frame
.margin
.bottom
);
3552 // move frame.changing to the specified anchor
3560 dx
= frame
.rect
.right() - frame
.changing
.right();
3564 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3568 dx
= frame
.rect
.right() - frame
.changing
.right();
3569 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3573 assert(false); // unhandled corner
3575 frame
.changing
.setPos(frame
.changing
.x() + dx
, frame
.changing
.y() + dy
);
3579 void WindowStyle::doJustify(const std::string
&text
, int &start_pos
,
3580 unsigned int max_length
,
3581 unsigned int modifier
) const {
3582 size_t text_len
= text
.size();
3583 unsigned int length
;
3586 length
= font
->measureString(string(text
, 0, text_len
)) + modifier
;
3587 } while (length
> max_length
&& text_len
-- > 0);
3591 start_pos
+= max_length
- length
;
3595 start_pos
+= (max_length
- length
) / 2;
3605 BWindowGroup::BWindowGroup(Blackbox
*b
, Window _group
)
3606 : blackbox(b
), group(_group
) {
3607 XWindowAttributes wattrib
;
3608 if (! XGetWindowAttributes(blackbox
->getXDisplay(), group
, &wattrib
)) {
3609 // group window doesn't seem to exist anymore
3615 watch for destroy notify on the group window (in addition to
3616 any other events we are looking for)
3618 since some managed windows can also be window group controllers,
3619 we need to make sure that we don't clobber the event mask for the
3622 XSelectInput(blackbox
->getXDisplay(), group
,
3623 wattrib
.your_event_mask
| StructureNotifyMask
);
3625 blackbox
->saveGroupSearch(group
, this);
3629 BWindowGroup::~BWindowGroup(void) {
3630 blackbox
->removeGroupSearch(group
);
3635 BWindowGroup::find(BScreen
*screen
, bool allow_transients
) const {
3636 BlackboxWindow
*ret
= blackbox
->getFocusedWindow();
3638 // does the focus window match (or any transient_fors)?
3640 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3641 if (ret
->isTransient() && allow_transients
) break;
3642 else if (! ret
->isTransient()) break;
3645 ret
= ret
->getTransientFor();
3648 if (ret
) return ret
;
3650 // the focus window didn't match, look in the group's window list
3651 BlackboxWindowList::const_iterator it
, end
= windowList
.end();
3652 for (it
= windowList
.begin(); it
!= end
; ++it
) {
3654 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3655 if (ret
->isTransient() && allow_transients
) break;
3656 else if (! ret
->isTransient()) break;