1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2 // Window.cc for Blackbox - an X11 Window manager
3 // Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry <shaleh at debian.org>
4 // Copyright (c) 1997 - 2000, 2002 Brad Hughes <bhughes at trolltech.com>
6 // Permission is hereby granted, free of charge, to any person obtaining a
7 // copy of this software and associated documentation files (the "Software"),
8 // to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 // and/or sell copies of the Software, and to permit persons to whom the
11 // Software is furnished to do so, subject to the following conditions:
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 // DEALINGS IN THE SOFTWARE.
25 # include "../config.h"
26 #endif // HAVE_CONFIG_H
29 #include <X11/Xatom.h>
30 #include <X11/keysym.h>
34 #endif // HAVE_STRING_H
39 # endif // HAVE_STDIO_H
44 #endif // HAVE_STDLIB_H
48 #include "blackbox.hh"
49 #include "Clientmenu.hh"
52 #include "Iconmenu.hh"
58 #include "Windowmenu.hh"
59 #include "Workspace.hh"
65 // change this to change what modifier keys openbox uses for mouse bindings
66 // for example: Mod1Mask | ControlMask
67 // or: ControlMask| ShiftMask
68 const unsigned int ModMask
= Mod1Mask
;
71 * Initializes the class with default values/the window's set initial values.
73 BlackboxWindow::BlackboxWindow(Blackbox
*b
, Window w
, BScreen
*s
) {
74 // fprintf(stderr, "BlackboxWindow size: %d bytes\n",
75 // sizeof(BlackboxWindow));
78 fprintf(stderr
, "BlackboxWindow::BlackboxWindow(): creating 0x%lx\n", w
);
82 set timer to zero... it is initialized properly later, so we check
83 if timer is zero in the destructor, and assume that the window is not
84 fully constructed if timer is zero...
90 xatom
= blackbox
->getXAtom();
92 if (! validateClient()) {
97 // fetch client size and placement
98 XWindowAttributes wattrib
;
99 if (! XGetWindowAttributes(blackbox
->getXDisplay(),
100 client
.window
, &wattrib
) ||
101 ! wattrib
.screen
|| wattrib
.override_redirect
) {
104 "BlackboxWindow::BlackboxWindow(): XGetWindowAttributes failed\n");
111 // set the eventmask early in the game so that we make sure we get
112 // all the events we are interested in
113 XSetWindowAttributes attrib_set
;
114 attrib_set
.event_mask
= PropertyChangeMask
| FocusChangeMask
|
116 attrib_set
.do_not_propagate_mask
= ButtonPressMask
| ButtonReleaseMask
|
118 XChangeWindowAttributes(blackbox
->getXDisplay(), client
.window
,
119 CWEventMask
|CWDontPropagate
, &attrib_set
);
121 flags
.moving
= flags
.resizing
= flags
.shaded
= flags
.visible
=
122 flags
.iconic
= flags
.focused
= flags
.stuck
= flags
.modal
=
123 flags
.send_focus_message
= flags
.shaped
= flags
.skip_taskbar
=
124 flags
.skip_pager
= flags
.fullscreen
= False
;
127 blackbox_attrib
.workspace
= window_number
= BSENTINEL
;
129 blackbox_attrib
.flags
= blackbox_attrib
.attrib
= blackbox_attrib
.stack
130 = blackbox_attrib
.decoration
= 0l;
131 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
132 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
135 frame
.window
= frame
.plate
= frame
.title
= frame
.handle
= None
;
136 frame
.close_button
= frame
.iconify_button
= frame
.maximize_button
= None
;
137 frame
.right_grip
= frame
.left_grip
= None
;
139 frame
.ulabel_pixel
= frame
.flabel_pixel
= frame
.utitle_pixel
=
140 frame
.ftitle_pixel
= frame
.uhandle_pixel
= frame
.fhandle_pixel
=
141 frame
.ubutton_pixel
= frame
.fbutton_pixel
= frame
.pbutton_pixel
=
142 frame
.uborder_pixel
= frame
.fborder_pixel
= frame
.ugrip_pixel
=
143 frame
.fgrip_pixel
= 0;
144 frame
.utitle
= frame
.ftitle
= frame
.uhandle
= frame
.fhandle
= None
;
145 frame
.ulabel
= frame
.flabel
= frame
.ubutton
= frame
.fbutton
= None
;
146 frame
.pbutton
= frame
.ugrip
= frame
.fgrip
= None
;
148 decorations
= Decor_Titlebar
| Decor_Border
| Decor_Handle
|
149 Decor_Iconify
| Decor_Maximize
;
150 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
152 client
.normal_hint_flags
= 0;
153 client
.window_group
= None
;
154 client
.transient_for
= 0;
156 current_state
= NormalState
;
159 get the initial size and location of client window (relative to the
160 _root window_). This position is the reference point used with the
161 window's gravity to find the window's initial position.
163 client
.rect
.setRect(wattrib
.x
, wattrib
.y
, wattrib
.width
, wattrib
.height
);
164 client
.old_bw
= wattrib
.border_width
;
166 lastButtonPressTime
= 0;
168 timer
= new BTimer(blackbox
, this);
169 timer
->setTimeout(blackbox
->getAutoRaiseDelay());
171 windowmenu
= new Windowmenu(this);
173 // get size, aspect, minimum/maximum size and other hints set by the
176 if (! getBlackboxHints()) {
185 frame
.window
= createToplevelWindow();
187 blackbox
->saveWindowSearch(frame
.window
, this);
189 frame
.plate
= createChildWindow(frame
.window
);
190 blackbox
->saveWindowSearch(frame
.plate
, this);
192 // determine if this is a transient window
195 // determine the window's type, so we can decide its decorations and
196 // functionality, or if we should not manage it at all
199 // adjust the window decorations/behavior based on the window type
201 switch (window_type
) {
208 // none of these windows are decorated or manipulated by the window manager
211 blackbox_attrib
.workspace
= 0; // we do need to belong to a workspace
212 flags
.stuck
= True
; // we show up on all workspaces
216 // dialogs cannot be maximized, and don't display a handle
217 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
218 functions
&= ~Func_Maximize
;
222 // normal windows retain all of the possible decorations and functionality
228 // further adjeust the window's decorations/behavior based on window sizes
229 if ((client
.normal_hint_flags
& PMinSize
) &&
230 (client
.normal_hint_flags
& PMaxSize
) &&
231 client
.max_width
<= client
.min_width
&&
232 client
.max_height
<= client
.min_height
) {
233 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
234 functions
&= ~(Func_Resize
| Func_Maximize
);
237 if (decorations
& Decor_Titlebar
)
240 if (decorations
& Decor_Handle
)
243 // apply the size and gravity hint to the frame
247 bool place_window
= True
;
248 if (blackbox
->isStartup() || isTransient() ||
249 client
.normal_hint_flags
& (PPosition
|USPosition
)) {
250 applyGravity(frame
.rect
);
252 if (blackbox
->isStartup() || client
.rect
.intersects(screen
->getRect()))
253 place_window
= False
;
256 // add the window's strut. note this is done *after* placing the window.
257 screen
->addStrut(&client
.strut
);
261 if (blackbox
->hasShapeExtensions() && flags
.shaped
)
265 // get the window's title before adding it to the workspace
269 if (blackbox_attrib
.workspace
>= screen
->getWorkspaceCount())
270 screen
->getCurrentWorkspace()->addWindow(this, place_window
);
272 screen
->getWorkspace(blackbox_attrib
.workspace
)->
273 addWindow(this, place_window
);
276 the server needs to be grabbed here to prevent client's from sending
277 events while we are in the process of configuring their window.
278 We hold the grab until after we are done moving the window around.
281 XGrabServer(blackbox
->getXDisplay());
283 associateClientWindow();
285 blackbox
->saveWindowSearch(client
.window
, this);
287 if (! place_window
) {
288 // don't need to call configure if we are letting the workspace
290 configure(frame
.rect
.x(), frame
.rect
.y(),
291 frame
.rect
.width(), frame
.rect
.height());
297 XUngrabServer(blackbox
->getXDisplay());
299 // now that we know where to put the window and what it should look like
300 // we apply the decorations
305 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
307 // this ensures the title, buttons, and other decor are properly displayed
310 // preserve the window's initial state on first map, and its current state
312 unsigned long initial_state
= current_state
;
314 current_state
= initial_state
;
316 // get sticky state from our parent window if we've got one
317 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
318 client
.transient_for
->isStuck() != flags
.stuck
)
321 // the following flags are set by blackbox native apps only
323 flags
.shaded
= False
;
324 initial_state
= current_state
;
328 At this point in the life of a window, current_state should only be set
329 to IconicState if the window was an *icon*, not if it was shaded.
331 if (initial_state
!= IconicState
)
332 current_state
= NormalState
;
340 if (flags
.maximized
&& (functions
& Func_Maximize
))
345 BlackboxWindow::~BlackboxWindow(void) {
347 fprintf(stderr
, "BlackboxWindow::~BlackboxWindow: destroying 0x%lx\n",
351 if (! timer
) // window not managed...
354 screen
->removeStrut(&client
.strut
);
355 screen
->updateAvailableArea();
357 // We don't need to worry about resizing because resizing always grabs the X
358 // server. This should only ever happen if using opaque moving.
366 if (client
.window_group
) {
367 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
368 if (group
) group
->removeWindow(this);
371 // remove ourselves from our transient_for
373 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
374 client
.transient_for
->client
.transientList
.remove(this);
376 client
.transient_for
= (BlackboxWindow
*) 0;
379 if (client
.transientList
.size() > 0) {
380 // reset transient_for for all transients
381 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
382 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
383 (*it
)->client
.transient_for
= (BlackboxWindow
*) 0;
394 blackbox
->removeWindowSearch(frame
.plate
);
395 XDestroyWindow(blackbox
->getXDisplay(), frame
.plate
);
399 blackbox
->removeWindowSearch(frame
.window
);
400 XDestroyWindow(blackbox
->getXDisplay(), frame
.window
);
403 blackbox
->removeWindowSearch(client
.window
);
408 * Creates a new top level window, with a given location, size, and border
410 * Returns: the newly created window
412 Window
BlackboxWindow::createToplevelWindow(void) {
413 XSetWindowAttributes attrib_create
;
414 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
| CWColormap
|
415 CWOverrideRedirect
| CWEventMask
;
417 attrib_create
.background_pixmap
= None
;
418 attrib_create
.colormap
= screen
->getColormap();
419 attrib_create
.override_redirect
= True
;
420 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
421 ButtonMotionMask
| EnterWindowMask
;
423 return XCreateWindow(blackbox
->getXDisplay(), screen
->getRootWindow(),
424 0, 0, 1, 1, frame
.border_w
, screen
->getDepth(),
425 InputOutput
, screen
->getVisual(), create_mask
,
431 * Creates a child window, and optionally associates a given cursor with
434 Window
BlackboxWindow::createChildWindow(Window parent
, Cursor cursor
) {
435 XSetWindowAttributes attrib_create
;
436 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
|
439 attrib_create
.background_pixmap
= None
;
440 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
441 ButtonMotionMask
| ExposureMask
;
444 create_mask
|= CWCursor
;
445 attrib_create
.cursor
= cursor
;
448 return XCreateWindow(blackbox
->getXDisplay(), parent
, 0, 0, 1, 1, 0,
449 screen
->getDepth(), InputOutput
, screen
->getVisual(),
450 create_mask
, &attrib_create
);
454 void BlackboxWindow::associateClientWindow(void) {
455 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, 0);
457 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeInsert
);
459 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, SubstructureRedirectMask
);
462 note we used to grab around this call to XReparentWindow however the
463 server is now grabbed before this method is called
465 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
467 XSelectInput(blackbox
->getXDisplay(), client
.window
,
468 event_mask
& ~StructureNotifyMask
);
469 XReparentWindow(blackbox
->getXDisplay(), client
.window
, frame
.plate
, 0, 0);
470 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
472 XRaiseWindow(blackbox
->getXDisplay(), frame
.plate
);
473 XMapSubwindows(blackbox
->getXDisplay(), frame
.plate
);
476 if (blackbox
->hasShapeExtensions()) {
477 XShapeSelectInput(blackbox
->getXDisplay(), client
.window
,
484 XShapeQueryExtents(blackbox
->getXDisplay(), client
.window
, &shaped
,
485 &foo
, &foo
, &ufoo
, &ufoo
, &foo
, &foo
, &foo
,
487 flags
.shaped
= shaped
;
493 void BlackboxWindow::decorate(void) {
496 texture
= &(screen
->getWindowStyle()->b_focus
);
497 frame
.fbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
500 frame
.fbutton_pixel
= texture
->color().pixel();
502 texture
= &(screen
->getWindowStyle()->b_unfocus
);
503 frame
.ubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
506 frame
.ubutton_pixel
= texture
->color().pixel();
508 texture
= &(screen
->getWindowStyle()->b_pressed
);
509 frame
.pbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
512 frame
.pbutton_pixel
= texture
->color().pixel();
514 if (decorations
& Decor_Titlebar
) {
515 texture
= &(screen
->getWindowStyle()->t_focus
);
516 frame
.ftitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
519 frame
.ftitle_pixel
= texture
->color().pixel();
521 texture
= &(screen
->getWindowStyle()->t_unfocus
);
522 frame
.utitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
525 frame
.utitle_pixel
= texture
->color().pixel();
527 XSetWindowBorder(blackbox
->getXDisplay(), frame
.title
,
528 screen
->getBorderColor()->pixel());
533 if (decorations
& Decor_Border
) {
534 frame
.fborder_pixel
= screen
->getWindowStyle()->f_focus
.pixel();
535 frame
.uborder_pixel
= screen
->getWindowStyle()->f_unfocus
.pixel();
536 blackbox_attrib
.flags
|= AttribDecoration
;
537 blackbox_attrib
.decoration
= DecorNormal
;
539 blackbox_attrib
.flags
|= AttribDecoration
;
540 blackbox_attrib
.decoration
= DecorNone
;
543 if (decorations
& Decor_Handle
) {
544 texture
= &(screen
->getWindowStyle()->h_focus
);
545 frame
.fhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
548 frame
.fhandle_pixel
= texture
->color().pixel();
550 texture
= &(screen
->getWindowStyle()->h_unfocus
);
551 frame
.uhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
554 frame
.uhandle_pixel
= texture
->color().pixel();
556 texture
= &(screen
->getWindowStyle()->g_focus
);
557 frame
.fgrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.fgrip
);
559 frame
.fgrip_pixel
= texture
->color().pixel();
561 texture
= &(screen
->getWindowStyle()->g_unfocus
);
562 frame
.ugrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.ugrip
);
564 frame
.ugrip_pixel
= texture
->color().pixel();
566 XSetWindowBorder(blackbox
->getXDisplay(), frame
.handle
,
567 screen
->getBorderColor()->pixel());
568 XSetWindowBorder(blackbox
->getXDisplay(), frame
.left_grip
,
569 screen
->getBorderColor()->pixel());
570 XSetWindowBorder(blackbox
->getXDisplay(), frame
.right_grip
,
571 screen
->getBorderColor()->pixel());
574 XSetWindowBorder(blackbox
->getXDisplay(), frame
.window
,
575 screen
->getBorderColor()->pixel());
579 void BlackboxWindow::decorateLabel(void) {
582 texture
= &(screen
->getWindowStyle()->l_focus
);
583 frame
.flabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.flabel
);
585 frame
.flabel_pixel
= texture
->color().pixel();
587 texture
= &(screen
->getWindowStyle()->l_unfocus
);
588 frame
.ulabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.ulabel
);
590 frame
.ulabel_pixel
= texture
->color().pixel();
594 void BlackboxWindow::createHandle(void) {
595 frame
.handle
= createChildWindow(frame
.window
);
596 blackbox
->saveWindowSearch(frame
.handle
, this);
599 createChildWindow(frame
.handle
, blackbox
->getLowerLeftAngleCursor());
600 blackbox
->saveWindowSearch(frame
.left_grip
, this);
603 createChildWindow(frame
.handle
, blackbox
->getLowerRightAngleCursor());
604 blackbox
->saveWindowSearch(frame
.right_grip
, this);
608 void BlackboxWindow::destroyHandle(void) {
610 screen
->getImageControl()->removeImage(frame
.fhandle
);
613 screen
->getImageControl()->removeImage(frame
.uhandle
);
616 screen
->getImageControl()->removeImage(frame
.fgrip
);
619 screen
->getImageControl()->removeImage(frame
.ugrip
);
621 blackbox
->removeWindowSearch(frame
.left_grip
);
622 blackbox
->removeWindowSearch(frame
.right_grip
);
624 XDestroyWindow(blackbox
->getXDisplay(), frame
.left_grip
);
625 XDestroyWindow(blackbox
->getXDisplay(), frame
.right_grip
);
626 frame
.left_grip
= frame
.right_grip
= None
;
628 blackbox
->removeWindowSearch(frame
.handle
);
629 XDestroyWindow(blackbox
->getXDisplay(), frame
.handle
);
634 void BlackboxWindow::createTitlebar(void) {
635 frame
.title
= createChildWindow(frame
.window
);
636 frame
.label
= createChildWindow(frame
.title
);
637 blackbox
->saveWindowSearch(frame
.title
, this);
638 blackbox
->saveWindowSearch(frame
.label
, this);
640 if (decorations
& Decor_Iconify
) createIconifyButton();
641 if (decorations
& Decor_Maximize
) createMaximizeButton();
642 if (decorations
& Decor_Close
) createCloseButton();
646 void BlackboxWindow::destroyTitlebar(void) {
647 if (frame
.close_button
)
648 destroyCloseButton();
650 if (frame
.iconify_button
)
651 destroyIconifyButton();
653 if (frame
.maximize_button
)
654 destroyMaximizeButton();
657 screen
->getImageControl()->removeImage(frame
.ftitle
);
660 screen
->getImageControl()->removeImage(frame
.utitle
);
663 screen
->getImageControl()->removeImage(frame
.flabel
);
666 screen
->getImageControl()->removeImage(frame
.ulabel
);
669 screen
->getImageControl()->removeImage(frame
.fbutton
);
672 screen
->getImageControl()->removeImage(frame
.ubutton
);
675 screen
->getImageControl()->removeImage(frame
.pbutton
);
677 blackbox
->removeWindowSearch(frame
.title
);
678 blackbox
->removeWindowSearch(frame
.label
);
680 XDestroyWindow(blackbox
->getXDisplay(), frame
.label
);
681 XDestroyWindow(blackbox
->getXDisplay(), frame
.title
);
682 frame
.title
= frame
.label
= None
;
686 void BlackboxWindow::createCloseButton(void) {
687 if (frame
.title
!= None
) {
688 frame
.close_button
= createChildWindow(frame
.title
);
689 blackbox
->saveWindowSearch(frame
.close_button
, this);
694 void BlackboxWindow::destroyCloseButton(void) {
695 blackbox
->removeWindowSearch(frame
.close_button
);
696 XDestroyWindow(blackbox
->getXDisplay(), frame
.close_button
);
697 frame
.close_button
= None
;
701 void BlackboxWindow::createIconifyButton(void) {
702 if (frame
.title
!= None
) {
703 frame
.iconify_button
= createChildWindow(frame
.title
);
704 blackbox
->saveWindowSearch(frame
.iconify_button
, this);
709 void BlackboxWindow::destroyIconifyButton(void) {
710 blackbox
->removeWindowSearch(frame
.iconify_button
);
711 XDestroyWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
712 frame
.iconify_button
= None
;
716 void BlackboxWindow::createMaximizeButton(void) {
717 if (frame
.title
!= None
) {
718 frame
.maximize_button
= createChildWindow(frame
.title
);
719 blackbox
->saveWindowSearch(frame
.maximize_button
, this);
724 void BlackboxWindow::destroyMaximizeButton(void) {
725 blackbox
->removeWindowSearch(frame
.maximize_button
);
726 XDestroyWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
727 frame
.maximize_button
= None
;
731 void BlackboxWindow::positionButtons(bool redecorate_label
) {
732 string layout
= blackbox
->getTitlebarLayout();
735 bool hasclose
, hasiconify
, hasmaximize
, haslabel
;
736 hasclose
= hasiconify
= hasmaximize
= haslabel
= false;
738 string::const_iterator it
, end
;
739 for (it
= layout
.begin(), end
= layout
.end(); it
!= end
; ++it
) {
742 if (! hasclose
&& (decorations
& Decor_Close
)) {
748 if (! hasiconify
&& (decorations
& Decor_Iconify
)) {
754 if (! hasmaximize
&& (decorations
& Decor_Maximize
)) {
766 if (! hasclose
&& frame
.close_button
)
767 destroyCloseButton();
768 if (! hasiconify
&& frame
.iconify_button
)
769 destroyIconifyButton();
770 if (! hasmaximize
&& frame
.maximize_button
)
771 destroyMaximizeButton();
773 parsed
+= 'L'; // require that the label be in the layout
775 const unsigned int bsep
= frame
.bevel_w
+ 1; // separation between elements
776 const unsigned int by
= frame
.bevel_w
+ 1;
777 const unsigned int ty
= frame
.bevel_w
;
779 frame
.label_w
= frame
.inside_w
- bsep
* 2 -
780 (frame
.button_w
+ bsep
) * (parsed
.size() - 1);
782 unsigned int x
= bsep
;
783 for (it
= parsed
.begin(), end
= parsed
.end(); it
!= end
; ++it
) {
786 if (! frame
.close_button
) createCloseButton();
787 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.close_button
, x
, by
,
788 frame
.button_w
, frame
.button_w
);
789 x
+= frame
.button_w
+ bsep
;
792 if (! frame
.iconify_button
) createIconifyButton();
793 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.iconify_button
, x
, by
,
794 frame
.button_w
, frame
.button_w
);
795 x
+= frame
.button_w
+ bsep
;
798 if (! frame
.maximize_button
) createMaximizeButton();
799 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.maximize_button
, x
, by
,
800 frame
.button_w
, frame
.button_w
);
801 x
+= frame
.button_w
+ bsep
;
804 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.label
, x
, ty
,
805 frame
.label_w
, frame
.label_h
);
806 x
+= frame
.label_w
+ bsep
;
811 if (redecorate_label
) decorateLabel();
817 void BlackboxWindow::reconfigure(void) {
818 restoreGravity(client
.rect
);
820 applyGravity(frame
.rect
);
829 windowmenu
->move(windowmenu
->getX(), frame
.rect
.y() + frame
.title_h
);
830 windowmenu
->reconfigure();
835 void BlackboxWindow::grabButtons(void) {
836 if (! screen
->isSloppyFocus() || screen
->doClickRaise())
837 // grab button 1 for changing focus/raising
838 blackbox
->grabButton(Button1
, 0, frame
.plate
, True
, ButtonPressMask
,
839 GrabModeSync
, GrabModeSync
, frame
.plate
, None
,
840 screen
->allowScrollLock());
842 if (functions
& Func_Move
)
843 blackbox
->grabButton(Button1
, ModMask
, frame
.window
, True
,
844 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
845 GrabModeAsync
, frame
.window
, None
,
846 screen
->allowScrollLock());
847 if (functions
& Func_Resize
)
848 blackbox
->grabButton(Button3
, ModMask
, frame
.window
, True
,
849 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
850 GrabModeAsync
, frame
.window
, None
,
851 screen
->allowScrollLock());
852 // alt+middle lowers the window
853 blackbox
->grabButton(Button2
, ModMask
, frame
.window
, True
,
854 ButtonReleaseMask
, GrabModeAsync
, GrabModeAsync
,
856 screen
->allowScrollLock());
860 void BlackboxWindow::ungrabButtons(void) {
861 blackbox
->ungrabButton(Button1
, 0, frame
.plate
);
862 blackbox
->ungrabButton(Button1
, ModMask
, frame
.window
);
863 blackbox
->ungrabButton(Button2
, ModMask
, frame
.window
);
864 blackbox
->ungrabButton(Button3
, ModMask
, frame
.window
);
868 void BlackboxWindow::positionWindows(void) {
869 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.window
,
870 frame
.rect
.x(), frame
.rect
.y(), frame
.inside_w
,
871 (flags
.shaded
) ? frame
.title_h
: frame
.inside_h
);
872 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.window
,
874 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.plate
,
876 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.plate
,
877 frame
.margin
.left
- frame
.mwm_border_w
- frame
.border_w
,
878 frame
.margin
.top
- frame
.mwm_border_w
- frame
.border_w
,
879 client
.rect
.width(), client
.rect
.height());
880 XMoveResizeWindow(blackbox
->getXDisplay(), client
.window
,
881 0, 0, client
.rect
.width(), client
.rect
.height());
882 // ensure client.rect contains the real location
883 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
884 frame
.rect
.top() + frame
.margin
.top
);
886 if (decorations
& Decor_Titlebar
) {
887 if (frame
.title
== None
) createTitlebar();
889 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.title
,
891 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.title
, -frame
.border_w
,
892 -frame
.border_w
, frame
.inside_w
, frame
.title_h
);
895 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
896 XMapWindow(blackbox
->getXDisplay(), frame
.title
);
897 } else if (frame
.title
) {
900 if (decorations
& Decor_Handle
) {
901 if (frame
.handle
== None
) createHandle();
902 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.handle
,
904 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.left_grip
,
906 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.right_grip
,
909 // use client.rect here so the value is correct even if shaded
910 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.handle
,
912 client
.rect
.height() + frame
.margin
.top
+
913 frame
.mwm_border_w
- frame
.border_w
,
914 frame
.inside_w
, frame
.handle_h
);
915 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.left_grip
,
916 -frame
.border_w
, -frame
.border_w
,
917 frame
.grip_w
, frame
.handle_h
);
918 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.right_grip
,
919 frame
.inside_w
- frame
.grip_w
- frame
.border_w
,
920 -frame
.border_w
, frame
.grip_w
, frame
.handle_h
);
922 XMapSubwindows(blackbox
->getXDisplay(), frame
.handle
);
923 XMapWindow(blackbox
->getXDisplay(), frame
.handle
);
924 } else if (frame
.handle
) {
927 XSync(blackbox
->getXDisplay(), False
);
931 void BlackboxWindow::updateStrut(void) {
932 unsigned long num
= 4;
934 if (! xatom
->getValue(client
.window
, XAtom::net_wm_strut
, XAtom::cardinal
,
939 client
.strut
.left
= data
[0];
940 client
.strut
.right
= data
[1];
941 client
.strut
.top
= data
[2];
942 client
.strut
.bottom
= data
[3];
944 screen
->updateAvailableArea();
951 void BlackboxWindow::getWindowType(void) {
953 if (xatom
->getValue(client
.window
, XAtom::net_wm_window_type
, XAtom::atom
,
955 if (val
== xatom
->getAtom(XAtom::net_wm_window_type_desktop
))
956 window_type
= Type_Desktop
;
957 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_dock
))
958 window_type
= Type_Dock
;
959 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_toolbar
))
960 window_type
= Type_Toolbar
;
961 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_menu
))
962 window_type
= Type_Menu
;
963 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_utility
))
964 window_type
= Type_Utility
;
965 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_splash
))
966 window_type
= Type_Splash
;
967 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_dialog
))
968 window_type
= Type_Dialog
;
969 else //if (val[0] == xatom->getAtom(XAtom::net_wm_window_type_normal))
970 window_type
= Type_Normal
;
975 * the window type hint was not set, which means we either classify ourself
976 * as a normal window or a dialog, depending on if we are a transient.
979 window_type
= Type_Dialog
;
981 window_type
= Type_Normal
;
985 void BlackboxWindow::getWMName(void) {
986 if (xatom
->getValue(client
.window
, XAtom::net_wm_name
,
987 XAtom::utf8
, client
.title
) &&
988 !client
.title
.empty()) {
989 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
992 //fall through to using WM_NAME
993 if (xatom
->getValue(client
.window
, XAtom::wm_name
, XAtom::ansi
, client
.title
)
994 && !client
.title
.empty()) {
995 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
998 // fall back to an internal default
999 client
.title
= i18n(WindowSet
, WindowUnnamed
, "Unnamed");
1000 xatom
->setValue(client
.window
, XAtom::net_wm_visible_name
, XAtom::utf8
,
1005 void BlackboxWindow::getWMIconName(void) {
1006 if (xatom
->getValue(client
.window
, XAtom::net_wm_icon_name
,
1007 XAtom::utf8
, client
.icon_title
) &&
1008 !client
.icon_title
.empty()) {
1009 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1012 //fall through to using WM_ICON_NAME
1013 if (xatom
->getValue(client
.window
, XAtom::wm_icon_name
, XAtom::ansi
,
1014 client
.icon_title
) &&
1015 !client
.icon_title
.empty()) {
1016 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1019 // fall back to using the main name
1020 client
.icon_title
= client
.title
;
1021 xatom
->setValue(client
.window
, XAtom::net_wm_visible_icon_name
, XAtom::utf8
,
1027 * Retrieve which WM Protocols are supported by the client window.
1028 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
1029 * window's decorations and allow the close behavior.
1030 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
1033 void BlackboxWindow::getWMProtocols(void) {
1037 if (XGetWMProtocols(blackbox
->getXDisplay(), client
.window
,
1038 &proto
, &num_return
)) {
1039 for (int i
= 0; i
< num_return
; ++i
) {
1040 if (proto
[i
] == xatom
->getAtom(XAtom::wm_delete_window
)) {
1041 decorations
|= Decor_Close
;
1042 functions
|= Func_Close
;
1043 } else if (proto
[i
] == xatom
->getAtom(XAtom::wm_take_focus
))
1044 flags
.send_focus_message
= True
;
1045 else if (proto
[i
] == xatom
->getAtom(XAtom::blackbox_structure_messages
))
1046 screen
->addNetizen(new Netizen(screen
, client
.window
));
1055 * Gets the value of the WM_HINTS property.
1056 * If the property is not set, then use a set of default values.
1058 void BlackboxWindow::getWMHints(void) {
1059 focus_mode
= F_Passive
;
1061 // remove from current window group
1062 if (client
.window_group
) {
1063 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1064 if (group
) group
->removeWindow(this);
1066 client
.window_group
= None
;
1068 XWMHints
*wmhint
= XGetWMHints(blackbox
->getXDisplay(), client
.window
);
1073 if (wmhint
->flags
& InputHint
) {
1074 if (wmhint
->input
== True
) {
1075 if (flags
.send_focus_message
)
1076 focus_mode
= F_LocallyActive
;
1078 if (flags
.send_focus_message
)
1079 focus_mode
= F_GloballyActive
;
1081 focus_mode
= F_NoInput
;
1085 if (wmhint
->flags
& StateHint
)
1086 current_state
= wmhint
->initial_state
;
1088 if (wmhint
->flags
& WindowGroupHint
) {
1089 client
.window_group
= wmhint
->window_group
;
1091 // add window to the appropriate group
1092 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1093 if (! group
) { // no group found, create it!
1094 new BWindowGroup(blackbox
, client
.window_group
);
1095 group
= blackbox
->searchGroup(client
.window_group
);
1098 group
->addWindow(this);
1106 * Gets the value of the WM_NORMAL_HINTS property.
1107 * If the property is not set, then use a set of default values.
1109 void BlackboxWindow::getWMNormalHints(void) {
1111 XSizeHints sizehint
;
1113 client
.min_width
= client
.min_height
=
1114 client
.width_inc
= client
.height_inc
= 1;
1115 client
.base_width
= client
.base_height
= 0;
1116 client
.win_gravity
= NorthWestGravity
;
1118 client
.min_aspect_x
= client
.min_aspect_y
=
1119 client
.max_aspect_x
= client
.max_aspect_y
= 1;
1123 use the full screen, not the strut modified size. otherwise when the
1124 availableArea changes max_width/height will be incorrect and lead to odd
1127 const Rect
& screen_area
= screen
->getRect();
1128 client
.max_width
= screen_area
.width();
1129 client
.max_height
= screen_area
.height();
1131 if (! XGetWMNormalHints(blackbox
->getXDisplay(), client
.window
,
1132 &sizehint
, &icccm_mask
))
1135 client
.normal_hint_flags
= sizehint
.flags
;
1137 if (sizehint
.flags
& PMinSize
) {
1138 if (sizehint
.min_width
>= 0)
1139 client
.min_width
= sizehint
.min_width
;
1140 if (sizehint
.min_height
>= 0)
1141 client
.min_height
= sizehint
.min_height
;
1144 if (sizehint
.flags
& PMaxSize
) {
1145 if (sizehint
.max_width
> static_cast<signed>(client
.min_width
))
1146 client
.max_width
= sizehint
.max_width
;
1148 client
.max_width
= client
.min_width
;
1150 if (sizehint
.max_height
> static_cast<signed>(client
.min_height
))
1151 client
.max_height
= sizehint
.max_height
;
1153 client
.max_height
= client
.min_height
;
1156 if (sizehint
.flags
& PResizeInc
) {
1157 client
.width_inc
= sizehint
.width_inc
;
1158 client
.height_inc
= sizehint
.height_inc
;
1161 #if 0 // we do not support this at the moment
1162 if (sizehint
.flags
& PAspect
) {
1163 client
.min_aspect_x
= sizehint
.min_aspect
.x
;
1164 client
.min_aspect_y
= sizehint
.min_aspect
.y
;
1165 client
.max_aspect_x
= sizehint
.max_aspect
.x
;
1166 client
.max_aspect_y
= sizehint
.max_aspect
.y
;
1170 if (sizehint
.flags
& PBaseSize
) {
1171 client
.base_width
= sizehint
.base_width
;
1172 client
.base_height
= sizehint
.base_height
;
1175 if (sizehint
.flags
& PWinGravity
)
1176 client
.win_gravity
= sizehint
.win_gravity
;
1181 * Gets the NETWM hints for the class' contained window.
1183 void BlackboxWindow::getNetWMHints(void) {
1184 unsigned long workspace
;
1186 if (xatom
->getValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1188 if (workspace
== 0xffffffff)
1191 blackbox_attrib
.workspace
= workspace
;
1194 unsigned long *state
;
1195 unsigned long num
= (unsigned) -1;
1196 if (xatom
->getValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
1200 for (unsigned long i
= 0; i
< num
; ++i
) {
1201 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
))
1203 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_shaded
))
1204 flags
.shaded
= True
;
1205 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
))
1206 flags
.skip_taskbar
= True
;
1207 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_pager
))
1208 flags
.skip_pager
= True
;
1209 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_fullscreen
))
1210 flags
.fullscreen
= True
;
1211 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_hidden
))
1212 setState(IconicState
);
1213 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_vert
))
1215 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_horz
))
1219 flags
.maximized
= 1;
1221 flags
.maximized
= 2;
1223 flags
.maximized
= 3;
1231 * Gets the MWM hints for the class' contained window.
1232 * This is used while initializing the window to its first state, and not
1234 * Returns: true if the MWM hints are successfully retreived and applied;
1235 * false if they are not.
1237 void BlackboxWindow::getMWMHints(void) {
1241 num
= PropMwmHintsElements
;
1242 if (! xatom
->getValue(client
.window
, XAtom::motif_wm_hints
,
1243 XAtom::motif_wm_hints
, num
,
1244 (unsigned long **)&mwm_hint
))
1246 if (num
< PropMwmHintsElements
) {
1251 if (mwm_hint
->flags
& MwmHintsDecorations
) {
1252 if (mwm_hint
->decorations
& MwmDecorAll
) {
1253 decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
1254 Decor_Iconify
| Decor_Maximize
| Decor_Close
;
1258 if (mwm_hint
->decorations
& MwmDecorBorder
)
1259 decorations
|= Decor_Border
;
1260 if (mwm_hint
->decorations
& MwmDecorHandle
)
1261 decorations
|= Decor_Handle
;
1262 if (mwm_hint
->decorations
& MwmDecorTitle
)
1263 decorations
|= Decor_Titlebar
;
1264 if (mwm_hint
->decorations
& MwmDecorIconify
)
1265 decorations
|= Decor_Iconify
;
1266 if (mwm_hint
->decorations
& MwmDecorMaximize
)
1267 decorations
|= Decor_Maximize
;
1271 if (mwm_hint
->flags
& MwmHintsFunctions
) {
1272 if (mwm_hint
->functions
& MwmFuncAll
) {
1273 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
|
1278 if (mwm_hint
->functions
& MwmFuncResize
)
1279 functions
|= Func_Resize
;
1280 if (mwm_hint
->functions
& MwmFuncMove
)
1281 functions
|= Func_Move
;
1282 if (mwm_hint
->functions
& MwmFuncIconify
)
1283 functions
|= Func_Iconify
;
1284 if (mwm_hint
->functions
& MwmFuncMaximize
)
1285 functions
|= Func_Maximize
;
1286 if (mwm_hint
->functions
& MwmFuncClose
)
1287 functions
|= Func_Close
;
1295 * Gets the blackbox hints from the class' contained window.
1296 * This is used while initializing the window to its first state, and not
1298 * Returns: true if the hints are successfully retreived and applied; false if
1301 bool BlackboxWindow::getBlackboxHints(void) {
1303 BlackboxHints
*blackbox_hint
;
1305 num
= PropBlackboxHintsElements
;
1306 if (! xatom
->getValue(client
.window
, XAtom::blackbox_hints
,
1307 XAtom::blackbox_hints
, num
,
1308 (unsigned long **)&blackbox_hint
))
1310 if (num
< PropBlackboxHintsElements
) {
1311 delete [] blackbox_hint
;
1315 if (blackbox_hint
->flags
& AttribShaded
)
1316 flags
.shaded
= (blackbox_hint
->attrib
& AttribShaded
);
1318 if ((blackbox_hint
->flags
& AttribMaxHoriz
) &&
1319 (blackbox_hint
->flags
& AttribMaxVert
))
1320 flags
.maximized
= (blackbox_hint
->attrib
&
1321 (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1322 else if (blackbox_hint
->flags
& AttribMaxVert
)
1323 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxVert
) ? 2 : 0;
1324 else if (blackbox_hint
->flags
& AttribMaxHoriz
)
1325 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1327 if (blackbox_hint
->flags
& AttribOmnipresent
)
1328 flags
.stuck
= (blackbox_hint
->attrib
& AttribOmnipresent
);
1330 if (blackbox_hint
->flags
& AttribWorkspace
)
1331 blackbox_attrib
.workspace
= blackbox_hint
->workspace
;
1333 // if (blackbox_hint->flags & AttribStack)
1334 // don't yet have always on top/bottom for blackbox yet... working
1337 if (blackbox_hint
->flags
& AttribDecoration
) {
1338 switch (blackbox_hint
->decoration
) {
1344 decorations
|= Decor_Titlebar
| Decor_Iconify
;
1345 decorations
&= ~(Decor_Border
| Decor_Handle
| Decor_Maximize
);
1346 functions
&= ~(Func_Resize
| Func_Maximize
);
1351 decorations
|= Decor_Titlebar
;
1352 decorations
&= ~(Decor_Iconify
| Decor_Border
| Decor_Handle
);
1353 functions
&= ~(Func_Resize
| Func_Maximize
| Func_Iconify
);
1359 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Handle
|
1360 Decor_Iconify
| Decor_Maximize
;
1367 delete [] blackbox_hint
;
1373 void BlackboxWindow::getTransientInfo(void) {
1374 if (client
.transient_for
&&
1375 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1376 // reset transient_for in preparation of looking for a new owner
1377 client
.transient_for
->client
.transientList
.remove(this);
1380 // we have no transient_for until we find a new one
1381 client
.transient_for
= 0;
1384 if (! XGetTransientForHint(blackbox
->getXDisplay(), client
.window
,
1386 // transient_for hint not set
1390 if (trans_for
== client
.window
) {
1391 // wierd client... treat this window as a normal window
1395 if (trans_for
== None
|| trans_for
== screen
->getRootWindow()) {
1396 // this is an undocumented interpretation of the ICCCM. a transient
1397 // associated with None/Root/itself is assumed to be a modal root
1398 // transient. we don't support the concept of a global transient,
1399 // so we just associate this transient with nothing, and perhaps
1400 // we will add support later for global modality.
1401 client
.transient_for
= (BlackboxWindow
*) ~0ul;
1406 client
.transient_for
= blackbox
->searchWindow(trans_for
);
1407 if (! client
.transient_for
&&
1408 client
.window_group
&& trans_for
== client
.window_group
) {
1409 // no direct transient_for, perhaps this is a group transient?
1410 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1411 if (group
) client
.transient_for
= group
->find(screen
);
1414 if (! client
.transient_for
|| client
.transient_for
== this) {
1415 // no transient_for found, or we have a wierd client that wants to be
1416 // a transient for itself, so we treat this window as a normal window
1417 client
.transient_for
= (BlackboxWindow
*) 0;
1421 // register ourselves with our new transient_for
1422 client
.transient_for
->client
.transientList
.push_back(this);
1423 flags
.stuck
= client
.transient_for
->flags
.stuck
;
1427 BlackboxWindow
*BlackboxWindow::getTransientFor(void) const {
1428 if (client
.transient_for
&&
1429 client
.transient_for
!= (BlackboxWindow
*) ~0ul)
1430 return client
.transient_for
;
1436 * This function is responsible for updating both the client and the frame
1438 * According to the ICCCM a client message is not sent for a resize, only a
1441 void BlackboxWindow::configure(int dx
, int dy
,
1442 unsigned int dw
, unsigned int dh
) {
1443 bool send_event
= ((frame
.rect
.x() != dx
|| frame
.rect
.y() != dy
) &&
1446 if (dw
!= frame
.rect
.width() || dh
!= frame
.rect
.height()) {
1447 frame
.rect
.setRect(dx
, dy
, dw
, dh
);
1448 frame
.inside_w
= frame
.rect
.width() - (frame
.border_w
* 2);
1449 frame
.inside_h
= frame
.rect
.height() - (frame
.border_w
* 2);
1451 if (frame
.rect
.right() <= 0 || frame
.rect
.bottom() <= 0)
1452 frame
.rect
.setPos(0, 0);
1454 client
.rect
.setCoords(frame
.rect
.left() + frame
.margin
.left
,
1455 frame
.rect
.top() + frame
.margin
.top
,
1456 frame
.rect
.right() - frame
.margin
.right
,
1457 frame
.rect
.bottom() - frame
.margin
.bottom
);
1460 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
1467 redrawWindowFrame();
1469 frame
.rect
.setPos(dx
, dy
);
1471 XMoveWindow(blackbox
->getXDisplay(), frame
.window
,
1472 frame
.rect
.x(), frame
.rect
.y());
1474 we may have been called just after an opaque window move, so even though
1475 the old coords match the new ones no ConfigureNotify has been sent yet.
1476 There are likely other times when this will be relevant as well.
1478 if (! flags
.moving
) send_event
= True
;
1482 // if moving, the update and event will occur when the move finishes
1483 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1484 frame
.rect
.top() + frame
.margin
.top
);
1487 event
.type
= ConfigureNotify
;
1489 event
.xconfigure
.display
= blackbox
->getXDisplay();
1490 event
.xconfigure
.event
= client
.window
;
1491 event
.xconfigure
.window
= client
.window
;
1492 event
.xconfigure
.x
= client
.rect
.x();
1493 event
.xconfigure
.y
= client
.rect
.y();
1494 event
.xconfigure
.width
= client
.rect
.width();
1495 event
.xconfigure
.height
= client
.rect
.height();
1496 event
.xconfigure
.border_width
= client
.old_bw
;
1497 event
.xconfigure
.above
= frame
.window
;
1498 event
.xconfigure
.override_redirect
= False
;
1500 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1501 StructureNotifyMask
, &event
);
1502 screen
->updateNetizenConfigNotify(&event
);
1503 XFlush(blackbox
->getXDisplay());
1509 void BlackboxWindow::configureShape(void) {
1510 XShapeCombineShape(blackbox
->getXDisplay(), frame
.window
, ShapeBounding
,
1511 frame
.margin
.left
- frame
.border_w
,
1512 frame
.margin
.top
- frame
.border_w
,
1513 client
.window
, ShapeBounding
, ShapeSet
);
1516 XRectangle xrect
[2];
1518 if (decorations
& Decor_Titlebar
) {
1519 xrect
[0].x
= xrect
[0].y
= -frame
.border_w
;
1520 xrect
[0].width
= frame
.rect
.width();
1521 xrect
[0].height
= frame
.title_h
+ (frame
.border_w
* 2);
1525 if (decorations
& Decor_Handle
) {
1526 xrect
[1].x
= -frame
.border_w
;
1527 xrect
[1].y
= frame
.rect
.height() - frame
.margin
.bottom
+
1528 frame
.mwm_border_w
- frame
.border_w
;
1529 xrect
[1].width
= frame
.rect
.width();
1530 xrect
[1].height
= frame
.handle_h
+ (frame
.border_w
* 2);
1534 XShapeCombineRectangles(blackbox
->getXDisplay(), frame
.window
,
1535 ShapeBounding
, 0, 0, xrect
, num
,
1536 ShapeUnion
, Unsorted
);
1541 bool BlackboxWindow::setInputFocus(void) {
1542 if (flags
.focused
) return True
;
1544 assert((flags
.stuck
|| // window must be on the current workspace or sticky
1545 blackbox_attrib
.workspace
== screen
->getCurrentWorkspaceID()));
1548 We only do this check for normal windows and dialogs because other windows
1549 do this on purpose, such as kde's kicker, and we don't want to go moving
1552 if (window_type
== Type_Normal
|| window_type
== Type_Dialog
)
1553 if (! frame
.rect
.intersects(screen
->getRect())) {
1554 // client is outside the screen, move it to the center
1555 configure((screen
->getWidth() - frame
.rect
.width()) / 2,
1556 (screen
->getHeight() - frame
.rect
.height()) / 2,
1557 frame
.rect
.width(), frame
.rect
.height());
1560 if (client
.transientList
.size() > 0) {
1561 // transfer focus to any modal transients
1562 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1563 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1564 if ((*it
)->flags
.modal
) return (*it
)->setInputFocus();
1569 if (focus_mode
== F_LocallyActive
|| focus_mode
== F_Passive
) {
1570 XSetInputFocus(blackbox
->getXDisplay(), client
.window
,
1571 RevertToPointerRoot
, CurrentTime
);
1573 /* we could set the focus to none, since the window doesn't accept focus,
1574 * but we shouldn't set focus to nothing since this would surely make
1580 if (flags
.send_focus_message
) {
1582 ce
.xclient
.type
= ClientMessage
;
1583 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1584 ce
.xclient
.display
= blackbox
->getXDisplay();
1585 ce
.xclient
.window
= client
.window
;
1586 ce
.xclient
.format
= 32;
1587 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_take_focus
);
1588 ce
.xclient
.data
.l
[1] = blackbox
->getLastTime();
1589 ce
.xclient
.data
.l
[2] = 0l;
1590 ce
.xclient
.data
.l
[3] = 0l;
1591 ce
.xclient
.data
.l
[4] = 0l;
1592 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1594 XFlush(blackbox
->getXDisplay());
1601 void BlackboxWindow::iconify(void) {
1602 if (flags
.iconic
) return;
1604 // We don't need to worry about resizing because resizing always grabs the X
1605 // server. This should only ever happen if using opaque moving.
1609 if (windowmenu
) windowmenu
->hide();
1612 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1613 * we need to clear the event mask on client.window for a split second.
1614 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1615 * split second, leaving us with a ghost window... so, we need to do this
1616 * while the X server is grabbed
1618 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1619 StructureNotifyMask
;
1620 XGrabServer(blackbox
->getXDisplay());
1621 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1622 event_mask
& ~StructureNotifyMask
);
1623 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1624 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1625 XUngrabServer(blackbox
->getXDisplay());
1627 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1628 flags
.visible
= False
;
1629 flags
.iconic
= True
;
1631 setState(IconicState
);
1633 screen
->getWorkspace(blackbox_attrib
.workspace
)->removeWindow(this);
1635 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
1636 if (i
!= blackbox_attrib
.workspace
)
1637 screen
->getWorkspace(i
)->removeWindow(this, True
);
1640 if (isTransient()) {
1641 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1642 ! client
.transient_for
->flags
.iconic
) {
1643 // iconify our transient_for
1644 client
.transient_for
->iconify();
1648 screen
->addIcon(this);
1650 if (client
.transientList
.size() > 0) {
1651 // iconify all transients
1652 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1653 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1654 if (! (*it
)->flags
.iconic
) (*it
)->iconify();
1657 screen
->updateStackingList();
1661 void BlackboxWindow::show(void) {
1662 flags
.visible
= True
;
1663 flags
.iconic
= False
;
1665 current_state
= (flags
.shaded
) ? IconicState
: NormalState
;
1666 setState(current_state
);
1668 XMapWindow(blackbox
->getXDisplay(), client
.window
);
1669 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
1670 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
1675 XTranslateCoordinates(blackbox
->getXDisplay(), client
.window
,
1676 screen
->getRootWindow(),
1677 0, 0, &real_x
, &real_y
, &child
);
1678 fprintf(stderr
, "%s -- assumed: (%d, %d), real: (%d, %d)\n", getTitle(),
1679 client
.rect
.left(), client
.rect
.top(), real_x
, real_y
);
1680 assert(client
.rect
.left() == real_x
&& client
.rect
.top() == real_y
);
1685 void BlackboxWindow::deiconify(bool reassoc
, bool raise
) {
1686 if (flags
.iconic
|| reassoc
)
1687 screen
->reassociateWindow(this, BSENTINEL
, False
);
1688 else if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID())
1693 // reassociate and deiconify all transients
1694 if (reassoc
&& client
.transientList
.size() > 0) {
1695 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1696 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1697 (*it
)->deiconify(True
, False
);
1702 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1706 void BlackboxWindow::close(void) {
1708 ce
.xclient
.type
= ClientMessage
;
1709 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1710 ce
.xclient
.display
= blackbox
->getXDisplay();
1711 ce
.xclient
.window
= client
.window
;
1712 ce
.xclient
.format
= 32;
1713 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_delete_window
);
1714 ce
.xclient
.data
.l
[1] = CurrentTime
;
1715 ce
.xclient
.data
.l
[2] = 0l;
1716 ce
.xclient
.data
.l
[3] = 0l;
1717 ce
.xclient
.data
.l
[4] = 0l;
1718 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
, NoEventMask
, &ce
);
1719 XFlush(blackbox
->getXDisplay());
1723 void BlackboxWindow::withdraw(void) {
1724 // We don't need to worry about resizing because resizing always grabs the X
1725 // server. This should only ever happen if using opaque moving.
1729 flags
.visible
= False
;
1730 flags
.iconic
= False
;
1732 setState(current_state
);
1734 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1736 XGrabServer(blackbox
->getXDisplay());
1738 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1739 StructureNotifyMask
;
1740 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1741 event_mask
& ~StructureNotifyMask
);
1742 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1743 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1745 XUngrabServer(blackbox
->getXDisplay());
1747 if (windowmenu
) windowmenu
->hide();
1751 void BlackboxWindow::maximize(unsigned int button
) {
1752 // We don't need to worry about resizing because resizing always grabs the X
1753 // server. This should only ever happen if using opaque moving.
1757 // handle case where menu is open then the max button is used instead
1758 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
1760 if (flags
.maximized
) {
1761 flags
.maximized
= 0;
1763 blackbox_attrib
.flags
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1764 blackbox_attrib
.attrib
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1767 when a resize finishes, maximize(0) is called to clear any maximization
1768 flags currently set. Otherwise it still thinks it is maximized.
1769 so we do not need to call configure() because resizing will handle it
1771 if (! flags
.resizing
)
1772 configure(blackbox_attrib
.premax_x
, blackbox_attrib
.premax_y
,
1773 blackbox_attrib
.premax_w
, blackbox_attrib
.premax_h
);
1775 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
1776 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
1778 redrawAllButtons(); // in case it is not called in configure()
1779 setState(current_state
);
1783 blackbox_attrib
.premax_x
= frame
.rect
.x();
1784 blackbox_attrib
.premax_y
= frame
.rect
.y();
1785 blackbox_attrib
.premax_w
= frame
.rect
.width();
1786 // use client.rect so that clients can be restored even if shaded
1787 blackbox_attrib
.premax_h
=
1788 client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
;
1791 if (screen
->isXineramaActive() && blackbox
->doXineramaMaximizing()) {
1792 // find the area to use
1793 RectList availableAreas
= screen
->allAvailableAreas();
1794 RectList::iterator it
, end
= availableAreas
.end();
1796 for (it
= availableAreas
.begin(); it
!= end
; ++it
)
1797 if (it
->intersects(frame
.rect
)) break;
1798 if (it
== end
) // the window isn't inside an area
1799 it
= availableAreas
.begin(); // so just default to the first one
1801 frame
.changing
= *it
;
1804 frame
.changing
= screen
->availableArea();
1808 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1809 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1813 blackbox_attrib
.flags
|= AttribMaxVert
;
1814 blackbox_attrib
.attrib
|= AttribMaxVert
;
1816 frame
.changing
.setX(frame
.rect
.x());
1817 frame
.changing
.setWidth(frame
.rect
.width());
1821 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1822 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1824 frame
.changing
.setY(frame
.rect
.y());
1825 frame
.changing
.setHeight(frame
.rect
.height());
1832 blackbox_attrib
.flags
^= AttribShaded
;
1833 blackbox_attrib
.attrib
^= AttribShaded
;
1834 flags
.shaded
= False
;
1837 flags
.maximized
= button
;
1839 configure(frame
.changing
.x(), frame
.changing
.y(),
1840 frame
.changing
.width(), frame
.changing
.height());
1842 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1843 redrawAllButtons(); // in case it is not called in configure()
1844 setState(current_state
);
1848 // re-maximizes the window to take into account availableArea changes
1849 void BlackboxWindow::remaximize(void) {
1851 // we only update the window's attributes otherwise we lose the shade bit
1852 switch(flags
.maximized
) {
1854 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1855 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1859 blackbox_attrib
.flags
|= AttribMaxVert
;
1860 blackbox_attrib
.attrib
|= AttribMaxVert
;
1864 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1865 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1871 // save the original dimensions because maximize will wipe them out
1872 int premax_x
= blackbox_attrib
.premax_x
,
1873 premax_y
= blackbox_attrib
.premax_y
,
1874 premax_w
= blackbox_attrib
.premax_w
,
1875 premax_h
= blackbox_attrib
.premax_h
;
1877 unsigned int button
= flags
.maximized
;
1878 flags
.maximized
= 0; // trick maximize() into working
1881 // restore saved values
1882 blackbox_attrib
.premax_x
= premax_x
;
1883 blackbox_attrib
.premax_y
= premax_y
;
1884 blackbox_attrib
.premax_w
= premax_w
;
1885 blackbox_attrib
.premax_h
= premax_h
;
1889 void BlackboxWindow::setWorkspace(unsigned int n
) {
1890 blackbox_attrib
.flags
|= AttribWorkspace
;
1891 blackbox_attrib
.workspace
= n
;
1892 if (n
== BSENTINEL
) { // iconified window
1894 we set the workspace to 'all workspaces' so that taskbars will show the
1895 window. otherwise, it made uniconifying a window imposible without the
1896 blackbox workspace menu
1900 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
, n
);
1904 void BlackboxWindow::shade(void) {
1906 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1907 frame
.inside_w
, frame
.inside_h
);
1908 flags
.shaded
= False
;
1909 blackbox_attrib
.flags
^= AttribShaded
;
1910 blackbox_attrib
.attrib
^= AttribShaded
;
1912 setState(NormalState
);
1914 // set the frame rect to the normal size
1915 frame
.rect
.setHeight(client
.rect
.height() + frame
.margin
.top
+
1916 frame
.margin
.bottom
);
1918 if (! (decorations
& Decor_Titlebar
))
1919 return; // can't shade it without a titlebar!
1921 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1922 frame
.inside_w
, frame
.title_h
);
1923 flags
.shaded
= True
;
1924 blackbox_attrib
.flags
|= AttribShaded
;
1925 blackbox_attrib
.attrib
|= AttribShaded
;
1927 setState(IconicState
);
1929 // set the frame rect to the shaded size
1930 frame
.rect
.setHeight(frame
.title_h
+ (frame
.border_w
* 2));
1936 * (Un)Sticks a window and its relatives.
1938 void BlackboxWindow::stick(void) {
1940 blackbox_attrib
.flags
^= AttribOmnipresent
;
1941 blackbox_attrib
.attrib
^= AttribOmnipresent
;
1943 flags
.stuck
= False
;
1946 screen
->reassociateWindow(this, BSENTINEL
, True
);
1947 // temporary fix since sticky windows suck. set the hint to what we
1948 // actually hold in our data.
1949 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1950 blackbox_attrib
.workspace
);
1952 setState(current_state
);
1956 blackbox_attrib
.flags
|= AttribOmnipresent
;
1957 blackbox_attrib
.attrib
|= AttribOmnipresent
;
1959 // temporary fix since sticky windows suck. set the hint to a different
1960 // value than that contained in the class' data.
1961 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1964 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
1965 if (i
!= blackbox_attrib
.workspace
)
1966 screen
->getWorkspace(i
)->addWindow(this, False
, True
);
1968 setState(current_state
);
1971 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1972 client
.transient_for
->isStuck() != flags
.stuck
)
1973 client
.transient_for
->stick();
1974 // go down the chain
1975 BlackboxWindowList::iterator it
;
1976 const BlackboxWindowList::iterator end
= client
.transientList
.end();
1977 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1978 if ((*it
)->isStuck() != flags
.stuck
)
1983 void BlackboxWindow::redrawWindowFrame(void) const {
1984 if (decorations
& Decor_Titlebar
) {
1985 if (flags
.focused
) {
1987 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1988 frame
.title
, frame
.ftitle
);
1990 XSetWindowBackground(blackbox
->getXDisplay(),
1991 frame
.title
, frame
.ftitle_pixel
);
1994 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1995 frame
.title
, frame
.utitle
);
1997 XSetWindowBackground(blackbox
->getXDisplay(),
1998 frame
.title
, frame
.utitle_pixel
);
2000 XClearWindow(blackbox
->getXDisplay(), frame
.title
);
2006 if (decorations
& Decor_Handle
) {
2007 if (flags
.focused
) {
2009 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2010 frame
.handle
, frame
.fhandle
);
2012 XSetWindowBackground(blackbox
->getXDisplay(),
2013 frame
.handle
, frame
.fhandle_pixel
);
2016 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2017 frame
.left_grip
, frame
.fgrip
);
2018 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2019 frame
.right_grip
, frame
.fgrip
);
2021 XSetWindowBackground(blackbox
->getXDisplay(),
2022 frame
.left_grip
, frame
.fgrip_pixel
);
2023 XSetWindowBackground(blackbox
->getXDisplay(),
2024 frame
.right_grip
, frame
.fgrip_pixel
);
2028 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2029 frame
.handle
, frame
.uhandle
);
2031 XSetWindowBackground(blackbox
->getXDisplay(),
2032 frame
.handle
, frame
.uhandle_pixel
);
2035 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2036 frame
.left_grip
, frame
.ugrip
);
2037 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2038 frame
.right_grip
, frame
.ugrip
);
2040 XSetWindowBackground(blackbox
->getXDisplay(),
2041 frame
.left_grip
, frame
.ugrip_pixel
);
2042 XSetWindowBackground(blackbox
->getXDisplay(),
2043 frame
.right_grip
, frame
.ugrip_pixel
);
2046 XClearWindow(blackbox
->getXDisplay(), frame
.handle
);
2047 XClearWindow(blackbox
->getXDisplay(), frame
.left_grip
);
2048 XClearWindow(blackbox
->getXDisplay(), frame
.right_grip
);
2051 if (decorations
& Decor_Border
) {
2053 XSetWindowBorder(blackbox
->getXDisplay(),
2054 frame
.plate
, frame
.fborder_pixel
);
2056 XSetWindowBorder(blackbox
->getXDisplay(),
2057 frame
.plate
, frame
.uborder_pixel
);
2062 void BlackboxWindow::setFocusFlag(bool focus
) {
2063 // only focus a window if it is visible
2064 if (focus
&& !flags
.visible
)
2067 flags
.focused
= focus
;
2069 redrawWindowFrame();
2071 if (screen
->isSloppyFocus() && screen
->doAutoRaise()) {
2072 if (isFocused()) timer
->start();
2077 blackbox
->setFocusedWindow(this);
2079 if (! flags
.iconic
) {
2080 // iconic windows arent in a workspace menu!
2082 screen
->getCurrentWorkspace()->setFocused(this, isFocused());
2084 screen
->getWorkspace(blackbox_attrib
.workspace
)->
2085 setFocused(this, flags
.focused
);
2090 void BlackboxWindow::installColormap(bool install
) {
2091 int i
= 0, ncmap
= 0;
2092 Colormap
*cmaps
= XListInstalledColormaps(blackbox
->getXDisplay(),
2093 client
.window
, &ncmap
);
2095 XWindowAttributes wattrib
;
2096 if (XGetWindowAttributes(blackbox
->getXDisplay(),
2097 client
.window
, &wattrib
)) {
2099 // install the window's colormap
2100 for (i
= 0; i
< ncmap
; i
++) {
2101 if (*(cmaps
+ i
) == wattrib
.colormap
)
2102 // this window is using an installed color map... do not install
2105 // otherwise, install the window's colormap
2107 XInstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2109 // uninstall the window's colormap
2110 for (i
= 0; i
< ncmap
; i
++) {
2111 if (*(cmaps
+ i
) == wattrib
.colormap
)
2112 // we found the colormap to uninstall
2113 XUninstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2123 void BlackboxWindow::setAllowedActions(void) {
2127 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_shade
);
2128 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_change_desktop
);
2129 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_close
);
2131 if (functions
& Func_Move
)
2132 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_move
);
2133 if (functions
& Func_Resize
)
2134 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_resize
);
2135 if (functions
& Func_Maximize
) {
2136 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_horz
);
2137 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_vert
);
2140 xatom
->setValue(client
.window
, XAtom::net_wm_allowed_actions
, XAtom::atom
,
2145 void BlackboxWindow::setState(unsigned long new_state
) {
2146 current_state
= new_state
;
2148 unsigned long state
[2];
2149 state
[0] = current_state
;
2151 xatom
->setValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
, state
, 2);
2153 xatom
->setValue(client
.window
, XAtom::blackbox_attributes
,
2154 XAtom::blackbox_attributes
, (unsigned long *)&blackbox_attrib
,
2155 PropBlackboxAttributesElements
);
2160 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_modal
);
2162 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_shaded
);
2164 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_hidden
);
2165 if (flags
.skip_taskbar
)
2166 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
);
2167 if (flags
.skip_pager
)
2168 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_pager
);
2169 if (flags
.fullscreen
)
2170 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_fullscreen
);
2171 if (flags
.maximized
== 1 || flags
.maximized
== 2)
2172 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_vert
);
2173 if (flags
.maximized
== 1 || flags
.maximized
== 3)
2174 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_horz
);
2175 xatom
->setValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
2180 bool BlackboxWindow::getState(void) {
2181 bool ret
= xatom
->getValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
,
2183 if (! ret
) current_state
= 0;
2188 void BlackboxWindow::restoreAttributes(void) {
2189 unsigned long num
= PropBlackboxAttributesElements
;
2190 BlackboxAttributes
*net
;
2191 if (! xatom
->getValue(client
.window
, XAtom::blackbox_attributes
,
2192 XAtom::blackbox_attributes
, num
,
2193 (unsigned long **)&net
))
2195 if (num
< PropBlackboxAttributesElements
) {
2200 if (net
->flags
& AttribShaded
&& net
->attrib
& AttribShaded
) {
2201 flags
.shaded
= False
;
2202 unsigned long orig_state
= current_state
;
2206 At this point in the life of a window, current_state should only be set
2207 to IconicState if the window was an *icon*, not if it was shaded.
2209 if (orig_state
!= IconicState
)
2210 current_state
= WithdrawnState
;
2213 if (net
->workspace
!= screen
->getCurrentWorkspaceID() &&
2214 net
->workspace
< screen
->getWorkspaceCount())
2215 screen
->reassociateWindow(this, net
->workspace
, True
);
2217 if ((blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID()) &&
2218 (blackbox_attrib
.workspace
< screen
->getWorkspaceCount())) {
2219 // set to WithdrawnState so it will be mapped on the new workspace
2220 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2221 } else if (current_state
== WithdrawnState
) {
2222 // the window is on this workspace and is Withdrawn, so it is waiting to
2224 current_state
= NormalState
;
2227 if (net
->flags
& AttribOmnipresent
&& net
->attrib
& AttribOmnipresent
) {
2228 flags
.stuck
= False
;
2231 // if the window was on another workspace, it was going to be hidden. this
2232 // specifies that the window should be mapped since it is sticky.
2233 if (current_state
== WithdrawnState
) current_state
= NormalState
;
2236 if (net
->flags
& AttribMaxHoriz
|| net
->flags
& AttribMaxVert
) {
2237 int x
= net
->premax_x
, y
= net
->premax_y
;
2238 unsigned int w
= net
->premax_w
, h
= net
->premax_h
;
2239 flags
.maximized
= 0;
2242 if ((net
->flags
& AttribMaxHoriz
) &&
2243 (net
->flags
& AttribMaxVert
))
2244 m
= (net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
2245 else if (net
->flags
& AttribMaxVert
)
2246 m
= (net
->attrib
& AttribMaxVert
) ? 2 : 0;
2247 else if (net
->flags
& AttribMaxHoriz
)
2248 m
= (net
->attrib
& AttribMaxHoriz
) ? 3 : 0;
2252 blackbox_attrib
.premax_x
= x
;
2253 blackbox_attrib
.premax_y
= y
;
2254 blackbox_attrib
.premax_w
= w
;
2255 blackbox_attrib
.premax_h
= h
;
2258 if (net
->flags
& AttribDecoration
) {
2259 switch (net
->decoration
) {
2267 decorations
|= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
2268 Decor_Iconify
| Decor_Maximize
;
2273 decorations
|= Decor_Titlebar
| Decor_Iconify
;
2274 decorations
&= ~(Decor_Border
| Decor_Handle
| Decor_Maximize
);
2279 decorations
|= Decor_Titlebar
;
2280 decorations
&= ~(Decor_Iconify
| Decor_Border
| Decor_Handle
);
2285 // sanity check the new decor
2286 if (! (functions
& Func_Resize
) || isTransient())
2287 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2288 if (! (functions
& Func_Maximize
))
2289 decorations
&= ~Decor_Maximize
;
2291 if (decorations
& Decor_Titlebar
) {
2292 if (functions
& Func_Close
) // close button is controlled by function
2293 decorations
|= Decor_Close
; // not decor type
2295 if (flags
.shaded
) // we can not be shaded if we lack a titlebar
2299 if (flags
.visible
&& frame
.window
) {
2300 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
2301 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
2305 setState(current_state
);
2308 // with the state set it will then be the map event's job to read the
2309 // window's state and behave accordingly
2316 * Positions the Rect r according the the client window position and
2319 void BlackboxWindow::applyGravity(Rect
&r
) {
2320 // apply horizontal window gravity
2321 switch (client
.win_gravity
) {
2323 case NorthWestGravity
:
2324 case SouthWestGravity
:
2326 r
.setX(client
.rect
.x());
2332 r
.setX(client
.rect
.x() - (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2335 case NorthEastGravity
:
2336 case SouthEastGravity
:
2338 r
.setX(client
.rect
.x() - frame
.margin
.left
- frame
.margin
.right
+ 2);
2343 r
.setX(client
.rect
.x() - frame
.margin
.left
);
2347 // apply vertical window gravity
2348 switch (client
.win_gravity
) {
2350 case NorthWestGravity
:
2351 case NorthEastGravity
:
2353 r
.setY(client
.rect
.y());
2359 r
.setY(client
.rect
.y() - (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2362 case SouthWestGravity
:
2363 case SouthEastGravity
:
2365 r
.setY(client
.rect
.y() - frame
.margin
.top
- frame
.margin
.bottom
+ 2);
2370 r
.setY(client
.rect
.y() - frame
.margin
.top
);
2377 * The reverse of the applyGravity function.
2379 * Positions the Rect r according to the frame window position and
2382 void BlackboxWindow::restoreGravity(Rect
&r
) {
2383 // restore horizontal window gravity
2384 switch (client
.win_gravity
) {
2386 case NorthWestGravity
:
2387 case SouthWestGravity
:
2389 r
.setX(frame
.rect
.x());
2395 r
.setX(frame
.rect
.x() + (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2398 case NorthEastGravity
:
2399 case SouthEastGravity
:
2401 r
.setX(frame
.rect
.x() + frame
.margin
.left
+ frame
.margin
.right
- 2);
2406 r
.setX(frame
.rect
.x() + frame
.margin
.left
);
2410 // restore vertical window gravity
2411 switch (client
.win_gravity
) {
2413 case NorthWestGravity
:
2414 case NorthEastGravity
:
2416 r
.setY(frame
.rect
.y());
2422 r
.setY(frame
.rect
.y() + (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2425 case SouthWestGravity
:
2426 case SouthEastGravity
:
2428 r
.setY(frame
.rect
.y() + frame
.margin
.top
+ frame
.margin
.bottom
- 2);
2433 r
.setY(frame
.rect
.y() + frame
.margin
.top
);
2439 void BlackboxWindow::redrawLabel(void) const {
2440 if (flags
.focused
) {
2442 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2443 frame
.label
, frame
.flabel
);
2445 XSetWindowBackground(blackbox
->getXDisplay(),
2446 frame
.label
, frame
.flabel_pixel
);
2449 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2450 frame
.label
, frame
.ulabel
);
2452 XSetWindowBackground(blackbox
->getXDisplay(),
2453 frame
.label
, frame
.ulabel_pixel
);
2455 XClearWindow(blackbox
->getXDisplay(), frame
.label
);
2457 WindowStyle
*style
= screen
->getWindowStyle();
2459 int pos
= frame
.bevel_w
* 2;
2460 style
->doJustify(client
.title
.c_str(), pos
, frame
.label_w
, frame
.bevel_w
* 4);
2461 style
->font
->drawString(frame
.label
, pos
, 1,
2462 (flags
.focused
? style
->l_text_focus
:
2463 style
->l_text_unfocus
),
2468 void BlackboxWindow::redrawAllButtons(void) const {
2469 if (frame
.iconify_button
) redrawIconifyButton(False
);
2470 if (frame
.maximize_button
) redrawMaximizeButton(flags
.maximized
);
2471 if (frame
.close_button
) redrawCloseButton(False
);
2475 void BlackboxWindow::redrawIconifyButton(bool pressed
) const {
2477 if (flags
.focused
) {
2479 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2480 frame
.iconify_button
, frame
.fbutton
);
2482 XSetWindowBackground(blackbox
->getXDisplay(),
2483 frame
.iconify_button
, frame
.fbutton_pixel
);
2486 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2487 frame
.iconify_button
, frame
.ubutton
);
2489 XSetWindowBackground(blackbox
->getXDisplay(), frame
.iconify_button
,
2490 frame
.ubutton_pixel
);
2494 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2495 frame
.iconify_button
, frame
.pbutton
);
2497 XSetWindowBackground(blackbox
->getXDisplay(),
2498 frame
.iconify_button
, frame
.pbutton_pixel
);
2500 XClearWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
2502 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2503 screen
->getWindowStyle()->b_pic_unfocus
);
2504 XDrawRectangle(blackbox
->getXDisplay(), frame
.iconify_button
, pen
.gc(),
2505 2, (frame
.button_w
- 5), (frame
.button_w
- 5), 2);
2509 void BlackboxWindow::redrawMaximizeButton(bool pressed
) const {
2511 if (flags
.focused
) {
2513 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2514 frame
.maximize_button
, frame
.fbutton
);
2516 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2517 frame
.fbutton_pixel
);
2520 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2521 frame
.maximize_button
, frame
.ubutton
);
2523 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2524 frame
.ubutton_pixel
);
2528 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2529 frame
.maximize_button
, frame
.pbutton
);
2531 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2532 frame
.pbutton_pixel
);
2534 XClearWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
2536 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2537 screen
->getWindowStyle()->b_pic_unfocus
);
2538 XDrawRectangle(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2539 2, 2, (frame
.button_w
- 5), (frame
.button_w
- 5));
2540 XDrawLine(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2541 2, 3, (frame
.button_w
- 3), 3);
2545 void BlackboxWindow::redrawCloseButton(bool pressed
) const {
2547 if (flags
.focused
) {
2549 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2552 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2553 frame
.fbutton_pixel
);
2556 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2559 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2560 frame
.ubutton_pixel
);
2564 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2565 frame
.close_button
, frame
.pbutton
);
2567 XSetWindowBackground(blackbox
->getXDisplay(),
2568 frame
.close_button
, frame
.pbutton_pixel
);
2570 XClearWindow(blackbox
->getXDisplay(), frame
.close_button
);
2572 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2573 screen
->getWindowStyle()->b_pic_unfocus
);
2574 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2575 2, 2, (frame
.button_w
- 3), (frame
.button_w
- 3));
2576 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2577 2, (frame
.button_w
- 3), (frame
.button_w
- 3), 2);
2581 void BlackboxWindow::mapRequestEvent(const XMapRequestEvent
*re
) {
2582 if (re
->window
!= client
.window
)
2586 fprintf(stderr
, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2590 switch (current_state
) {
2595 case WithdrawnState
:
2604 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2606 if (! blackbox
->isStartup()) {
2607 XSync(blackbox
->getXDisplay(), False
); // make sure the frame is mapped
2608 if (screen
->doFocusNew()|| (isTransient() && getTransientFor() &&
2609 getTransientFor()->isFocused())) {
2612 if (screen
->getPlacementPolicy() == BScreen::ClickMousePlacement
) {
2616 XQueryPointer(blackbox
->getXDisplay(), screen
->getRootWindow(),
2617 &r
, &c
, &rx
, &ry
, &x
, &y
, &m
);
2627 void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent
*ue
) {
2628 if (ue
->window
!= client
.window
)
2632 fprintf(stderr
, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2636 screen
->unmanageWindow(this, False
);
2640 void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent
*de
) {
2641 if (de
->window
!= client
.window
)
2645 fprintf(stderr
, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2649 screen
->unmanageWindow(this, False
);
2653 void BlackboxWindow::reparentNotifyEvent(const XReparentEvent
*re
) {
2654 if (re
->window
!= client
.window
|| re
->parent
== frame
.plate
)
2658 fprintf(stderr
, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2659 "0x%lx.\n", client
.window
, re
->parent
);
2664 XPutBackEvent(blackbox
->getXDisplay(), &ev
);
2665 screen
->unmanageWindow(this, True
);
2669 void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent
*pe
) {
2670 if (pe
->state
== PropertyDelete
)
2674 fprintf(stderr
, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n",
2680 case XA_WM_CLIENT_MACHINE
:
2684 case XA_WM_TRANSIENT_FOR
: {
2685 // determine if this is a transient window
2688 // adjust the window decorations based on transience
2689 if (isTransient()) {
2690 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2691 functions
&= ~Func_Maximize
;
2692 setAllowedActions();
2703 case XA_WM_ICON_NAME
:
2705 if (flags
.iconic
) screen
->propagateWindowName(this);
2708 case XAtom::net_wm_name
:
2712 if (decorations
& Decor_Titlebar
)
2715 screen
->propagateWindowName(this);
2718 case XA_WM_NORMAL_HINTS
: {
2721 if ((client
.normal_hint_flags
& PMinSize
) &&
2722 (client
.normal_hint_flags
& PMaxSize
)) {
2723 // the window now can/can't resize itself, so the buttons need to be
2726 if (client
.max_width
<= client
.min_width
&&
2727 client
.max_height
<= client
.min_height
) {
2728 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2729 functions
&= ~(Func_Resize
| Func_Maximize
);
2731 if (! isTransient()) {
2732 decorations
|= Decor_Maximize
| Decor_Handle
;
2733 functions
|= Func_Maximize
;
2735 functions
|= Func_Resize
;
2738 setAllowedActions();
2741 Rect old_rect
= frame
.rect
;
2745 if (old_rect
!= frame
.rect
)
2752 if (pe
->atom
== xatom
->getAtom(XAtom::wm_protocols
)) {
2755 if ((decorations
& Decor_Close
) && (! frame
.close_button
)) {
2756 createCloseButton();
2757 if (decorations
& Decor_Titlebar
) {
2758 positionButtons(True
);
2759 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
2761 if (windowmenu
) windowmenu
->reconfigure();
2763 } else if (pe
->atom
== xatom
->getAtom(XAtom::net_wm_strut
)) {
2772 void BlackboxWindow::exposeEvent(const XExposeEvent
*ee
) {
2774 fprintf(stderr
, "BlackboxWindow::exposeEvent() for 0x%lx\n", client
.window
);
2777 if (frame
.label
== ee
->window
&& (decorations
& Decor_Titlebar
))
2779 else if (frame
.close_button
== ee
->window
)
2780 redrawCloseButton(False
);
2781 else if (frame
.maximize_button
== ee
->window
)
2782 redrawMaximizeButton(flags
.maximized
);
2783 else if (frame
.iconify_button
== ee
->window
)
2784 redrawIconifyButton(False
);
2788 void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent
*cr
) {
2789 if (cr
->window
!= client
.window
|| flags
.iconic
)
2792 if (cr
->value_mask
& CWBorderWidth
)
2793 client
.old_bw
= cr
->border_width
;
2795 if (cr
->value_mask
& (CWX
| CWY
| CWWidth
| CWHeight
)) {
2796 Rect req
= frame
.rect
;
2798 if (cr
->value_mask
& (CWX
| CWY
)) {
2799 if (cr
->value_mask
& CWX
)
2800 client
.rect
.setX(cr
->x
);
2801 if (cr
->value_mask
& CWY
)
2802 client
.rect
.setY(cr
->y
);
2807 if (cr
->value_mask
& CWWidth
)
2808 req
.setWidth(cr
->width
+ frame
.margin
.left
+ frame
.margin
.right
);
2810 if (cr
->value_mask
& CWHeight
)
2811 req
.setHeight(cr
->height
+ frame
.margin
.top
+ frame
.margin
.bottom
);
2813 configure(req
.x(), req
.y(), req
.width(), req
.height());
2816 if (cr
->value_mask
& CWStackMode
&& !isDesktop()) {
2817 switch (cr
->detail
) {
2820 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2826 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2833 void BlackboxWindow::buttonPressEvent(const XButtonEvent
*be
) {
2835 fprintf(stderr
, "BlackboxWindow::buttonPressEvent() for 0x%lx\n",
2839 if (frame
.maximize_button
== be
->window
&& be
->button
<= 3) {
2840 redrawMaximizeButton(True
);
2841 } else if (be
->button
== 1 || (be
->button
== 3 && be
->state
== ModMask
)) {
2842 if (! flags
.focused
)
2845 if (frame
.iconify_button
== be
->window
) {
2846 redrawIconifyButton(True
);
2847 } else if (frame
.close_button
== be
->window
) {
2848 redrawCloseButton(True
);
2849 } else if (frame
.plate
== be
->window
) {
2850 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2852 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2854 XAllowEvents(blackbox
->getXDisplay(), ReplayPointer
, be
->time
);
2856 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
2857 if (((be
->time
- lastButtonPressTime
) <=
2858 blackbox
->getDoubleClickInterval()) ||
2859 (be
->state
== ControlMask
)) {
2860 lastButtonPressTime
= 0;
2863 lastButtonPressTime
= be
->time
;
2867 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2869 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2871 } else if (be
->button
== 2 && (be
->window
!= frame
.iconify_button
) &&
2872 (be
->window
!= frame
.close_button
)) {
2873 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2874 } else if (windowmenu
&& be
->button
== 3 &&
2875 (frame
.title
== be
->window
|| frame
.label
== be
->window
||
2876 frame
.handle
== be
->window
|| frame
.window
== be
->window
)) {
2877 if (windowmenu
->isVisible()) {
2880 int mx
= be
->x_root
- windowmenu
->getWidth() / 2,
2881 my
= be
->y_root
- windowmenu
->getHeight() / 2;
2883 // snap the window menu into a corner/side if necessary
2884 int left_edge
, right_edge
, top_edge
, bottom_edge
;
2887 the " + (frame.border_w * 2) - 1" bits are to get the proper width
2888 and height of the menu, as the sizes returned by it do not include
2891 left_edge
= frame
.rect
.x();
2892 right_edge
= frame
.rect
.right() -
2893 (windowmenu
->getWidth() + (frame
.border_w
* 2) - 1);
2894 top_edge
= client
.rect
.top() - (frame
.border_w
+ frame
.mwm_border_w
);
2895 bottom_edge
= client
.rect
.bottom() -
2896 (windowmenu
->getHeight() + (frame
.border_w
* 2) - 1) +
2897 (frame
.border_w
+ frame
.mwm_border_w
);
2901 if (mx
> right_edge
)
2905 if (my
> bottom_edge
)
2908 windowmenu
->move(mx
, my
);
2910 XRaiseWindow(blackbox
->getXDisplay(), windowmenu
->getWindowID());
2911 XRaiseWindow(blackbox
->getXDisplay(),
2912 windowmenu
->getSendToMenu()->getWindowID());
2915 } else if (be
->button
== 4) {
2916 if ((be
->window
== frame
.label
||
2917 be
->window
== frame
.title
||
2918 be
->window
== frame
.maximize_button
||
2919 be
->window
== frame
.iconify_button
||
2920 be
->window
== frame
.close_button
) &&
2924 } else if (be
->button
== 5) {
2925 if ((be
->window
== frame
.label
||
2926 be
->window
== frame
.title
||
2927 be
->window
== frame
.maximize_button
||
2928 be
->window
== frame
.iconify_button
||
2929 be
->window
== frame
.close_button
) &&
2936 void BlackboxWindow::buttonReleaseEvent(const XButtonEvent
*re
) {
2938 fprintf(stderr
, "BlackboxWindow::buttonReleaseEvent() for 0x%lx\n",
2942 if (re
->window
== frame
.maximize_button
&&
2943 re
->button
>= 1 && re
->button
<= 3) {
2944 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2945 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2946 maximize(re
->button
);
2948 redrawMaximizeButton(flags
.maximized
);
2950 } else if (re
->window
== frame
.iconify_button
&& re
->button
== 1) {
2951 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2952 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2955 redrawIconifyButton(False
);
2957 } else if (re
->window
== frame
.close_button
& re
->button
== 1) {
2958 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2959 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
)))
2961 redrawCloseButton(False
);
2962 } else if (flags
.moving
) {
2964 } else if (flags
.resizing
) {
2966 } else if (re
->window
== frame
.window
) {
2967 if (re
->button
== 2 && re
->state
== ModMask
)
2968 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
2974 void BlackboxWindow::beginMove(int x_root
, int y_root
) {
2975 assert(! (flags
.resizing
|| flags
.moving
));
2978 Only one window can be moved/resized at a time. If another window is already
2979 being moved or resized, then stop it before whating to work with this one.
2981 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
2982 if (changing
&& changing
!= this) {
2983 if (changing
->flags
.moving
)
2984 changing
->endMove();
2985 else // if (changing->flags.resizing)
2986 changing
->endResize();
2989 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
2990 PointerMotionMask
| ButtonReleaseMask
,
2991 GrabModeAsync
, GrabModeAsync
,
2992 None
, blackbox
->getMoveCursor(), CurrentTime
);
2994 if (windowmenu
&& windowmenu
->isVisible())
2997 flags
.moving
= True
;
2998 blackbox
->setChangingWindow(this);
3000 if (! screen
->doOpaqueMove()) {
3001 XGrabServer(blackbox
->getXDisplay());
3003 frame
.changing
= frame
.rect
;
3004 screen
->showPosition(frame
.changing
.x(), frame
.changing
.y());
3006 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3010 frame
.changing
.width() - 1,
3011 frame
.changing
.height() - 1);
3014 frame
.grab_x
= x_root
- frame
.rect
.x() - frame
.border_w
;
3015 frame
.grab_y
= y_root
- frame
.rect
.y() - frame
.border_w
;
3019 void BlackboxWindow::doMove(int x_root
, int y_root
) {
3020 assert(flags
.moving
);
3021 assert(blackbox
->getChangingWindow() == this);
3023 int dx
= x_root
- frame
.grab_x
, dy
= y_root
- frame
.grab_y
;
3024 dx
-= frame
.border_w
;
3025 dy
-= frame
.border_w
;
3027 if (screen
->doWorkspaceWarping()) {
3028 // workspace warping
3030 unsigned int dest
= screen
->getCurrentWorkspaceID();
3034 if (dest
> 0) dest
--;
3035 else dest
= screen
->getNumberOfWorkspaces() - 1;
3037 } else if (x_root
>= screen
->getRect().right()) {
3040 if (dest
< screen
->getNumberOfWorkspaces() - 1) dest
++;
3045 bool focus
= flags
.focused
; // had focus while moving?
3047 screen
->reassociateWindow(this, dest
, False
);
3048 screen
->changeWorkspaceID(dest
);
3053 If the XWarpPointer is done after the configure, we can end up
3054 grabbing another window, so made sure you do it first.
3058 dest_x
= screen
->getRect().right() - 1;
3059 XWarpPointer(blackbox
->getXDisplay(), None
,
3060 screen
->getRootWindow(), 0, 0, 0, 0,
3063 configure(dx
+ (screen
->getRect().width() - 1), dy
,
3064 frame
.rect
.width(), frame
.rect
.height());
3067 XWarpPointer(blackbox
->getXDisplay(), None
,
3068 screen
->getRootWindow(), 0, 0, 0, 0,
3071 configure(dx
- (screen
->getRect().width() - 1), dy
,
3072 frame
.rect
.width(), frame
.rect
.height());
3075 beginMove(dest_x
, y_root
);
3080 const int snap_distance
= screen
->getEdgeSnapThreshold();
3082 if (snap_distance
) {
3084 const int wleft
= dx
,
3085 wright
= dx
+ frame
.rect
.width() - 1,
3087 wbottom
= dy
+ frame
.rect
.height() - 1;
3089 if (screen
->getWindowToWindowSnap()) {
3090 Workspace
*w
= screen
->getWorkspace(getWorkspaceNumber());
3093 RectList winsnaplist
;
3095 // try snap to another window
3097 // add windows on the workspace to the snap list
3098 const BlackboxWindowList
& stack_list
= w
->getStackingList();
3099 BlackboxWindowList::const_iterator st_it
, st_end
= stack_list
.end();
3100 for (st_it
= stack_list
.begin(); st_it
!= st_end
; ++st_it
)
3101 winsnaplist
.push_back( (*st_it
)->frameRect() );
3103 // add the toolbar and the slit to the snap list.
3104 // (only if they are not hidden)
3105 Toolbar
*tbar
= screen
->getToolbar();
3106 Slit
*slit
= screen
->getSlit();
3107 Rect tbar_rect
, slit_rect
;
3108 unsigned int bwidth
= screen
->getBorderWidth() * 2;
3110 if (! (screen
->doHideToolbar() || tbar
->isHidden())) {
3111 tbar_rect
.setRect(tbar
->getX(), tbar
->getY(), tbar
->getWidth() + bwidth
,
3112 tbar
->getHeight() + bwidth
);
3113 winsnaplist
.push_back(tbar_rect
);
3116 if (! slit
->isHidden()) {
3117 slit_rect
.setRect(slit
->getX(), slit
->getY(), slit
->getWidth() + bwidth
,
3118 slit
->getHeight() + bwidth
);
3119 winsnaplist
.push_back(slit_rect
);
3122 RectList::const_iterator it
, end
= winsnaplist
.end();
3123 for (it
= winsnaplist
.begin(); it
!= end
; ++it
) {
3124 bool snapped
= False
;
3126 const Rect
&winrect
= *it
;
3127 int dleft
= abs(wright
- winrect
.left()),
3128 dright
= abs(wleft
- winrect
.right()),
3129 dtop
= abs(wbottom
- winrect
.top()),
3130 dbottom
= abs(wtop
- winrect
.bottom());
3132 if (wtop
>= (signed)(winrect
.y() - frame
.rect
.height() + 1) &&
3133 wtop
< (signed)(winrect
.y() + winrect
.height() - 1)) {
3135 // snap left of other window?
3136 if (dleft
< snap_distance
&& dleft
<= dright
) {
3137 dx
= winrect
.left() - frame
.rect
.width();
3140 // snap right of other window?
3141 else if (dright
< snap_distance
) {
3142 dx
= winrect
.right() + 1;
3147 if (screen
->getWindowCornerSnap()) {
3148 // try corner-snap to its other sides
3149 dtop
= abs(wtop
- winrect
.top());
3150 dbottom
= abs(wbottom
- winrect
.bottom());
3151 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3153 else if (dbottom
< snap_distance
)
3154 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
3161 if (wleft
>= (signed)(winrect
.x() - frame
.rect
.width() + 1) &&
3162 wleft
< (signed)(winrect
.x() + winrect
.width() - 1)) {
3164 // snap top of other window?
3165 if (dtop
< snap_distance
&& dtop
<= dbottom
) {
3166 dy
= winrect
.top() - frame
.rect
.height();
3169 // snap bottom of other window?
3170 else if (dbottom
< snap_distance
) {
3171 dy
= winrect
.bottom() + 1;
3176 if (screen
->getWindowCornerSnap()) {
3177 // try corner-snap to its other sides
3178 dleft
= abs(wleft
- winrect
.left());
3179 dright
= abs(wright
- winrect
.right());
3180 if (dleft
< snap_distance
&& dleft
<= dright
)
3181 dx
= winrect
.left();
3182 else if (dright
< snap_distance
)
3183 dx
= winrect
.right() - frame
.rect
.width() + 1;
3192 RectList snaplist
; // the list of rects we will try to snap to
3194 // snap to the screen edges (and screen boundaries for xinerama)
3196 if (screen
->isXineramaActive() && blackbox
->doXineramaSnapping()) {
3197 snaplist
.insert(snaplist
.begin(),
3198 screen
->getXineramaAreas().begin(),
3199 screen
->getXineramaAreas().end());
3202 snaplist
.push_back(screen
->getRect());
3204 RectList::const_iterator it
, end
= snaplist
.end();
3205 for (it
= snaplist
.begin(); it
!= end
; ++it
) {
3206 const Rect
&srect
= *it
;
3208 // if we're not in the rectangle then don't snap to it.
3209 if (! srect
.intersects(Rect(wleft
, wtop
, frame
.rect
.width(),
3210 frame
.rect
.height())))
3213 int dleft
= abs(wleft
- srect
.left()),
3214 dright
= abs(wright
- srect
.right()),
3215 dtop
= abs(wtop
- srect
.top()),
3216 dbottom
= abs(wbottom
- srect
.bottom());
3219 if (dleft
< snap_distance
&& dleft
<= dright
)
3222 else if (dright
< snap_distance
)
3223 dx
= srect
.right() - frame
.rect
.width() + 1;
3226 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3229 else if (dbottom
< snap_distance
)
3230 dy
= srect
.bottom() - frame
.rect
.height() + 1;
3234 if (screen
->doOpaqueMove()) {
3235 configure(dx
, dy
, frame
.rect
.width(), frame
.rect
.height());
3237 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3241 frame
.changing
.width() - 1,
3242 frame
.changing
.height() - 1);
3244 frame
.changing
.setPos(dx
, dy
);
3246 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3250 frame
.changing
.width() - 1,
3251 frame
.changing
.height() - 1);
3254 screen
->showPosition(dx
, dy
);
3258 void BlackboxWindow::endMove(void) {
3259 assert(flags
.moving
);
3260 assert(blackbox
->getChangingWindow() == this);
3262 flags
.moving
= False
;
3263 blackbox
->setChangingWindow(0);
3265 if (! screen
->doOpaqueMove()) {
3266 /* when drawing the rubber band, we need to make sure we only draw inside
3267 * the frame... frame.changing_* contain the new coords for the window,
3268 * so we need to subtract 1 from changing_w/changing_h every where we
3269 * draw the rubber band (for both moving and resizing)
3271 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3272 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3273 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3274 XUngrabServer(blackbox
->getXDisplay());
3276 configure(frame
.changing
.x(), frame
.changing
.y(),
3277 frame
.changing
.width(), frame
.changing
.height());
3279 configure(frame
.rect
.x(), frame
.rect
.y(),
3280 frame
.rect
.width(), frame
.rect
.height());
3282 screen
->hideGeometry();
3284 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3286 // if there are any left over motions from the move, drop them now
3287 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3289 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3294 void BlackboxWindow::beginResize(int x_root
, int y_root
, Corner dir
) {
3295 assert(! (flags
.resizing
|| flags
.moving
));
3298 Only one window can be moved/resized at a time. If another window is already
3299 being moved or resized, then stop it before whating to work with this one.
3301 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3302 if (changing
&& changing
!= this) {
3303 if (changing
->flags
.moving
)
3304 changing
->endMove();
3305 else // if (changing->flags.resizing)
3306 changing
->endResize();
3314 switch (resize_dir
) {
3317 cursor
= blackbox
->getLowerLeftAngleCursor();
3322 cursor
= blackbox
->getLowerRightAngleCursor();
3326 anchor
= BottomRight
;
3327 cursor
= blackbox
->getUpperLeftAngleCursor();
3331 anchor
= BottomLeft
;
3332 cursor
= blackbox
->getUpperRightAngleCursor();
3336 assert(false); // unhandled Corner
3337 return; // unreachable, for the compiler
3340 XGrabServer(blackbox
->getXDisplay());
3341 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3342 PointerMotionMask
| ButtonReleaseMask
,
3343 GrabModeAsync
, GrabModeAsync
, None
, cursor
, CurrentTime
);
3345 flags
.resizing
= True
;
3346 blackbox
->setChangingWindow(this);
3349 frame
.changing
= frame
.rect
;
3351 constrain(anchor
, &gw
, &gh
);
3353 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3354 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3355 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3357 screen
->showGeometry(gw
, gh
);
3359 frame
.grab_x
= x_root
;
3360 frame
.grab_y
= y_root
;
3364 void BlackboxWindow::doResize(int x_root
, int y_root
) {
3365 assert(flags
.resizing
);
3366 assert(blackbox
->getChangingWindow() == this);
3368 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3369 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3370 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3375 switch (resize_dir
) {
3378 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3379 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3383 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3384 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3387 anchor
= BottomRight
;
3388 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3389 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3392 anchor
= BottomLeft
;
3393 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3394 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3398 assert(false); // unhandled Corner
3399 return; // unreachable, for the compiler
3402 constrain(anchor
, &gw
, &gh
);
3404 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3405 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3406 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3408 screen
->showGeometry(gw
, gh
);
3412 void BlackboxWindow::endResize(void) {
3413 assert(flags
.resizing
);
3414 assert(blackbox
->getChangingWindow() == this);
3416 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3417 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3418 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3419 XUngrabServer(blackbox
->getXDisplay());
3421 // unset maximized state after resized when fully maximized
3422 if (flags
.maximized
== 1)
3425 flags
.resizing
= False
;
3426 blackbox
->setChangingWindow(0);
3428 configure(frame
.changing
.x(), frame
.changing
.y(),
3429 frame
.changing
.width(), frame
.changing
.height());
3430 screen
->hideGeometry();
3432 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3434 // if there are any left over motions from the resize, drop them now
3435 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3437 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3442 void BlackboxWindow::motionNotifyEvent(const XMotionEvent
*me
) {
3444 fprintf(stderr
, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n",
3449 doMove(me
->x_root
, me
->y_root
);
3450 } else if (flags
.resizing
) {
3451 doResize(me
->x_root
, me
->y_root
);
3453 if (!flags
.resizing
&& me
->state
& Button1Mask
&& (functions
& Func_Move
) &&
3454 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3455 frame
.handle
== me
->window
|| frame
.window
== me
->window
)) {
3456 beginMove(me
->x_root
, me
->y_root
);
3457 } else if ((functions
& Func_Resize
) &&
3458 (me
->state
& Button1Mask
&& (me
->window
== frame
.right_grip
||
3459 me
->window
== frame
.left_grip
)) ||
3460 (me
->state
& Button3Mask
&& me
->state
& ModMask
&&
3461 me
->window
== frame
.window
)) {
3462 unsigned int zones
= screen
->getResizeZones();
3465 if (me
->window
== frame
.left_grip
) {
3466 corner
= BottomLeft
;
3467 } else if (me
->window
== frame
.right_grip
|| zones
== 1) {
3468 corner
= BottomRight
;
3471 bool left
= (me
->x_root
- frame
.rect
.x() <=
3472 static_cast<signed>(frame
.rect
.width() / 2));
3475 else // (zones == 4)
3476 top
= (me
->y_root
- frame
.rect
.y() <=
3477 static_cast<signed>(frame
.rect
.height() / 2));
3478 corner
= (top
? (left
? TopLeft
: TopRight
) :
3479 (left
? BottomLeft
: BottomRight
));
3482 beginResize(me
->x_root
, me
->y_root
, corner
);
3489 void BlackboxWindow::shapeEvent(XShapeEvent
*) {
3490 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
3497 bool BlackboxWindow::validateClient(void) const {
3498 XSync(blackbox
->getXDisplay(), False
);
3501 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3502 DestroyNotify
, &e
) ||
3503 XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3505 XPutBackEvent(blackbox
->getXDisplay(), &e
);
3514 void BlackboxWindow::restore(bool remap
) {
3515 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeDelete
);
3516 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
3517 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, NoEventMask
);
3519 // do not leave a shaded window as an icon unless it was an icon
3520 if (flags
.shaded
&& ! flags
.iconic
)
3521 setState(NormalState
);
3523 restoreGravity(client
.rect
);
3525 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
3526 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
3528 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, client
.old_bw
);
3531 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3532 ReparentNotify
, &ev
)) {
3535 // according to the ICCCM - if the client doesn't reparent to
3536 // root, then we have to do it for them
3537 XReparentWindow(blackbox
->getXDisplay(), client
.window
,
3538 screen
->getRootWindow(),
3539 client
.rect
.x(), client
.rect
.y());
3542 if (remap
) XMapWindow(blackbox
->getXDisplay(), client
.window
);
3546 // timer for autoraise
3547 void BlackboxWindow::timeout(void) {
3548 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3552 void BlackboxWindow::changeBlackboxHints(const BlackboxHints
*net
) {
3553 if ((net
->flags
& AttribShaded
) &&
3554 ((blackbox_attrib
.attrib
& AttribShaded
) !=
3555 (net
->attrib
& AttribShaded
)))
3558 if (flags
.visible
&& // watch out for requests when we can not be seen
3559 (net
->flags
& (AttribMaxVert
| AttribMaxHoriz
)) &&
3560 ((blackbox_attrib
.attrib
& (AttribMaxVert
| AttribMaxHoriz
)) !=
3561 (net
->attrib
& (AttribMaxVert
| AttribMaxHoriz
)))) {
3562 if (flags
.maximized
) {
3567 if ((net
->flags
& AttribMaxHoriz
) && (net
->flags
& AttribMaxVert
))
3568 button
= ((net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0);
3569 else if (net
->flags
& AttribMaxVert
)
3570 button
= ((net
->attrib
& AttribMaxVert
) ? 2 : 0);
3571 else if (net
->flags
& AttribMaxHoriz
)
3572 button
= ((net
->attrib
& AttribMaxHoriz
) ? 3 : 0);
3578 if ((net
->flags
& AttribOmnipresent
) &&
3579 ((blackbox_attrib
.attrib
& AttribOmnipresent
) !=
3580 (net
->attrib
& AttribOmnipresent
)))
3583 if ((net
->flags
& AttribWorkspace
) &&
3584 (blackbox_attrib
.workspace
!= net
->workspace
)) {
3585 screen
->reassociateWindow(this, net
->workspace
, True
);
3587 if (screen
->getCurrentWorkspaceID() != net
->workspace
) {
3591 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3595 if (net
->flags
& AttribDecoration
) {
3596 switch (net
->decoration
) {
3604 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Iconify
;
3606 decorations
= ((functions
& Func_Resize
) && !isTransient() ?
3607 decorations
| Decor_Handle
:
3608 decorations
&= ~Decor_Handle
);
3609 decorations
= (functions
& Func_Maximize
?
3610 decorations
| Decor_Maximize
:
3611 decorations
&= ~Decor_Maximize
);
3616 decorations
|= Decor_Titlebar
| Decor_Iconify
;
3617 decorations
&= ~(Decor_Border
| Decor_Handle
);
3619 decorations
= (functions
& Func_Maximize
?
3620 decorations
| Decor_Maximize
:
3621 decorations
&= ~Decor_Maximize
);
3626 decorations
|= Decor_Titlebar
;
3627 decorations
&= ~(Decor_Iconify
| Decor_Border
);
3629 decorations
= ((functions
& Func_Resize
) && !isTransient() ?
3630 decorations
| Decor_Handle
:
3631 decorations
&= ~Decor_Handle
);
3632 decorations
= (functions
& Func_Maximize
?
3633 decorations
| Decor_Maximize
:
3634 decorations
&= ~Decor_Maximize
);
3639 // we can not be shaded if we lack a titlebar
3640 if (flags
.shaded
&& ! (decorations
& Decor_Titlebar
))
3643 if (flags
.visible
&& frame
.window
) {
3644 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
3645 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
3649 setState(current_state
);
3655 * Set the sizes of all components of the window frame
3656 * (the window decorations).
3657 * These values are based upon the current style settings and the client
3658 * window's dimensions.
3660 void BlackboxWindow::upsize(void) {
3661 frame
.bevel_w
= screen
->getBevelWidth();
3663 if (decorations
& Decor_Border
) {
3664 frame
.border_w
= screen
->getBorderWidth();
3665 if (! isTransient())
3666 frame
.mwm_border_w
= screen
->getFrameWidth();
3668 frame
.mwm_border_w
= 0;
3670 frame
.mwm_border_w
= frame
.border_w
= 0;
3673 if (decorations
& Decor_Titlebar
) {
3674 // the height of the titlebar is based upon the height of the font being
3675 // used to display the window's title
3676 WindowStyle
*style
= screen
->getWindowStyle();
3677 frame
.title_h
= style
->font
->height() + (frame
.bevel_w
* 2) + 2;
3679 frame
.label_h
= frame
.title_h
- (frame
.bevel_w
* 2);
3680 frame
.button_w
= (frame
.label_h
- 2);
3682 // set the top frame margin
3683 frame
.margin
.top
= frame
.border_w
+ frame
.title_h
+
3684 frame
.border_w
+ frame
.mwm_border_w
;
3690 // set the top frame margin
3691 frame
.margin
.top
= frame
.border_w
+ frame
.mwm_border_w
;
3694 // set the left/right frame margin
3695 frame
.margin
.left
= frame
.margin
.right
= frame
.border_w
+ frame
.mwm_border_w
;
3697 if (decorations
& Decor_Handle
) {
3698 frame
.grip_w
= frame
.button_w
* 2;
3699 frame
.handle_h
= screen
->getHandleWidth();
3701 // set the bottom frame margin
3702 frame
.margin
.bottom
= frame
.border_w
+ frame
.handle_h
+
3703 frame
.border_w
+ frame
.mwm_border_w
;
3708 // set the bottom frame margin
3709 frame
.margin
.bottom
= frame
.border_w
+ frame
.mwm_border_w
;
3713 We first get the normal dimensions and use this to define the inside_w/h
3714 then we modify the height if shading is in effect.
3715 If the shade state is not considered then frame.rect gets reset to the
3716 normal window size on a reconfigure() call resulting in improper
3717 dimensions appearing in move/resize and other events.
3720 height
= client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
,
3721 width
= client
.rect
.width() + frame
.margin
.left
+ frame
.margin
.right
;
3723 frame
.inside_w
= width
- (frame
.border_w
* 2);
3724 frame
.inside_h
= height
- (frame
.border_w
* 2);
3727 height
= frame
.title_h
+ (frame
.border_w
* 2);
3728 frame
.rect
.setSize(width
, height
);
3733 * Calculate the size of the client window and constrain it to the
3734 * size specified by the size hints of the client window.
3736 * The logical width and height are placed into pw and ph, if they
3737 * are non-zero. Logical size refers to the users perception of
3738 * the window size (for example an xterm resizes in cells, not in pixels).
3740 * The physical geometry is placed into frame.changing_{x,y,width,height}.
3741 * Physical geometry refers to the geometry of the window in pixels.
3743 void BlackboxWindow::constrain(Corner anchor
, int *pw
, int *ph
) {
3744 // frame.changing represents the requested frame size, we need to
3745 // strip the frame margin off and constrain the client size
3746 frame
.changing
.setCoords(frame
.changing
.left() + frame
.margin
.left
,
3747 frame
.changing
.top() + frame
.margin
.top
,
3748 frame
.changing
.right() - frame
.margin
.right
,
3749 frame
.changing
.bottom() - frame
.margin
.bottom
);
3751 int dw
= frame
.changing
.width(), dh
= frame
.changing
.height(),
3752 base_width
= (client
.base_width
) ? client
.base_width
: client
.min_width
,
3753 base_height
= (client
.base_height
) ? client
.base_height
:
3757 if (dw
< static_cast<signed>(client
.min_width
)) dw
= client
.min_width
;
3758 if (dh
< static_cast<signed>(client
.min_height
)) dh
= client
.min_height
;
3759 if (dw
> static_cast<signed>(client
.max_width
)) dw
= client
.max_width
;
3760 if (dh
> static_cast<signed>(client
.max_height
)) dh
= client
.max_height
;
3763 dw
/= client
.width_inc
;
3765 dh
/= client
.height_inc
;
3768 if (client
.width_inc
== 1)
3769 *pw
= dw
+ base_width
;
3774 if (client
.height_inc
== 1)
3775 *ph
= dh
+ base_height
;
3780 dw
*= client
.width_inc
;
3782 dh
*= client
.height_inc
;
3785 frame
.changing
.setSize(dw
, dh
);
3787 // add the frame margin back onto frame.changing
3788 frame
.changing
.setCoords(frame
.changing
.left() - frame
.margin
.left
,
3789 frame
.changing
.top() - frame
.margin
.top
,
3790 frame
.changing
.right() + frame
.margin
.right
,
3791 frame
.changing
.bottom() + frame
.margin
.bottom
);
3793 // move frame.changing to the specified anchor
3801 dx
= frame
.rect
.right() - frame
.changing
.right();
3805 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3809 dx
= frame
.rect
.right() - frame
.changing
.right();
3810 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3814 assert(false); // unhandled corner
3816 frame
.changing
.setPos(frame
.changing
.x() + dx
, frame
.changing
.y() + dy
);
3820 void WindowStyle::doJustify(const std::string
&text
, int &start_pos
,
3821 unsigned int max_length
,
3822 unsigned int modifier
) const {
3823 size_t text_len
= text
.size();
3824 unsigned int length
;
3827 length
= font
->measureString(string(text
, 0, text_len
)) + modifier
;
3828 } while (length
> max_length
&& text_len
-- > 0);
3832 start_pos
+= max_length
- length
;
3836 start_pos
+= (max_length
- length
) / 2;
3846 BWindowGroup::BWindowGroup(Blackbox
*b
, Window _group
)
3847 : blackbox(b
), group(_group
) {
3848 XWindowAttributes wattrib
;
3849 if (! XGetWindowAttributes(blackbox
->getXDisplay(), group
, &wattrib
)) {
3850 // group window doesn't seem to exist anymore
3855 XSelectInput(blackbox
->getXDisplay(), group
,
3856 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
3858 blackbox
->saveGroupSearch(group
, this);
3862 BWindowGroup::~BWindowGroup(void) {
3863 blackbox
->removeGroupSearch(group
);
3868 BWindowGroup::find(BScreen
*screen
, bool allow_transients
) const {
3869 BlackboxWindow
*ret
= blackbox
->getFocusedWindow();
3871 // does the focus window match (or any transient_fors)?
3873 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3874 if (ret
->isTransient() && allow_transients
) break;
3875 else if (! ret
->isTransient()) break;
3878 ret
= ret
->getTransientFor();
3881 if (ret
) return ret
;
3883 // the focus window didn't match, look in the group's window list
3884 BlackboxWindowList::const_iterator it
, end
= windowList
.end();
3885 for (it
= windowList
.begin(); it
!= end
; ++it
) {
3887 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3888 if (ret
->isTransient() && allow_transients
) break;
3889 else if (! ret
->isTransient()) break;