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"
64 // change this to change what modifier keys openbox uses for mouse bindings
65 // for example: Mod1Mask | ControlMask
66 // or: ControlMask| ShiftMask
67 const unsigned int ModMask
= Mod1Mask
;
70 * Initializes the class with default values/the window's set initial values.
72 BlackboxWindow::BlackboxWindow(Blackbox
*b
, Window w
, BScreen
*s
) {
73 // fprintf(stderr, "BlackboxWindow size: %d bytes\n",
74 // sizeof(BlackboxWindow));
77 fprintf(stderr
, "BlackboxWindow::BlackboxWindow(): creating 0x%lx\n", w
);
81 set timer to zero... it is initialized properly later, so we check
82 if timer is zero in the destructor, and assume that the window is not
83 fully constructed if timer is zero...
89 xatom
= blackbox
->getXAtom();
91 if (! validateClient()) {
96 // fetch client size and placement
97 XWindowAttributes wattrib
;
98 if (! XGetWindowAttributes(blackbox
->getXDisplay(),
99 client
.window
, &wattrib
) ||
100 ! wattrib
.screen
|| wattrib
.override_redirect
) {
103 "BlackboxWindow::BlackboxWindow(): XGetWindowAttributes failed\n");
110 // set the eventmask early in the game so that we make sure we get
111 // all the events we are interested in
112 XSetWindowAttributes attrib_set
;
113 attrib_set
.event_mask
= PropertyChangeMask
| FocusChangeMask
|
115 attrib_set
.do_not_propagate_mask
= ButtonPressMask
| ButtonReleaseMask
|
117 XChangeWindowAttributes(blackbox
->getXDisplay(), client
.window
,
118 CWEventMask
|CWDontPropagate
, &attrib_set
);
120 flags
.moving
= flags
.resizing
= flags
.shaded
= flags
.visible
=
121 flags
.iconic
= flags
.focused
= flags
.stuck
= flags
.modal
=
122 flags
.send_focus_message
= flags
.shaped
= flags
.skip_taskbar
=
123 flags
.skip_pager
= flags
.fullscreen
= False
;
126 blackbox_attrib
.workspace
= window_number
= BSENTINEL
;
128 blackbox_attrib
.flags
= blackbox_attrib
.attrib
= blackbox_attrib
.stack
129 = blackbox_attrib
.decoration
= 0l;
130 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
131 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
134 frame
.window
= frame
.plate
= frame
.title
= frame
.handle
= None
;
135 frame
.close_button
= frame
.iconify_button
= frame
.maximize_button
= None
;
136 frame
.right_grip
= frame
.left_grip
= None
;
138 frame
.ulabel_pixel
= frame
.flabel_pixel
= frame
.utitle_pixel
=
139 frame
.ftitle_pixel
= frame
.uhandle_pixel
= frame
.fhandle_pixel
=
140 frame
.ubutton_pixel
= frame
.fbutton_pixel
= frame
.pbutton_pixel
=
141 frame
.uborder_pixel
= frame
.fborder_pixel
= frame
.ugrip_pixel
=
142 frame
.fgrip_pixel
= 0;
143 frame
.utitle
= frame
.ftitle
= frame
.uhandle
= frame
.fhandle
= None
;
144 frame
.ulabel
= frame
.flabel
= frame
.ubutton
= frame
.fbutton
= None
;
145 frame
.pbutton
= frame
.ugrip
= frame
.fgrip
= None
;
147 decorations
= Decor_Titlebar
| Decor_Border
| Decor_Handle
|
148 Decor_Iconify
| Decor_Maximize
;
149 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
151 client
.normal_hint_flags
= 0;
152 client
.window_group
= None
;
153 client
.transient_for
= 0;
155 current_state
= NormalState
;
158 get the initial size and location of client window (relative to the
159 _root window_). This position is the reference point used with the
160 window's gravity to find the window's initial position.
162 client
.rect
.setRect(wattrib
.x
, wattrib
.y
, wattrib
.width
, wattrib
.height
);
163 client
.old_bw
= wattrib
.border_width
;
165 lastButtonPressTime
= 0;
167 timer
= new BTimer(blackbox
, this);
168 timer
->setTimeout(blackbox
->getAutoRaiseDelay());
170 windowmenu
= new Windowmenu(this);
172 // get size, aspect, minimum/maximum size and other hints set by the
175 if (! getBlackboxHints()) {
184 frame
.window
= createToplevelWindow();
186 blackbox
->saveWindowSearch(frame
.window
, this);
188 frame
.plate
= createChildWindow(frame
.window
);
189 blackbox
->saveWindowSearch(frame
.plate
, this);
191 // determine if this is a transient window
194 // determine the window's type, so we can decide its decorations and
195 // functionality, or if we should not manage it at all
198 // adjust the window decorations/behavior based on the window type
200 switch (window_type
) {
207 // none of these windows are decorated or manipulated by the window manager
210 blackbox_attrib
.workspace
= 0; // we do need to belong to a workspace
211 flags
.stuck
= True
; // we show up on all workspaces
215 // dialogs cannot be maximized, and don't display a handle
216 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
217 functions
&= ~Func_Maximize
;
221 // normal windows retain all of the possible decorations and functionality
227 // further adjeust the window's decorations/behavior based on window sizes
228 if ((client
.normal_hint_flags
& PMinSize
) &&
229 (client
.normal_hint_flags
& PMaxSize
) &&
230 client
.max_width
<= client
.min_width
&&
231 client
.max_height
<= client
.min_height
) {
232 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
233 functions
&= ~(Func_Resize
| Func_Maximize
);
236 if (decorations
& Decor_Titlebar
)
239 if (decorations
& Decor_Handle
)
242 // apply the size and gravity hint to the frame
246 bool place_window
= True
;
247 if (blackbox
->isStartup() || isTransient() ||
248 client
.normal_hint_flags
& (PPosition
|USPosition
)) {
249 applyGravity(frame
.rect
);
251 if (blackbox
->isStartup() || client
.rect
.intersects(screen
->getRect()))
252 place_window
= False
;
255 // add the window's strut. note this is done *after* placing the window.
256 screen
->addStrut(&client
.strut
);
260 if (blackbox
->hasShapeExtensions() && flags
.shaped
)
264 if (blackbox_attrib
.workspace
>= screen
->getWorkspaceCount())
265 screen
->getCurrentWorkspace()->addWindow(this, place_window
);
267 screen
->getWorkspace(blackbox_attrib
.workspace
)->
268 addWindow(this, place_window
);
271 the server needs to be grabbed here to prevent client's from sending
272 events while we are in the process of configuring their window.
273 We hold the grab until after we are done moving the window around.
276 XGrabServer(blackbox
->getXDisplay());
278 associateClientWindow();
280 blackbox
->saveWindowSearch(client
.window
, this);
282 if (! place_window
) {
283 // don't need to call configure if we are letting the workspace
285 configure(frame
.rect
.x(), frame
.rect
.y(),
286 frame
.rect
.width(), frame
.rect
.height());
292 XUngrabServer(blackbox
->getXDisplay());
294 // now that we know where to put the window and what it should look like
295 // we apply the decorations
300 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
302 // this ensures the title, buttons, and other decor are properly displayed
305 // preserve the window's initial state on first map, and its current state
307 unsigned long initial_state
= current_state
;
309 current_state
= initial_state
;
311 // get sticky state from our parent window if we've got one
312 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
313 client
.transient_for
->isStuck() != flags
.stuck
)
316 // the following flags are set by blackbox native apps only
318 flags
.shaded
= False
;
319 initial_state
= current_state
;
323 At this point in the life of a window, current_state should only be set
324 to IconicState if the window was an *icon*, not if it was shaded.
326 if (initial_state
!= IconicState
)
327 current_state
= NormalState
;
335 if (flags
.maximized
&& (functions
& Func_Maximize
))
340 BlackboxWindow::~BlackboxWindow(void) {
342 fprintf(stderr
, "BlackboxWindow::~BlackboxWindow: destroying 0x%lx\n",
346 if (! timer
) // window not managed...
349 screen
->removeStrut(&client
.strut
);
350 screen
->updateAvailableArea();
352 // We don't need to worry about resizing because resizing always grabs the X
353 // server. This should only ever happen if using opaque moving.
361 if (client
.window_group
) {
362 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
363 if (group
) group
->removeWindow(this);
366 // remove ourselves from our transient_for
368 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
369 client
.transient_for
->client
.transientList
.remove(this);
371 client
.transient_for
= (BlackboxWindow
*) 0;
374 if (client
.transientList
.size() > 0) {
375 // reset transient_for for all transients
376 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
377 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
378 (*it
)->client
.transient_for
= (BlackboxWindow
*) 0;
389 blackbox
->removeWindowSearch(frame
.plate
);
390 XDestroyWindow(blackbox
->getXDisplay(), frame
.plate
);
394 blackbox
->removeWindowSearch(frame
.window
);
395 XDestroyWindow(blackbox
->getXDisplay(), frame
.window
);
398 blackbox
->removeWindowSearch(client
.window
);
403 * Creates a new top level window, with a given location, size, and border
405 * Returns: the newly created window
407 Window
BlackboxWindow::createToplevelWindow(void) {
408 XSetWindowAttributes attrib_create
;
409 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
| CWColormap
|
410 CWOverrideRedirect
| CWEventMask
;
412 attrib_create
.background_pixmap
= None
;
413 attrib_create
.colormap
= screen
->getColormap();
414 attrib_create
.override_redirect
= True
;
415 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
416 ButtonMotionMask
| EnterWindowMask
;
418 return XCreateWindow(blackbox
->getXDisplay(), screen
->getRootWindow(),
419 0, 0, 1, 1, frame
.border_w
, screen
->getDepth(),
420 InputOutput
, screen
->getVisual(), create_mask
,
426 * Creates a child window, and optionally associates a given cursor with
429 Window
BlackboxWindow::createChildWindow(Window parent
, Cursor cursor
) {
430 XSetWindowAttributes attrib_create
;
431 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
|
434 attrib_create
.background_pixmap
= None
;
435 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
436 ButtonMotionMask
| ExposureMask
;
439 create_mask
|= CWCursor
;
440 attrib_create
.cursor
= cursor
;
443 return XCreateWindow(blackbox
->getXDisplay(), parent
, 0, 0, 1, 1, 0,
444 screen
->getDepth(), InputOutput
, screen
->getVisual(),
445 create_mask
, &attrib_create
);
449 void BlackboxWindow::associateClientWindow(void) {
450 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, 0);
454 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeInsert
);
456 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, SubstructureRedirectMask
);
459 note we used to grab around this call to XReparentWindow however the
460 server is now grabbed before this method is called
462 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
464 XSelectInput(blackbox
->getXDisplay(), client
.window
,
465 event_mask
& ~StructureNotifyMask
);
466 XReparentWindow(blackbox
->getXDisplay(), client
.window
, frame
.plate
, 0, 0);
467 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
469 XRaiseWindow(blackbox
->getXDisplay(), frame
.plate
);
470 XMapSubwindows(blackbox
->getXDisplay(), frame
.plate
);
473 if (blackbox
->hasShapeExtensions()) {
474 XShapeSelectInput(blackbox
->getXDisplay(), client
.window
,
481 XShapeQueryExtents(blackbox
->getXDisplay(), client
.window
, &shaped
,
482 &foo
, &foo
, &ufoo
, &ufoo
, &foo
, &foo
, &foo
,
484 flags
.shaped
= shaped
;
490 void BlackboxWindow::decorate(void) {
493 texture
= &(screen
->getWindowStyle()->b_focus
);
494 frame
.fbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
497 frame
.fbutton_pixel
= texture
->color().pixel();
499 texture
= &(screen
->getWindowStyle()->b_unfocus
);
500 frame
.ubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
503 frame
.ubutton_pixel
= texture
->color().pixel();
505 texture
= &(screen
->getWindowStyle()->b_pressed
);
506 frame
.pbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
509 frame
.pbutton_pixel
= texture
->color().pixel();
511 if (decorations
& Decor_Titlebar
) {
512 texture
= &(screen
->getWindowStyle()->t_focus
);
513 frame
.ftitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
516 frame
.ftitle_pixel
= texture
->color().pixel();
518 texture
= &(screen
->getWindowStyle()->t_unfocus
);
519 frame
.utitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
522 frame
.utitle_pixel
= texture
->color().pixel();
524 XSetWindowBorder(blackbox
->getXDisplay(), frame
.title
,
525 screen
->getBorderColor()->pixel());
530 if (decorations
& Decor_Border
) {
531 frame
.fborder_pixel
= screen
->getWindowStyle()->f_focus
.pixel();
532 frame
.uborder_pixel
= screen
->getWindowStyle()->f_unfocus
.pixel();
533 blackbox_attrib
.flags
|= AttribDecoration
;
534 blackbox_attrib
.decoration
= DecorNormal
;
536 blackbox_attrib
.flags
|= AttribDecoration
;
537 blackbox_attrib
.decoration
= DecorNone
;
540 if (decorations
& Decor_Handle
) {
541 texture
= &(screen
->getWindowStyle()->h_focus
);
542 frame
.fhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
545 frame
.fhandle_pixel
= texture
->color().pixel();
547 texture
= &(screen
->getWindowStyle()->h_unfocus
);
548 frame
.uhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
551 frame
.uhandle_pixel
= texture
->color().pixel();
553 texture
= &(screen
->getWindowStyle()->g_focus
);
554 frame
.fgrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.fgrip
);
556 frame
.fgrip_pixel
= texture
->color().pixel();
558 texture
= &(screen
->getWindowStyle()->g_unfocus
);
559 frame
.ugrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.ugrip
);
561 frame
.ugrip_pixel
= texture
->color().pixel();
563 XSetWindowBorder(blackbox
->getXDisplay(), frame
.handle
,
564 screen
->getBorderColor()->pixel());
565 XSetWindowBorder(blackbox
->getXDisplay(), frame
.left_grip
,
566 screen
->getBorderColor()->pixel());
567 XSetWindowBorder(blackbox
->getXDisplay(), frame
.right_grip
,
568 screen
->getBorderColor()->pixel());
571 XSetWindowBorder(blackbox
->getXDisplay(), frame
.window
,
572 screen
->getBorderColor()->pixel());
576 void BlackboxWindow::decorateLabel(void) {
579 texture
= &(screen
->getWindowStyle()->l_focus
);
580 frame
.flabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.flabel
);
582 frame
.flabel_pixel
= texture
->color().pixel();
584 texture
= &(screen
->getWindowStyle()->l_unfocus
);
585 frame
.ulabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.ulabel
);
587 frame
.ulabel_pixel
= texture
->color().pixel();
591 void BlackboxWindow::createHandle(void) {
592 frame
.handle
= createChildWindow(frame
.window
);
593 blackbox
->saveWindowSearch(frame
.handle
, this);
596 createChildWindow(frame
.handle
, blackbox
->getLowerLeftAngleCursor());
597 blackbox
->saveWindowSearch(frame
.left_grip
, this);
600 createChildWindow(frame
.handle
, blackbox
->getLowerRightAngleCursor());
601 blackbox
->saveWindowSearch(frame
.right_grip
, this);
605 void BlackboxWindow::destroyHandle(void) {
607 screen
->getImageControl()->removeImage(frame
.fhandle
);
610 screen
->getImageControl()->removeImage(frame
.uhandle
);
613 screen
->getImageControl()->removeImage(frame
.fgrip
);
616 screen
->getImageControl()->removeImage(frame
.ugrip
);
618 blackbox
->removeWindowSearch(frame
.left_grip
);
619 blackbox
->removeWindowSearch(frame
.right_grip
);
621 XDestroyWindow(blackbox
->getXDisplay(), frame
.left_grip
);
622 XDestroyWindow(blackbox
->getXDisplay(), frame
.right_grip
);
623 frame
.left_grip
= frame
.right_grip
= None
;
625 blackbox
->removeWindowSearch(frame
.handle
);
626 XDestroyWindow(blackbox
->getXDisplay(), frame
.handle
);
631 void BlackboxWindow::createTitlebar(void) {
632 frame
.title
= createChildWindow(frame
.window
);
633 frame
.label
= createChildWindow(frame
.title
);
634 blackbox
->saveWindowSearch(frame
.title
, this);
635 blackbox
->saveWindowSearch(frame
.label
, this);
637 if (decorations
& Decor_Iconify
) createIconifyButton();
638 if (decorations
& Decor_Maximize
) createMaximizeButton();
639 if (decorations
& Decor_Close
) createCloseButton();
643 void BlackboxWindow::destroyTitlebar(void) {
644 if (frame
.close_button
)
645 destroyCloseButton();
647 if (frame
.iconify_button
)
648 destroyIconifyButton();
650 if (frame
.maximize_button
)
651 destroyMaximizeButton();
654 screen
->getImageControl()->removeImage(frame
.ftitle
);
657 screen
->getImageControl()->removeImage(frame
.utitle
);
660 screen
->getImageControl()->removeImage(frame
.flabel
);
663 screen
->getImageControl()->removeImage(frame
.ulabel
);
666 screen
->getImageControl()->removeImage(frame
.fbutton
);
669 screen
->getImageControl()->removeImage(frame
.ubutton
);
672 screen
->getImageControl()->removeImage(frame
.pbutton
);
674 blackbox
->removeWindowSearch(frame
.title
);
675 blackbox
->removeWindowSearch(frame
.label
);
677 XDestroyWindow(blackbox
->getXDisplay(), frame
.label
);
678 XDestroyWindow(blackbox
->getXDisplay(), frame
.title
);
679 frame
.title
= frame
.label
= None
;
683 void BlackboxWindow::createCloseButton(void) {
684 if (frame
.title
!= None
) {
685 frame
.close_button
= createChildWindow(frame
.title
);
686 blackbox
->saveWindowSearch(frame
.close_button
, this);
691 void BlackboxWindow::destroyCloseButton(void) {
692 blackbox
->removeWindowSearch(frame
.close_button
);
693 XDestroyWindow(blackbox
->getXDisplay(), frame
.close_button
);
694 frame
.close_button
= None
;
698 void BlackboxWindow::createIconifyButton(void) {
699 if (frame
.title
!= None
) {
700 frame
.iconify_button
= createChildWindow(frame
.title
);
701 blackbox
->saveWindowSearch(frame
.iconify_button
, this);
706 void BlackboxWindow::destroyIconifyButton(void) {
707 blackbox
->removeWindowSearch(frame
.iconify_button
);
708 XDestroyWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
709 frame
.iconify_button
= None
;
713 void BlackboxWindow::createMaximizeButton(void) {
714 if (frame
.title
!= None
) {
715 frame
.maximize_button
= createChildWindow(frame
.title
);
716 blackbox
->saveWindowSearch(frame
.maximize_button
, this);
721 void BlackboxWindow::destroyMaximizeButton(void) {
722 blackbox
->removeWindowSearch(frame
.maximize_button
);
723 XDestroyWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
724 frame
.maximize_button
= None
;
728 void BlackboxWindow::positionButtons(bool redecorate_label
) {
729 string layout
= blackbox
->getTitlebarLayout();
732 bool hasclose
, hasiconify
, hasmaximize
, haslabel
;
733 hasclose
= hasiconify
= hasmaximize
= haslabel
= false;
735 string::const_iterator it
, end
;
736 for (it
= layout
.begin(), end
= layout
.end(); it
!= end
; ++it
) {
739 if (! hasclose
&& (decorations
& Decor_Close
)) {
745 if (! hasiconify
&& (decorations
& Decor_Iconify
)) {
751 if (! hasmaximize
&& (decorations
& Decor_Maximize
)) {
763 if (! hasclose
&& frame
.close_button
)
764 destroyCloseButton();
765 if (! hasiconify
&& frame
.iconify_button
)
766 destroyIconifyButton();
767 if (! hasmaximize
&& frame
.maximize_button
)
768 destroyMaximizeButton();
770 parsed
+= 'L'; // require that the label be in the layout
772 const unsigned int bsep
= frame
.bevel_w
+ 1; // separation between elements
773 const unsigned int by
= frame
.bevel_w
+ 1;
774 const unsigned int ty
= frame
.bevel_w
;
776 frame
.label_w
= frame
.inside_w
- bsep
* 2 -
777 (frame
.button_w
+ bsep
) * (parsed
.size() - 1);
779 unsigned int x
= bsep
;
780 for (it
= parsed
.begin(), end
= parsed
.end(); it
!= end
; ++it
) {
783 if (! frame
.close_button
) createCloseButton();
784 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.close_button
, x
, by
,
785 frame
.button_w
, frame
.button_w
);
786 x
+= frame
.button_w
+ bsep
;
789 if (! frame
.iconify_button
) createIconifyButton();
790 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.iconify_button
, x
, by
,
791 frame
.button_w
, frame
.button_w
);
792 x
+= frame
.button_w
+ bsep
;
795 if (! frame
.maximize_button
) createMaximizeButton();
796 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.maximize_button
, x
, by
,
797 frame
.button_w
, frame
.button_w
);
798 x
+= frame
.button_w
+ bsep
;
801 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.label
, x
, ty
,
802 frame
.label_w
, frame
.label_h
);
803 x
+= frame
.label_w
+ bsep
;
808 if (redecorate_label
) decorateLabel();
814 void BlackboxWindow::reconfigure(void) {
815 restoreGravity(client
.rect
);
817 applyGravity(frame
.rect
);
826 windowmenu
->move(windowmenu
->getX(), frame
.rect
.y() + frame
.title_h
);
827 windowmenu
->reconfigure();
832 void BlackboxWindow::grabButtons(void) {
833 if (! screen
->isSloppyFocus() || screen
->doClickRaise())
834 // grab button 1 for changing focus/raising
835 blackbox
->grabButton(Button1
, 0, frame
.plate
, True
, ButtonPressMask
,
836 GrabModeSync
, GrabModeSync
, frame
.plate
, None
,
837 screen
->allowScrollLock());
839 if (functions
& Func_Move
)
840 blackbox
->grabButton(Button1
, ModMask
, frame
.window
, True
,
841 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
842 GrabModeAsync
, frame
.window
, None
,
843 screen
->allowScrollLock());
844 if (functions
& Func_Resize
)
845 blackbox
->grabButton(Button3
, ModMask
, frame
.window
, True
,
846 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
847 GrabModeAsync
, frame
.window
, None
,
848 screen
->allowScrollLock());
849 // alt+middle lowers the window
850 blackbox
->grabButton(Button2
, ModMask
, frame
.window
, True
,
851 ButtonReleaseMask
, GrabModeAsync
, GrabModeAsync
,
853 screen
->allowScrollLock());
857 void BlackboxWindow::ungrabButtons(void) {
858 blackbox
->ungrabButton(Button1
, 0, frame
.plate
);
859 blackbox
->ungrabButton(Button1
, ModMask
, frame
.window
);
860 blackbox
->ungrabButton(Button2
, ModMask
, frame
.window
);
861 blackbox
->ungrabButton(Button3
, ModMask
, frame
.window
);
865 void BlackboxWindow::positionWindows(void) {
866 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.window
,
867 frame
.rect
.x(), frame
.rect
.y(), frame
.inside_w
,
868 (flags
.shaded
) ? frame
.title_h
: frame
.inside_h
);
869 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.window
,
871 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.plate
,
873 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.plate
,
874 frame
.margin
.left
- frame
.mwm_border_w
- frame
.border_w
,
875 frame
.margin
.top
- frame
.mwm_border_w
- frame
.border_w
,
876 client
.rect
.width(), client
.rect
.height());
877 XMoveResizeWindow(blackbox
->getXDisplay(), client
.window
,
878 0, 0, client
.rect
.width(), client
.rect
.height());
879 // ensure client.rect contains the real location
880 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
881 frame
.rect
.top() + frame
.margin
.top
);
883 if (decorations
& Decor_Titlebar
) {
884 if (frame
.title
== None
) createTitlebar();
886 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.title
,
888 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.title
, -frame
.border_w
,
889 -frame
.border_w
, frame
.inside_w
, frame
.title_h
);
892 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
893 XMapWindow(blackbox
->getXDisplay(), frame
.title
);
894 } else if (frame
.title
) {
897 if (decorations
& Decor_Handle
) {
898 if (frame
.handle
== None
) createHandle();
899 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.handle
,
901 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.left_grip
,
903 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.right_grip
,
906 // use client.rect here so the value is correct even if shaded
907 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.handle
,
909 client
.rect
.height() + frame
.margin
.top
+
910 frame
.mwm_border_w
- frame
.border_w
,
911 frame
.inside_w
, frame
.handle_h
);
912 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.left_grip
,
913 -frame
.border_w
, -frame
.border_w
,
914 frame
.grip_w
, frame
.handle_h
);
915 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.right_grip
,
916 frame
.inside_w
- frame
.grip_w
- frame
.border_w
,
917 -frame
.border_w
, frame
.grip_w
, frame
.handle_h
);
919 XMapSubwindows(blackbox
->getXDisplay(), frame
.handle
);
920 XMapWindow(blackbox
->getXDisplay(), frame
.handle
);
921 } else if (frame
.handle
) {
924 XSync(blackbox
->getXDisplay(), False
);
928 void BlackboxWindow::updateStrut(void) {
929 unsigned long num
= 4;
931 if (! xatom
->getValue(client
.window
, XAtom::net_wm_strut
, XAtom::cardinal
,
936 client
.strut
.left
= data
[0];
937 client
.strut
.right
= data
[1];
938 client
.strut
.top
= data
[2];
939 client
.strut
.bottom
= data
[3];
941 screen
->updateAvailableArea();
948 void BlackboxWindow::getWindowType(void) {
950 if (xatom
->getValue(client
.window
, XAtom::net_wm_window_type
, XAtom::atom
,
952 if (val
== xatom
->getAtom(XAtom::net_wm_window_type_desktop
))
953 window_type
= Type_Desktop
;
954 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_dock
))
955 window_type
= Type_Dock
;
956 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_toolbar
))
957 window_type
= Type_Toolbar
;
958 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_menu
))
959 window_type
= Type_Menu
;
960 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_utility
))
961 window_type
= Type_Utility
;
962 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_splash
))
963 window_type
= Type_Splash
;
964 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_dialog
))
965 window_type
= Type_Dialog
;
966 else //if (val[0] == xatom->getAtom(XAtom::net_wm_window_type_normal))
967 window_type
= Type_Normal
;
972 * the window type hint was not set, which means we either classify ourself
973 * as a normal window or a dialog, depending on if we are a transient.
976 window_type
= Type_Dialog
;
978 window_type
= Type_Normal
;
982 void BlackboxWindow::getWMName(void) {
983 if (xatom
->getValue(client
.window
, XAtom::net_wm_name
,
984 XAtom::utf8
, client
.title
) &&
985 !client
.title
.empty()) {
986 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
989 //fall through to using WM_NAME
990 if (xatom
->getValue(client
.window
, XAtom::wm_name
, XAtom::ansi
, client
.title
)
991 && !client
.title
.empty()) {
992 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
995 // fall back to an internal default
996 client
.title
= i18n(WindowSet
, WindowUnnamed
, "Unnamed");
997 xatom
->setValue(client
.window
, XAtom::net_wm_visible_name
, XAtom::utf8
,
1002 void BlackboxWindow::getWMIconName(void) {
1003 if (xatom
->getValue(client
.window
, XAtom::net_wm_icon_name
,
1004 XAtom::utf8
, client
.icon_title
) &&
1005 !client
.icon_title
.empty()) {
1006 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1009 //fall through to using WM_ICON_NAME
1010 if (xatom
->getValue(client
.window
, XAtom::wm_icon_name
, XAtom::ansi
,
1011 client
.icon_title
) &&
1012 !client
.icon_title
.empty()) {
1013 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1016 // fall back to using the main name
1017 client
.icon_title
= client
.title
;
1018 xatom
->setValue(client
.window
, XAtom::net_wm_visible_icon_name
, XAtom::utf8
,
1024 * Retrieve which WM Protocols are supported by the client window.
1025 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
1026 * window's decorations and allow the close behavior.
1027 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
1030 void BlackboxWindow::getWMProtocols(void) {
1034 if (XGetWMProtocols(blackbox
->getXDisplay(), client
.window
,
1035 &proto
, &num_return
)) {
1036 for (int i
= 0; i
< num_return
; ++i
) {
1037 if (proto
[i
] == xatom
->getAtom(XAtom::wm_delete_window
)) {
1038 decorations
|= Decor_Close
;
1039 functions
|= Func_Close
;
1040 } else if (proto
[i
] == xatom
->getAtom(XAtom::wm_take_focus
))
1041 flags
.send_focus_message
= True
;
1042 else if (proto
[i
] == xatom
->getAtom(XAtom::blackbox_structure_messages
))
1043 screen
->addNetizen(new Netizen(screen
, client
.window
));
1052 * Gets the value of the WM_HINTS property.
1053 * If the property is not set, then use a set of default values.
1055 void BlackboxWindow::getWMHints(void) {
1056 focus_mode
= F_Passive
;
1058 // remove from current window group
1059 if (client
.window_group
) {
1060 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1061 if (group
) group
->removeWindow(this);
1063 client
.window_group
= None
;
1065 XWMHints
*wmhint
= XGetWMHints(blackbox
->getXDisplay(), client
.window
);
1070 if (wmhint
->flags
& InputHint
) {
1071 if (wmhint
->input
== True
) {
1072 if (flags
.send_focus_message
)
1073 focus_mode
= F_LocallyActive
;
1075 if (flags
.send_focus_message
)
1076 focus_mode
= F_GloballyActive
;
1078 focus_mode
= F_NoInput
;
1082 if (wmhint
->flags
& StateHint
)
1083 current_state
= wmhint
->initial_state
;
1085 if (wmhint
->flags
& WindowGroupHint
) {
1086 client
.window_group
= wmhint
->window_group
;
1088 // add window to the appropriate group
1089 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1090 if (! group
) { // no group found, create it!
1091 new BWindowGroup(blackbox
, client
.window_group
);
1092 group
= blackbox
->searchGroup(client
.window_group
);
1095 group
->addWindow(this);
1103 * Gets the value of the WM_NORMAL_HINTS property.
1104 * If the property is not set, then use a set of default values.
1106 void BlackboxWindow::getWMNormalHints(void) {
1108 XSizeHints sizehint
;
1110 client
.min_width
= client
.min_height
=
1111 client
.width_inc
= client
.height_inc
= 1;
1112 client
.base_width
= client
.base_height
= 0;
1113 client
.win_gravity
= NorthWestGravity
;
1115 client
.min_aspect_x
= client
.min_aspect_y
=
1116 client
.max_aspect_x
= client
.max_aspect_y
= 1;
1120 use the full screen, not the strut modified size. otherwise when the
1121 availableArea changes max_width/height will be incorrect and lead to odd
1124 const Rect
& screen_area
= screen
->getRect();
1125 client
.max_width
= screen_area
.width();
1126 client
.max_height
= screen_area
.height();
1128 if (! XGetWMNormalHints(blackbox
->getXDisplay(), client
.window
,
1129 &sizehint
, &icccm_mask
))
1132 client
.normal_hint_flags
= sizehint
.flags
;
1134 if (sizehint
.flags
& PMinSize
) {
1135 if (sizehint
.min_width
>= 0)
1136 client
.min_width
= sizehint
.min_width
;
1137 if (sizehint
.min_height
>= 0)
1138 client
.min_height
= sizehint
.min_height
;
1141 if (sizehint
.flags
& PMaxSize
) {
1142 if (sizehint
.max_width
> static_cast<signed>(client
.min_width
))
1143 client
.max_width
= sizehint
.max_width
;
1145 client
.max_width
= client
.min_width
;
1147 if (sizehint
.max_height
> static_cast<signed>(client
.min_height
))
1148 client
.max_height
= sizehint
.max_height
;
1150 client
.max_height
= client
.min_height
;
1153 if (sizehint
.flags
& PResizeInc
) {
1154 client
.width_inc
= sizehint
.width_inc
;
1155 client
.height_inc
= sizehint
.height_inc
;
1158 #if 0 // we do not support this at the moment
1159 if (sizehint
.flags
& PAspect
) {
1160 client
.min_aspect_x
= sizehint
.min_aspect
.x
;
1161 client
.min_aspect_y
= sizehint
.min_aspect
.y
;
1162 client
.max_aspect_x
= sizehint
.max_aspect
.x
;
1163 client
.max_aspect_y
= sizehint
.max_aspect
.y
;
1167 if (sizehint
.flags
& PBaseSize
) {
1168 client
.base_width
= sizehint
.base_width
;
1169 client
.base_height
= sizehint
.base_height
;
1172 if (sizehint
.flags
& PWinGravity
)
1173 client
.win_gravity
= sizehint
.win_gravity
;
1178 * Gets the NETWM hints for the class' contained window.
1180 void BlackboxWindow::getNetWMHints(void) {
1181 unsigned long workspace
;
1183 if (xatom
->getValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1185 if (workspace
== 0xffffffff)
1188 blackbox_attrib
.workspace
= workspace
;
1191 unsigned long *state
;
1192 unsigned long num
= (unsigned) -1;
1193 if (xatom
->getValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
1197 for (unsigned long i
= 0; i
< num
; ++i
) {
1198 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
))
1200 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_shaded
))
1201 flags
.shaded
= True
;
1202 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
))
1203 flags
.skip_taskbar
= True
;
1204 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_pager
))
1205 flags
.skip_pager
= True
;
1206 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_fullscreen
))
1207 flags
.fullscreen
= True
;
1208 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_hidden
))
1209 setState(IconicState
);
1210 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_vert
))
1212 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_horz
))
1216 flags
.maximized
= 1;
1218 flags
.maximized
= 2;
1220 flags
.maximized
= 3;
1228 * Gets the MWM hints for the class' contained window.
1229 * This is used while initializing the window to its first state, and not
1231 * Returns: true if the MWM hints are successfully retreived and applied;
1232 * false if they are not.
1234 void BlackboxWindow::getMWMHints(void) {
1238 num
= PropMwmHintsElements
;
1239 if (! xatom
->getValue(client
.window
, XAtom::motif_wm_hints
,
1240 XAtom::motif_wm_hints
, num
,
1241 (unsigned long **)&mwm_hint
))
1243 if (num
< PropMwmHintsElements
) {
1248 if (mwm_hint
->flags
& MwmHintsDecorations
) {
1249 if (mwm_hint
->decorations
& MwmDecorAll
) {
1250 decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
1251 Decor_Iconify
| Decor_Maximize
| Decor_Close
;
1255 if (mwm_hint
->decorations
& MwmDecorBorder
)
1256 decorations
|= Decor_Border
;
1257 if (mwm_hint
->decorations
& MwmDecorHandle
)
1258 decorations
|= Decor_Handle
;
1259 if (mwm_hint
->decorations
& MwmDecorTitle
)
1260 decorations
|= Decor_Titlebar
;
1261 if (mwm_hint
->decorations
& MwmDecorIconify
)
1262 decorations
|= Decor_Iconify
;
1263 if (mwm_hint
->decorations
& MwmDecorMaximize
)
1264 decorations
|= Decor_Maximize
;
1268 if (mwm_hint
->flags
& MwmHintsFunctions
) {
1269 if (mwm_hint
->functions
& MwmFuncAll
) {
1270 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
|
1275 if (mwm_hint
->functions
& MwmFuncResize
)
1276 functions
|= Func_Resize
;
1277 if (mwm_hint
->functions
& MwmFuncMove
)
1278 functions
|= Func_Move
;
1279 if (mwm_hint
->functions
& MwmFuncIconify
)
1280 functions
|= Func_Iconify
;
1281 if (mwm_hint
->functions
& MwmFuncMaximize
)
1282 functions
|= Func_Maximize
;
1283 if (mwm_hint
->functions
& MwmFuncClose
)
1284 functions
|= Func_Close
;
1292 * Gets the blackbox hints from the class' contained window.
1293 * This is used while initializing the window to its first state, and not
1295 * Returns: true if the hints are successfully retreived and applied; false if
1298 bool BlackboxWindow::getBlackboxHints(void) {
1300 BlackboxHints
*blackbox_hint
;
1302 num
= PropBlackboxHintsElements
;
1303 if (! xatom
->getValue(client
.window
, XAtom::blackbox_hints
,
1304 XAtom::blackbox_hints
, num
,
1305 (unsigned long **)&blackbox_hint
))
1307 if (num
< PropBlackboxHintsElements
) {
1308 delete [] blackbox_hint
;
1312 if (blackbox_hint
->flags
& AttribShaded
)
1313 flags
.shaded
= (blackbox_hint
->attrib
& AttribShaded
);
1315 if ((blackbox_hint
->flags
& AttribMaxHoriz
) &&
1316 (blackbox_hint
->flags
& AttribMaxVert
))
1317 flags
.maximized
= (blackbox_hint
->attrib
&
1318 (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1319 else if (blackbox_hint
->flags
& AttribMaxVert
)
1320 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxVert
) ? 2 : 0;
1321 else if (blackbox_hint
->flags
& AttribMaxHoriz
)
1322 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1324 if (blackbox_hint
->flags
& AttribOmnipresent
)
1325 flags
.stuck
= (blackbox_hint
->attrib
& AttribOmnipresent
);
1327 if (blackbox_hint
->flags
& AttribWorkspace
)
1328 blackbox_attrib
.workspace
= blackbox_hint
->workspace
;
1330 // if (blackbox_hint->flags & AttribStack)
1331 // don't yet have always on top/bottom for blackbox yet... working
1334 if (blackbox_hint
->flags
& AttribDecoration
) {
1335 switch (blackbox_hint
->decoration
) {
1341 decorations
|= Decor_Titlebar
| Decor_Iconify
;
1342 decorations
&= ~(Decor_Border
| Decor_Handle
| Decor_Maximize
);
1343 functions
&= ~(Func_Resize
| Func_Maximize
);
1348 decorations
|= Decor_Titlebar
;
1349 decorations
&= ~(Decor_Iconify
| Decor_Border
| Decor_Handle
);
1350 functions
&= ~(Func_Resize
| Func_Maximize
| Func_Iconify
);
1356 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Handle
|
1357 Decor_Iconify
| Decor_Maximize
;
1364 delete [] blackbox_hint
;
1370 void BlackboxWindow::getTransientInfo(void) {
1371 if (client
.transient_for
&&
1372 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1373 // reset transient_for in preparation of looking for a new owner
1374 client
.transient_for
->client
.transientList
.remove(this);
1377 // we have no transient_for until we find a new one
1378 client
.transient_for
= 0;
1381 if (! XGetTransientForHint(blackbox
->getXDisplay(), client
.window
,
1383 // transient_for hint not set
1387 if (trans_for
== client
.window
) {
1388 // wierd client... treat this window as a normal window
1392 if (trans_for
== None
|| trans_for
== screen
->getRootWindow()) {
1393 // this is an undocumented interpretation of the ICCCM. a transient
1394 // associated with None/Root/itself is assumed to be a modal root
1395 // transient. we don't support the concept of a global transient,
1396 // so we just associate this transient with nothing, and perhaps
1397 // we will add support later for global modality.
1398 client
.transient_for
= (BlackboxWindow
*) ~0ul;
1403 client
.transient_for
= blackbox
->searchWindow(trans_for
);
1404 if (! client
.transient_for
&&
1405 client
.window_group
&& trans_for
== client
.window_group
) {
1406 // no direct transient_for, perhaps this is a group transient?
1407 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1408 if (group
) client
.transient_for
= group
->find(screen
);
1411 if (! client
.transient_for
|| client
.transient_for
== this) {
1412 // no transient_for found, or we have a wierd client that wants to be
1413 // a transient for itself, so we treat this window as a normal window
1414 client
.transient_for
= (BlackboxWindow
*) 0;
1418 // register ourselves with our new transient_for
1419 client
.transient_for
->client
.transientList
.push_back(this);
1420 flags
.stuck
= client
.transient_for
->flags
.stuck
;
1424 BlackboxWindow
*BlackboxWindow::getTransientFor(void) const {
1425 if (client
.transient_for
&&
1426 client
.transient_for
!= (BlackboxWindow
*) ~0ul)
1427 return client
.transient_for
;
1433 * This function is responsible for updating both the client and the frame
1435 * According to the ICCCM a client message is not sent for a resize, only a
1438 void BlackboxWindow::configure(int dx
, int dy
,
1439 unsigned int dw
, unsigned int dh
) {
1440 bool send_event
= ((frame
.rect
.x() != dx
|| frame
.rect
.y() != dy
) &&
1443 if (dw
!= frame
.rect
.width() || dh
!= frame
.rect
.height()) {
1444 frame
.rect
.setRect(dx
, dy
, dw
, dh
);
1445 frame
.inside_w
= frame
.rect
.width() - (frame
.border_w
* 2);
1446 frame
.inside_h
= frame
.rect
.height() - (frame
.border_w
* 2);
1448 if (frame
.rect
.right() <= 0 || frame
.rect
.bottom() <= 0)
1449 frame
.rect
.setPos(0, 0);
1451 client
.rect
.setCoords(frame
.rect
.left() + frame
.margin
.left
,
1452 frame
.rect
.top() + frame
.margin
.top
,
1453 frame
.rect
.right() - frame
.margin
.right
,
1454 frame
.rect
.bottom() - frame
.margin
.bottom
);
1457 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
1464 redrawWindowFrame();
1466 frame
.rect
.setPos(dx
, dy
);
1468 XMoveWindow(blackbox
->getXDisplay(), frame
.window
,
1469 frame
.rect
.x(), frame
.rect
.y());
1471 we may have been called just after an opaque window move, so even though
1472 the old coords match the new ones no ConfigureNotify has been sent yet.
1473 There are likely other times when this will be relevant as well.
1475 if (! flags
.moving
) send_event
= True
;
1479 // if moving, the update and event will occur when the move finishes
1480 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1481 frame
.rect
.top() + frame
.margin
.top
);
1484 event
.type
= ConfigureNotify
;
1486 event
.xconfigure
.display
= blackbox
->getXDisplay();
1487 event
.xconfigure
.event
= client
.window
;
1488 event
.xconfigure
.window
= client
.window
;
1489 event
.xconfigure
.x
= client
.rect
.x();
1490 event
.xconfigure
.y
= client
.rect
.y();
1491 event
.xconfigure
.width
= client
.rect
.width();
1492 event
.xconfigure
.height
= client
.rect
.height();
1493 event
.xconfigure
.border_width
= client
.old_bw
;
1494 event
.xconfigure
.above
= frame
.window
;
1495 event
.xconfigure
.override_redirect
= False
;
1497 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1498 StructureNotifyMask
, &event
);
1499 screen
->updateNetizenConfigNotify(&event
);
1500 XFlush(blackbox
->getXDisplay());
1506 void BlackboxWindow::configureShape(void) {
1507 XShapeCombineShape(blackbox
->getXDisplay(), frame
.window
, ShapeBounding
,
1508 frame
.margin
.left
- frame
.border_w
,
1509 frame
.margin
.top
- frame
.border_w
,
1510 client
.window
, ShapeBounding
, ShapeSet
);
1513 XRectangle xrect
[2];
1515 if (decorations
& Decor_Titlebar
) {
1516 xrect
[0].x
= xrect
[0].y
= -frame
.border_w
;
1517 xrect
[0].width
= frame
.rect
.width();
1518 xrect
[0].height
= frame
.title_h
+ (frame
.border_w
* 2);
1522 if (decorations
& Decor_Handle
) {
1523 xrect
[1].x
= -frame
.border_w
;
1524 xrect
[1].y
= frame
.rect
.height() - frame
.margin
.bottom
+
1525 frame
.mwm_border_w
- frame
.border_w
;
1526 xrect
[1].width
= frame
.rect
.width();
1527 xrect
[1].height
= frame
.handle_h
+ (frame
.border_w
* 2);
1531 XShapeCombineRectangles(blackbox
->getXDisplay(), frame
.window
,
1532 ShapeBounding
, 0, 0, xrect
, num
,
1533 ShapeUnion
, Unsorted
);
1538 bool BlackboxWindow::setInputFocus(void) {
1539 if (flags
.focused
) return True
;
1541 assert(! flags
.iconic
&&
1542 (flags
.stuck
|| // window must be on the current workspace or sticky
1543 blackbox_attrib
.workspace
== screen
->getCurrentWorkspaceID()));
1546 We only do this check for normal windows and dialogs because other windows
1547 do this on purpose, such as kde's kicker, and we don't want to go moving
1550 if (window_type
== Type_Normal
|| window_type
== Type_Dialog
)
1551 if (! frame
.rect
.intersects(screen
->getRect())) {
1552 // client is outside the screen, move it to the center
1553 configure((screen
->getWidth() - frame
.rect
.width()) / 2,
1554 (screen
->getHeight() - frame
.rect
.height()) / 2,
1555 frame
.rect
.width(), frame
.rect
.height());
1558 if (client
.transientList
.size() > 0) {
1559 // transfer focus to any modal transients
1560 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1561 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1562 if ((*it
)->flags
.modal
) return (*it
)->setInputFocus();
1567 if (focus_mode
== F_LocallyActive
|| focus_mode
== F_Passive
) {
1568 XSetInputFocus(blackbox
->getXDisplay(), client
.window
,
1569 RevertToPointerRoot
, CurrentTime
);
1571 /* we could set the focus to none, since the window doesn't accept focus,
1572 * but we shouldn't set focus to nothing since this would surely make
1578 if (flags
.send_focus_message
) {
1580 ce
.xclient
.type
= ClientMessage
;
1581 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1582 ce
.xclient
.display
= blackbox
->getXDisplay();
1583 ce
.xclient
.window
= client
.window
;
1584 ce
.xclient
.format
= 32;
1585 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_take_focus
);
1586 ce
.xclient
.data
.l
[1] = blackbox
->getLastTime();
1587 ce
.xclient
.data
.l
[2] = 0l;
1588 ce
.xclient
.data
.l
[3] = 0l;
1589 ce
.xclient
.data
.l
[4] = 0l;
1590 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1592 XFlush(blackbox
->getXDisplay());
1599 void BlackboxWindow::iconify(void) {
1600 if (flags
.iconic
) return;
1602 // We don't need to worry about resizing because resizing always grabs the X
1603 // server. This should only ever happen if using opaque moving.
1607 if (windowmenu
) windowmenu
->hide();
1610 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1611 * we need to clear the event mask on client.window for a split second.
1612 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1613 * split second, leaving us with a ghost window... so, we need to do this
1614 * while the X server is grabbed
1616 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1617 StructureNotifyMask
;
1618 XGrabServer(blackbox
->getXDisplay());
1619 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1620 event_mask
& ~StructureNotifyMask
);
1621 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1622 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1623 XUngrabServer(blackbox
->getXDisplay());
1625 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1626 flags
.visible
= False
;
1627 flags
.iconic
= True
;
1629 setState(IconicState
);
1631 screen
->getWorkspace(blackbox_attrib
.workspace
)->removeWindow(this);
1633 if (isTransient()) {
1634 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1635 ! client
.transient_for
->flags
.iconic
) {
1636 // iconify our transient_for
1637 client
.transient_for
->iconify();
1641 screen
->addIcon(this);
1643 if (client
.transientList
.size() > 0) {
1644 // iconify all transients
1645 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1646 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1647 if (! (*it
)->flags
.iconic
) (*it
)->iconify();
1650 screen
->updateStackingList();
1654 void BlackboxWindow::show(void) {
1655 flags
.visible
= True
;
1656 flags
.iconic
= False
;
1658 current_state
= (flags
.shaded
) ? IconicState
: NormalState
;
1659 setState(current_state
);
1661 XMapWindow(blackbox
->getXDisplay(), client
.window
);
1662 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
1663 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
1668 XTranslateCoordinates(blackbox
->getXDisplay(), client
.window
,
1669 screen
->getRootWindow(),
1670 0, 0, &real_x
, &real_y
, &child
);
1671 fprintf(stderr
, "%s -- assumed: (%d, %d), real: (%d, %d)\n", getTitle(),
1672 client
.rect
.left(), client
.rect
.top(), real_x
, real_y
);
1673 assert(client
.rect
.left() == real_x
&& client
.rect
.top() == real_y
);
1678 void BlackboxWindow::deiconify(bool reassoc
, bool raise
) {
1679 if (flags
.iconic
|| reassoc
)
1680 screen
->reassociateWindow(this, BSENTINEL
, False
);
1681 else if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID())
1686 // reassociate and deiconify all transients
1687 if (reassoc
&& client
.transientList
.size() > 0) {
1688 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1689 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1690 (*it
)->deiconify(True
, False
);
1695 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1699 void BlackboxWindow::close(void) {
1701 ce
.xclient
.type
= ClientMessage
;
1702 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1703 ce
.xclient
.display
= blackbox
->getXDisplay();
1704 ce
.xclient
.window
= client
.window
;
1705 ce
.xclient
.format
= 32;
1706 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_delete_window
);
1707 ce
.xclient
.data
.l
[1] = CurrentTime
;
1708 ce
.xclient
.data
.l
[2] = 0l;
1709 ce
.xclient
.data
.l
[3] = 0l;
1710 ce
.xclient
.data
.l
[4] = 0l;
1711 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
, NoEventMask
, &ce
);
1712 XFlush(blackbox
->getXDisplay());
1716 void BlackboxWindow::withdraw(void) {
1717 // We don't need to worry about resizing because resizing always grabs the X
1718 // server. This should only ever happen if using opaque moving.
1722 flags
.visible
= False
;
1723 flags
.iconic
= False
;
1725 setState(current_state
);
1727 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1729 XGrabServer(blackbox
->getXDisplay());
1731 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1732 StructureNotifyMask
;
1733 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1734 event_mask
& ~StructureNotifyMask
);
1735 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1736 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1738 XUngrabServer(blackbox
->getXDisplay());
1740 if (windowmenu
) windowmenu
->hide();
1744 void BlackboxWindow::maximize(unsigned int button
) {
1745 // We don't need to worry about resizing because resizing always grabs the X
1746 // server. This should only ever happen if using opaque moving.
1750 // handle case where menu is open then the max button is used instead
1751 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
1753 if (flags
.maximized
) {
1754 flags
.maximized
= 0;
1756 blackbox_attrib
.flags
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1757 blackbox_attrib
.attrib
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1760 when a resize finishes, maximize(0) is called to clear any maximization
1761 flags currently set. Otherwise it still thinks it is maximized.
1762 so we do not need to call configure() because resizing will handle it
1764 if (! flags
.resizing
)
1765 configure(blackbox_attrib
.premax_x
, blackbox_attrib
.premax_y
,
1766 blackbox_attrib
.premax_w
, blackbox_attrib
.premax_h
);
1768 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
1769 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
1771 redrawAllButtons(); // in case it is not called in configure()
1772 setState(current_state
);
1776 blackbox_attrib
.premax_x
= frame
.rect
.x();
1777 blackbox_attrib
.premax_y
= frame
.rect
.y();
1778 blackbox_attrib
.premax_w
= frame
.rect
.width();
1779 // use client.rect so that clients can be restored even if shaded
1780 blackbox_attrib
.premax_h
=
1781 client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
;
1784 if (screen
->isXineramaActive() && blackbox
->doXineramaMaximizing()) {
1785 // find the area to use
1786 RectList availableAreas
= screen
->allAvailableAreas();
1787 RectList::iterator it
, end
= availableAreas
.end();
1789 for (it
= availableAreas
.begin(); it
!= end
; ++it
)
1790 if (it
->intersects(frame
.rect
)) break;
1791 if (it
== end
) // the window isn't inside an area
1792 it
= availableAreas
.begin(); // so just default to the first one
1794 frame
.changing
= *it
;
1797 frame
.changing
= screen
->availableArea();
1801 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1802 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1806 blackbox_attrib
.flags
|= AttribMaxVert
;
1807 blackbox_attrib
.attrib
|= AttribMaxVert
;
1809 frame
.changing
.setX(frame
.rect
.x());
1810 frame
.changing
.setWidth(frame
.rect
.width());
1814 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1815 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1817 frame
.changing
.setY(frame
.rect
.y());
1818 frame
.changing
.setHeight(frame
.rect
.height());
1825 blackbox_attrib
.flags
^= AttribShaded
;
1826 blackbox_attrib
.attrib
^= AttribShaded
;
1827 flags
.shaded
= False
;
1830 flags
.maximized
= button
;
1832 configure(frame
.changing
.x(), frame
.changing
.y(),
1833 frame
.changing
.width(), frame
.changing
.height());
1835 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1836 redrawAllButtons(); // in case it is not called in configure()
1837 setState(current_state
);
1841 // re-maximizes the window to take into account availableArea changes
1842 void BlackboxWindow::remaximize(void) {
1844 // we only update the window's attributes otherwise we lose the shade bit
1845 switch(flags
.maximized
) {
1847 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1848 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1852 blackbox_attrib
.flags
|= AttribMaxVert
;
1853 blackbox_attrib
.attrib
|= AttribMaxVert
;
1857 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1858 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1864 // save the original dimensions because maximize will wipe them out
1865 int premax_x
= blackbox_attrib
.premax_x
,
1866 premax_y
= blackbox_attrib
.premax_y
,
1867 premax_w
= blackbox_attrib
.premax_w
,
1868 premax_h
= blackbox_attrib
.premax_h
;
1870 unsigned int button
= flags
.maximized
;
1871 flags
.maximized
= 0; // trick maximize() into working
1874 // restore saved values
1875 blackbox_attrib
.premax_x
= premax_x
;
1876 blackbox_attrib
.premax_y
= premax_y
;
1877 blackbox_attrib
.premax_w
= premax_w
;
1878 blackbox_attrib
.premax_h
= premax_h
;
1882 void BlackboxWindow::setWorkspace(unsigned int n
) {
1883 blackbox_attrib
.flags
|= AttribWorkspace
;
1884 blackbox_attrib
.workspace
= n
;
1885 if (n
== BSENTINEL
) { // iconified window
1887 we set the workspace to 'all workspaces' so that taskbars will show the
1888 window. otherwise, it made uniconifying a window imposible without the
1889 blackbox workspace menu
1893 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
, n
);
1897 void BlackboxWindow::shade(void) {
1899 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1900 frame
.inside_w
, frame
.inside_h
);
1901 flags
.shaded
= False
;
1902 blackbox_attrib
.flags
^= AttribShaded
;
1903 blackbox_attrib
.attrib
^= AttribShaded
;
1905 setState(NormalState
);
1907 // set the frame rect to the normal size
1908 frame
.rect
.setHeight(client
.rect
.height() + frame
.margin
.top
+
1909 frame
.margin
.bottom
);
1911 if (! (decorations
& Decor_Titlebar
))
1912 return; // can't shade it without a titlebar!
1914 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1915 frame
.inside_w
, frame
.title_h
);
1916 flags
.shaded
= True
;
1917 blackbox_attrib
.flags
|= AttribShaded
;
1918 blackbox_attrib
.attrib
|= AttribShaded
;
1920 setState(IconicState
);
1922 // set the frame rect to the shaded size
1923 frame
.rect
.setHeight(frame
.title_h
+ (frame
.border_w
* 2));
1929 * (Un)Sticks a window and its relatives.
1931 void BlackboxWindow::stick(void) {
1933 blackbox_attrib
.flags
^= AttribOmnipresent
;
1934 blackbox_attrib
.attrib
^= AttribOmnipresent
;
1936 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
1937 if (i
!= blackbox_attrib
.workspace
)
1938 screen
->getWorkspace(i
)->removeWindow(this, True
);
1940 flags
.stuck
= False
;
1943 screen
->reassociateWindow(this, BSENTINEL
, True
);
1944 // temporary fix since sticky windows suck. set the hint to what we
1945 // actually hold in our data.
1946 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1947 blackbox_attrib
.workspace
);
1949 setState(current_state
);
1953 blackbox_attrib
.flags
|= AttribOmnipresent
;
1954 blackbox_attrib
.attrib
|= AttribOmnipresent
;
1956 // temporary fix since sticky windows suck. set the hint to a different
1957 // value than that contained in the class' data.
1958 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1961 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
1962 if (i
!= blackbox_attrib
.workspace
)
1963 screen
->getWorkspace(i
)->addWindow(this, False
, True
);
1965 setState(current_state
);
1968 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1969 client
.transient_for
->isStuck() != flags
.stuck
)
1970 client
.transient_for
->stick();
1971 // go down the chain
1972 BlackboxWindowList::iterator it
;
1973 const BlackboxWindowList::iterator end
= client
.transientList
.end();
1974 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1975 if ((*it
)->isStuck() != flags
.stuck
)
1980 void BlackboxWindow::redrawWindowFrame(void) const {
1981 if (decorations
& Decor_Titlebar
) {
1982 if (flags
.focused
) {
1984 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1985 frame
.title
, frame
.ftitle
);
1987 XSetWindowBackground(blackbox
->getXDisplay(),
1988 frame
.title
, frame
.ftitle_pixel
);
1991 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
1992 frame
.title
, frame
.utitle
);
1994 XSetWindowBackground(blackbox
->getXDisplay(),
1995 frame
.title
, frame
.utitle_pixel
);
1997 XClearWindow(blackbox
->getXDisplay(), frame
.title
);
2003 if (decorations
& Decor_Handle
) {
2004 if (flags
.focused
) {
2006 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2007 frame
.handle
, frame
.fhandle
);
2009 XSetWindowBackground(blackbox
->getXDisplay(),
2010 frame
.handle
, frame
.fhandle_pixel
);
2013 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2014 frame
.left_grip
, frame
.fgrip
);
2015 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2016 frame
.right_grip
, frame
.fgrip
);
2018 XSetWindowBackground(blackbox
->getXDisplay(),
2019 frame
.left_grip
, frame
.fgrip_pixel
);
2020 XSetWindowBackground(blackbox
->getXDisplay(),
2021 frame
.right_grip
, frame
.fgrip_pixel
);
2025 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2026 frame
.handle
, frame
.uhandle
);
2028 XSetWindowBackground(blackbox
->getXDisplay(),
2029 frame
.handle
, frame
.uhandle_pixel
);
2032 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2033 frame
.left_grip
, frame
.ugrip
);
2034 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2035 frame
.right_grip
, frame
.ugrip
);
2037 XSetWindowBackground(blackbox
->getXDisplay(),
2038 frame
.left_grip
, frame
.ugrip_pixel
);
2039 XSetWindowBackground(blackbox
->getXDisplay(),
2040 frame
.right_grip
, frame
.ugrip_pixel
);
2043 XClearWindow(blackbox
->getXDisplay(), frame
.handle
);
2044 XClearWindow(blackbox
->getXDisplay(), frame
.left_grip
);
2045 XClearWindow(blackbox
->getXDisplay(), frame
.right_grip
);
2048 if (decorations
& Decor_Border
) {
2050 XSetWindowBorder(blackbox
->getXDisplay(),
2051 frame
.plate
, frame
.fborder_pixel
);
2053 XSetWindowBorder(blackbox
->getXDisplay(),
2054 frame
.plate
, frame
.uborder_pixel
);
2059 void BlackboxWindow::setFocusFlag(bool focus
) {
2060 // only focus a window if it is visible
2061 if (focus
&& !flags
.visible
)
2064 flags
.focused
= focus
;
2066 redrawWindowFrame();
2068 if (screen
->isSloppyFocus() && screen
->doAutoRaise()) {
2069 if (isFocused()) timer
->start();
2074 blackbox
->setFocusedWindow(this);
2076 if (! flags
.iconic
) {
2077 // iconic windows arent in a workspace menu!
2079 screen
->getCurrentWorkspace()->setFocused(this, isFocused());
2081 screen
->getWorkspace(blackbox_attrib
.workspace
)->
2082 setFocused(this, flags
.focused
);
2087 void BlackboxWindow::installColormap(bool install
) {
2088 int i
= 0, ncmap
= 0;
2089 Colormap
*cmaps
= XListInstalledColormaps(blackbox
->getXDisplay(),
2090 client
.window
, &ncmap
);
2092 XWindowAttributes wattrib
;
2093 if (XGetWindowAttributes(blackbox
->getXDisplay(),
2094 client
.window
, &wattrib
)) {
2096 // install the window's colormap
2097 for (i
= 0; i
< ncmap
; i
++) {
2098 if (*(cmaps
+ i
) == wattrib
.colormap
)
2099 // this window is using an installed color map... do not install
2102 // otherwise, install the window's colormap
2104 XInstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2106 // uninstall the window's colormap
2107 for (i
= 0; i
< ncmap
; i
++) {
2108 if (*(cmaps
+ i
) == wattrib
.colormap
)
2109 // we found the colormap to uninstall
2110 XUninstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2120 void BlackboxWindow::setAllowedActions(void) {
2124 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_shade
);
2125 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_change_desktop
);
2126 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_close
);
2128 if (functions
& Func_Move
)
2129 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_move
);
2130 if (functions
& Func_Resize
)
2131 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_resize
);
2132 if (functions
& Func_Maximize
) {
2133 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_horz
);
2134 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_vert
);
2137 xatom
->setValue(client
.window
, XAtom::net_wm_allowed_actions
, XAtom::atom
,
2142 void BlackboxWindow::setState(unsigned long new_state
) {
2143 current_state
= new_state
;
2145 unsigned long state
[2];
2146 state
[0] = current_state
;
2148 xatom
->setValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
, state
, 2);
2150 xatom
->setValue(client
.window
, XAtom::blackbox_attributes
,
2151 XAtom::blackbox_attributes
, (unsigned long *)&blackbox_attrib
,
2152 PropBlackboxAttributesElements
);
2157 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_modal
);
2159 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_shaded
);
2161 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_hidden
);
2162 if (flags
.skip_taskbar
)
2163 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
);
2164 if (flags
.skip_pager
)
2165 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_pager
);
2166 if (flags
.fullscreen
)
2167 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_fullscreen
);
2168 if (flags
.maximized
== 1 || flags
.maximized
== 2)
2169 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_vert
);
2170 if (flags
.maximized
== 1 || flags
.maximized
== 3)
2171 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_horz
);
2172 xatom
->setValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
2177 bool BlackboxWindow::getState(void) {
2178 bool ret
= xatom
->getValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
,
2180 if (! ret
) current_state
= 0;
2185 void BlackboxWindow::restoreAttributes(void) {
2186 unsigned long num
= PropBlackboxAttributesElements
;
2187 BlackboxAttributes
*net
;
2188 if (! xatom
->getValue(client
.window
, XAtom::blackbox_attributes
,
2189 XAtom::blackbox_attributes
, num
,
2190 (unsigned long **)&net
))
2192 if (num
< PropBlackboxAttributesElements
) {
2197 if (net
->flags
& AttribShaded
&& net
->attrib
& AttribShaded
) {
2198 flags
.shaded
= False
;
2199 unsigned long orig_state
= current_state
;
2203 At this point in the life of a window, current_state should only be set
2204 to IconicState if the window was an *icon*, not if it was shaded.
2206 if (orig_state
!= IconicState
)
2207 current_state
= WithdrawnState
;
2210 if (net
->workspace
!= screen
->getCurrentWorkspaceID() &&
2211 net
->workspace
< screen
->getWorkspaceCount())
2212 screen
->reassociateWindow(this, net
->workspace
, True
);
2214 if ((blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID()) &&
2215 (blackbox_attrib
.workspace
< screen
->getWorkspaceCount())) {
2216 // set to WithdrawnState so it will be mapped on the new workspace
2217 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2218 } else if (current_state
== WithdrawnState
) {
2219 // the window is on this workspace and is Withdrawn, so it is waiting to
2221 current_state
= NormalState
;
2224 if (net
->flags
& AttribOmnipresent
&& net
->attrib
& AttribOmnipresent
) {
2225 flags
.stuck
= False
;
2228 // if the window was on another workspace, it was going to be hidden. this
2229 // specifies that the window should be mapped since it is sticky.
2230 if (current_state
== WithdrawnState
) current_state
= NormalState
;
2233 if (net
->flags
& AttribMaxHoriz
|| net
->flags
& AttribMaxVert
) {
2234 int x
= net
->premax_x
, y
= net
->premax_y
;
2235 unsigned int w
= net
->premax_w
, h
= net
->premax_h
;
2236 flags
.maximized
= 0;
2239 if ((net
->flags
& AttribMaxHoriz
) &&
2240 (net
->flags
& AttribMaxVert
))
2241 m
= (net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
2242 else if (net
->flags
& AttribMaxVert
)
2243 m
= (net
->attrib
& AttribMaxVert
) ? 2 : 0;
2244 else if (net
->flags
& AttribMaxHoriz
)
2245 m
= (net
->attrib
& AttribMaxHoriz
) ? 3 : 0;
2249 blackbox_attrib
.premax_x
= x
;
2250 blackbox_attrib
.premax_y
= y
;
2251 blackbox_attrib
.premax_w
= w
;
2252 blackbox_attrib
.premax_h
= h
;
2255 if (net
->flags
& AttribDecoration
) {
2256 switch (net
->decoration
) {
2264 decorations
|= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
2265 Decor_Iconify
| Decor_Maximize
;
2270 decorations
|= Decor_Titlebar
| Decor_Iconify
;
2271 decorations
&= ~(Decor_Border
| Decor_Handle
| Decor_Maximize
);
2276 decorations
|= Decor_Titlebar
;
2277 decorations
&= ~(Decor_Iconify
| Decor_Border
| Decor_Handle
);
2282 // sanity check the new decor
2283 if (! (functions
& Func_Resize
) || isTransient())
2284 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2285 if (! (functions
& Func_Maximize
))
2286 decorations
&= ~Decor_Maximize
;
2288 if (decorations
& Decor_Titlebar
) {
2289 if (functions
& Func_Close
) // close button is controlled by function
2290 decorations
|= Decor_Close
; // not decor type
2292 if (flags
.shaded
) // we can not be shaded if we lack a titlebar
2296 if (flags
.visible
&& frame
.window
) {
2297 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
2298 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
2302 setState(current_state
);
2305 // with the state set it will then be the map event's job to read the
2306 // window's state and behave accordingly
2313 * Positions the Rect r according the the client window position and
2316 void BlackboxWindow::applyGravity(Rect
&r
) {
2317 // apply horizontal window gravity
2318 switch (client
.win_gravity
) {
2320 case NorthWestGravity
:
2321 case SouthWestGravity
:
2323 r
.setX(client
.rect
.x());
2329 r
.setX(client
.rect
.x() - (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2332 case NorthEastGravity
:
2333 case SouthEastGravity
:
2335 r
.setX(client
.rect
.x() - frame
.margin
.left
- frame
.margin
.right
+ 2);
2340 r
.setX(client
.rect
.x() - frame
.margin
.left
);
2344 // apply vertical window gravity
2345 switch (client
.win_gravity
) {
2347 case NorthWestGravity
:
2348 case NorthEastGravity
:
2350 r
.setY(client
.rect
.y());
2356 r
.setY(client
.rect
.y() - (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2359 case SouthWestGravity
:
2360 case SouthEastGravity
:
2362 r
.setY(client
.rect
.y() - frame
.margin
.top
- frame
.margin
.bottom
+ 2);
2367 r
.setY(client
.rect
.y() - frame
.margin
.top
);
2374 * The reverse of the applyGravity function.
2376 * Positions the Rect r according to the frame window position and
2379 void BlackboxWindow::restoreGravity(Rect
&r
) {
2380 // restore horizontal window gravity
2381 switch (client
.win_gravity
) {
2383 case NorthWestGravity
:
2384 case SouthWestGravity
:
2386 r
.setX(frame
.rect
.x());
2392 r
.setX(frame
.rect
.x() + (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2395 case NorthEastGravity
:
2396 case SouthEastGravity
:
2398 r
.setX(frame
.rect
.x() + frame
.margin
.left
+ frame
.margin
.right
- 2);
2403 r
.setX(frame
.rect
.x() + frame
.margin
.left
);
2407 // restore vertical window gravity
2408 switch (client
.win_gravity
) {
2410 case NorthWestGravity
:
2411 case NorthEastGravity
:
2413 r
.setY(frame
.rect
.y());
2419 r
.setY(frame
.rect
.y() + (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2422 case SouthWestGravity
:
2423 case SouthEastGravity
:
2425 r
.setY(frame
.rect
.y() + frame
.margin
.top
+ frame
.margin
.bottom
- 2);
2430 r
.setY(frame
.rect
.y() + frame
.margin
.top
);
2436 void BlackboxWindow::redrawLabel(void) const {
2437 if (flags
.focused
) {
2439 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2440 frame
.label
, frame
.flabel
);
2442 XSetWindowBackground(blackbox
->getXDisplay(),
2443 frame
.label
, frame
.flabel_pixel
);
2446 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2447 frame
.label
, frame
.ulabel
);
2449 XSetWindowBackground(blackbox
->getXDisplay(),
2450 frame
.label
, frame
.ulabel_pixel
);
2452 XClearWindow(blackbox
->getXDisplay(), frame
.label
);
2454 WindowStyle
*style
= screen
->getWindowStyle();
2456 int pos
= frame
.bevel_w
* 2;
2457 style
->doJustify(client
.title
.c_str(), pos
, frame
.label_w
, frame
.bevel_w
* 4);
2458 style
->font
->drawString(frame
.label
, pos
, 1,
2459 (flags
.focused
? style
->l_text_focus
:
2460 style
->l_text_unfocus
),
2465 void BlackboxWindow::redrawAllButtons(void) const {
2466 if (frame
.iconify_button
) redrawIconifyButton(False
);
2467 if (frame
.maximize_button
) redrawMaximizeButton(flags
.maximized
);
2468 if (frame
.close_button
) redrawCloseButton(False
);
2472 void BlackboxWindow::redrawIconifyButton(bool pressed
) const {
2474 if (flags
.focused
) {
2476 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2477 frame
.iconify_button
, frame
.fbutton
);
2479 XSetWindowBackground(blackbox
->getXDisplay(),
2480 frame
.iconify_button
, frame
.fbutton_pixel
);
2483 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2484 frame
.iconify_button
, frame
.ubutton
);
2486 XSetWindowBackground(blackbox
->getXDisplay(), frame
.iconify_button
,
2487 frame
.ubutton_pixel
);
2491 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2492 frame
.iconify_button
, frame
.pbutton
);
2494 XSetWindowBackground(blackbox
->getXDisplay(),
2495 frame
.iconify_button
, frame
.pbutton_pixel
);
2497 XClearWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
2499 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2500 screen
->getWindowStyle()->b_pic_unfocus
);
2501 XDrawRectangle(blackbox
->getXDisplay(), frame
.iconify_button
, pen
.gc(),
2502 2, (frame
.button_w
- 5), (frame
.button_w
- 5), 2);
2506 void BlackboxWindow::redrawMaximizeButton(bool pressed
) const {
2508 if (flags
.focused
) {
2510 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2511 frame
.maximize_button
, frame
.fbutton
);
2513 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2514 frame
.fbutton_pixel
);
2517 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2518 frame
.maximize_button
, frame
.ubutton
);
2520 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2521 frame
.ubutton_pixel
);
2525 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2526 frame
.maximize_button
, frame
.pbutton
);
2528 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2529 frame
.pbutton_pixel
);
2531 XClearWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
2533 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2534 screen
->getWindowStyle()->b_pic_unfocus
);
2535 XDrawRectangle(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2536 2, 2, (frame
.button_w
- 5), (frame
.button_w
- 5));
2537 XDrawLine(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2538 2, 3, (frame
.button_w
- 3), 3);
2542 void BlackboxWindow::redrawCloseButton(bool pressed
) const {
2544 if (flags
.focused
) {
2546 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2549 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2550 frame
.fbutton_pixel
);
2553 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2556 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2557 frame
.ubutton_pixel
);
2561 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2562 frame
.close_button
, frame
.pbutton
);
2564 XSetWindowBackground(blackbox
->getXDisplay(),
2565 frame
.close_button
, frame
.pbutton_pixel
);
2567 XClearWindow(blackbox
->getXDisplay(), frame
.close_button
);
2569 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2570 screen
->getWindowStyle()->b_pic_unfocus
);
2571 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2572 2, 2, (frame
.button_w
- 3), (frame
.button_w
- 3));
2573 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2574 2, (frame
.button_w
- 3), (frame
.button_w
- 3), 2);
2578 void BlackboxWindow::mapRequestEvent(const XMapRequestEvent
*re
) {
2579 if (re
->window
!= client
.window
)
2583 fprintf(stderr
, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2587 switch (current_state
) {
2592 case WithdrawnState
:
2601 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2603 if (! blackbox
->isStartup()) {
2604 XSync(blackbox
->getXDisplay(), False
); // make sure the frame is mapped
2605 if (screen
->doFocusNew()|| (isTransient() && getTransientFor() &&
2606 getTransientFor()->isFocused())) {
2609 if (screen
->getPlacementPolicy() == BScreen::ClickMousePlacement
) {
2613 XQueryPointer(blackbox
->getXDisplay(), screen
->getRootWindow(),
2614 &r
, &c
, &rx
, &ry
, &x
, &y
, &m
);
2624 void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent
*ue
) {
2625 if (ue
->window
!= client
.window
)
2629 fprintf(stderr
, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2633 screen
->unmanageWindow(this, False
);
2637 void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent
*de
) {
2638 if (de
->window
!= client
.window
)
2642 fprintf(stderr
, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2646 screen
->unmanageWindow(this, False
);
2650 void BlackboxWindow::reparentNotifyEvent(const XReparentEvent
*re
) {
2651 if (re
->window
!= client
.window
|| re
->parent
== frame
.plate
)
2655 fprintf(stderr
, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2656 "0x%lx.\n", client
.window
, re
->parent
);
2661 XPutBackEvent(blackbox
->getXDisplay(), &ev
);
2662 screen
->unmanageWindow(this, True
);
2666 void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent
*pe
) {
2667 if (pe
->state
== PropertyDelete
)
2671 fprintf(stderr
, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n",
2677 case XA_WM_CLIENT_MACHINE
:
2681 case XA_WM_TRANSIENT_FOR
: {
2682 // determine if this is a transient window
2685 // adjust the window decorations based on transience
2686 if (isTransient()) {
2687 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2688 functions
&= ~Func_Maximize
;
2689 setAllowedActions();
2700 case XA_WM_ICON_NAME
:
2702 if (flags
.iconic
) screen
->propagateWindowName(this);
2705 case XAtom::net_wm_name
:
2709 if (decorations
& Decor_Titlebar
)
2712 screen
->propagateWindowName(this);
2715 case XA_WM_NORMAL_HINTS
: {
2718 if ((client
.normal_hint_flags
& PMinSize
) &&
2719 (client
.normal_hint_flags
& PMaxSize
)) {
2720 // the window now can/can't resize itself, so the buttons need to be
2723 if (client
.max_width
<= client
.min_width
&&
2724 client
.max_height
<= client
.min_height
) {
2725 decorations
&= ~(Decor_Maximize
| Decor_Handle
);
2726 functions
&= ~(Func_Resize
| Func_Maximize
);
2728 if (! isTransient()) {
2729 decorations
|= Decor_Maximize
| Decor_Handle
;
2730 functions
|= Func_Maximize
;
2732 functions
|= Func_Resize
;
2735 setAllowedActions();
2738 Rect old_rect
= frame
.rect
;
2742 if (old_rect
!= frame
.rect
)
2749 if (pe
->atom
== xatom
->getAtom(XAtom::wm_protocols
)) {
2752 if ((decorations
& Decor_Close
) && (! frame
.close_button
)) {
2753 createCloseButton();
2754 if (decorations
& Decor_Titlebar
) {
2755 positionButtons(True
);
2756 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
2758 if (windowmenu
) windowmenu
->reconfigure();
2760 } else if (pe
->atom
== xatom
->getAtom(XAtom::net_wm_strut
)) {
2769 void BlackboxWindow::exposeEvent(const XExposeEvent
*ee
) {
2771 fprintf(stderr
, "BlackboxWindow::exposeEvent() for 0x%lx\n", client
.window
);
2774 if (frame
.label
== ee
->window
&& (decorations
& Decor_Titlebar
))
2776 else if (frame
.close_button
== ee
->window
)
2777 redrawCloseButton(False
);
2778 else if (frame
.maximize_button
== ee
->window
)
2779 redrawMaximizeButton(flags
.maximized
);
2780 else if (frame
.iconify_button
== ee
->window
)
2781 redrawIconifyButton(False
);
2785 void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent
*cr
) {
2786 if (cr
->window
!= client
.window
|| flags
.iconic
)
2789 if (cr
->value_mask
& CWBorderWidth
)
2790 client
.old_bw
= cr
->border_width
;
2792 if (cr
->value_mask
& (CWX
| CWY
| CWWidth
| CWHeight
)) {
2793 Rect req
= frame
.rect
;
2795 if (cr
->value_mask
& (CWX
| CWY
)) {
2796 if (cr
->value_mask
& CWX
)
2797 client
.rect
.setX(cr
->x
);
2798 if (cr
->value_mask
& CWY
)
2799 client
.rect
.setY(cr
->y
);
2804 if (cr
->value_mask
& CWWidth
)
2805 req
.setWidth(cr
->width
+ frame
.margin
.left
+ frame
.margin
.right
);
2807 if (cr
->value_mask
& CWHeight
)
2808 req
.setHeight(cr
->height
+ frame
.margin
.top
+ frame
.margin
.bottom
);
2810 configure(req
.x(), req
.y(), req
.width(), req
.height());
2813 if (cr
->value_mask
& CWStackMode
&& !isDesktop()) {
2814 switch (cr
->detail
) {
2817 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2823 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2830 void BlackboxWindow::buttonPressEvent(const XButtonEvent
*be
) {
2832 fprintf(stderr
, "BlackboxWindow::buttonPressEvent() for 0x%lx\n",
2836 if (frame
.maximize_button
== be
->window
&& be
->button
<= 3) {
2837 redrawMaximizeButton(True
);
2838 } else if (be
->button
== 1 || (be
->button
== 3 && be
->state
== ModMask
)) {
2839 if (! flags
.focused
)
2842 if (frame
.iconify_button
== be
->window
) {
2843 redrawIconifyButton(True
);
2844 } else if (frame
.close_button
== be
->window
) {
2845 redrawCloseButton(True
);
2846 } else if (frame
.plate
== be
->window
) {
2847 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2849 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2851 XAllowEvents(blackbox
->getXDisplay(), ReplayPointer
, be
->time
);
2853 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
2854 if (((be
->time
- lastButtonPressTime
) <=
2855 blackbox
->getDoubleClickInterval()) ||
2856 (be
->state
== ControlMask
)) {
2857 lastButtonPressTime
= 0;
2860 lastButtonPressTime
= be
->time
;
2864 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2866 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2868 } else if (be
->button
== 2 && (be
->window
!= frame
.iconify_button
) &&
2869 (be
->window
!= frame
.close_button
)) {
2870 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2871 } else if (windowmenu
&& be
->button
== 3 &&
2872 (frame
.title
== be
->window
|| frame
.label
== be
->window
||
2873 frame
.handle
== be
->window
|| frame
.window
== be
->window
)) {
2874 if (windowmenu
->isVisible()) {
2877 int mx
= be
->x_root
- windowmenu
->getWidth() / 2,
2878 my
= be
->y_root
- windowmenu
->getHeight() / 2;
2880 // snap the window menu into a corner/side if necessary
2881 int left_edge
, right_edge
, top_edge
, bottom_edge
;
2884 the " + (frame.border_w * 2) - 1" bits are to get the proper width
2885 and height of the menu, as the sizes returned by it do not include
2888 left_edge
= frame
.rect
.x();
2889 right_edge
= frame
.rect
.right() -
2890 (windowmenu
->getWidth() + (frame
.border_w
* 2) - 1);
2891 top_edge
= client
.rect
.top() - (frame
.border_w
+ frame
.mwm_border_w
);
2892 bottom_edge
= client
.rect
.bottom() -
2893 (windowmenu
->getHeight() + (frame
.border_w
* 2) - 1) +
2894 (frame
.border_w
+ frame
.mwm_border_w
);
2898 if (mx
> right_edge
)
2902 if (my
> bottom_edge
)
2905 windowmenu
->move(mx
, my
);
2907 XRaiseWindow(blackbox
->getXDisplay(), windowmenu
->getWindowID());
2908 XRaiseWindow(blackbox
->getXDisplay(),
2909 windowmenu
->getSendToMenu()->getWindowID());
2912 } else if (be
->button
== 4) {
2913 if ((be
->window
== frame
.label
||
2914 be
->window
== frame
.title
||
2915 be
->window
== frame
.maximize_button
||
2916 be
->window
== frame
.iconify_button
||
2917 be
->window
== frame
.close_button
) &&
2921 } else if (be
->button
== 5) {
2922 if ((be
->window
== frame
.label
||
2923 be
->window
== frame
.title
||
2924 be
->window
== frame
.maximize_button
||
2925 be
->window
== frame
.iconify_button
||
2926 be
->window
== frame
.close_button
) &&
2933 void BlackboxWindow::buttonReleaseEvent(const XButtonEvent
*re
) {
2935 fprintf(stderr
, "BlackboxWindow::buttonReleaseEvent() for 0x%lx\n",
2939 if (re
->window
== frame
.maximize_button
&&
2940 re
->button
>= 1 && re
->button
<= 3) {
2941 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2942 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2943 maximize(re
->button
);
2945 redrawMaximizeButton(flags
.maximized
);
2947 } else if (re
->window
== frame
.iconify_button
&& re
->button
== 1) {
2948 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2949 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2952 redrawIconifyButton(False
);
2954 } else if (re
->window
== frame
.close_button
& re
->button
== 1) {
2955 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2956 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
)))
2958 redrawCloseButton(False
);
2959 } else if (flags
.moving
) {
2961 } else if (flags
.resizing
) {
2963 } else if (re
->window
== frame
.window
) {
2964 if (re
->button
== 2 && re
->state
== ModMask
)
2965 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
2971 void BlackboxWindow::beginMove(int x_root
, int y_root
) {
2972 assert(! (flags
.resizing
|| flags
.moving
));
2975 Only one window can be moved/resized at a time. If another window is already
2976 being moved or resized, then stop it before whating to work with this one.
2978 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
2979 if (changing
&& changing
!= this) {
2980 if (changing
->flags
.moving
)
2981 changing
->endMove();
2982 else // if (changing->flags.resizing)
2983 changing
->endResize();
2986 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
2987 PointerMotionMask
| ButtonReleaseMask
,
2988 GrabModeAsync
, GrabModeAsync
,
2989 None
, blackbox
->getMoveCursor(), CurrentTime
);
2991 if (windowmenu
&& windowmenu
->isVisible())
2994 flags
.moving
= True
;
2995 blackbox
->setChangingWindow(this);
2997 if (! screen
->doOpaqueMove()) {
2998 XGrabServer(blackbox
->getXDisplay());
3000 frame
.changing
= frame
.rect
;
3001 screen
->showPosition(frame
.changing
.x(), frame
.changing
.y());
3003 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3007 frame
.changing
.width() - 1,
3008 frame
.changing
.height() - 1);
3011 frame
.grab_x
= x_root
- frame
.rect
.x() - frame
.border_w
;
3012 frame
.grab_y
= y_root
- frame
.rect
.y() - frame
.border_w
;
3016 void BlackboxWindow::doMove(int x_root
, int y_root
) {
3017 assert(flags
.moving
);
3018 assert(blackbox
->getChangingWindow() == this);
3020 int dx
= x_root
- frame
.grab_x
, dy
= y_root
- frame
.grab_y
;
3021 dx
-= frame
.border_w
;
3022 dy
-= frame
.border_w
;
3024 if (screen
->doWorkspaceWarping()) {
3025 // workspace warping
3027 unsigned int dest
= screen
->getCurrentWorkspaceID();
3031 if (dest
> 0) dest
--;
3032 else dest
= screen
->getNumberOfWorkspaces() - 1;
3034 } else if (x_root
>= screen
->getRect().right()) {
3037 if (dest
< screen
->getNumberOfWorkspaces() - 1) dest
++;
3042 bool focus
= flags
.focused
; // had focus while moving?
3044 screen
->reassociateWindow(this, dest
, False
);
3045 screen
->changeWorkspaceID(dest
);
3050 If the XWarpPointer is done after the configure, we can end up
3051 grabbing another window, so made sure you do it first.
3055 dest_x
= screen
->getRect().right() - 1;
3056 XWarpPointer(blackbox
->getXDisplay(), None
,
3057 screen
->getRootWindow(), 0, 0, 0, 0,
3060 configure(dx
+ (screen
->getRect().width() - 1), dy
,
3061 frame
.rect
.width(), frame
.rect
.height());
3064 XWarpPointer(blackbox
->getXDisplay(), None
,
3065 screen
->getRootWindow(), 0, 0, 0, 0,
3068 configure(dx
- (screen
->getRect().width() - 1), dy
,
3069 frame
.rect
.width(), frame
.rect
.height());
3072 beginMove(dest_x
, y_root
);
3077 const int snap_distance
= screen
->getEdgeSnapThreshold();
3079 if (snap_distance
) {
3081 const int wleft
= dx
,
3082 wright
= dx
+ frame
.rect
.width() - 1,
3084 wbottom
= dy
+ frame
.rect
.height() - 1;
3086 if (screen
->getWindowToWindowSnap()) {
3087 Workspace
*w
= screen
->getWorkspace(getWorkspaceNumber());
3090 // try snap to another window
3091 for (unsigned int i
= 0, c
= w
->getCount(); i
< c
; ++i
) {
3092 BlackboxWindow
*snapwin
= w
->getWindow(i
);
3093 if (snapwin
== this)
3094 continue; // don't snap to self
3096 bool snapped
= False
;
3098 const Rect
&winrect
= snapwin
->frameRect();
3099 int dleft
= abs(wright
- winrect
.left()),
3100 dright
= abs(wleft
- winrect
.right()),
3101 dtop
= abs(wbottom
- winrect
.top()),
3102 dbottom
= abs(wtop
- winrect
.bottom());
3104 if (wtop
>= (signed)(winrect
.y() - frame
.rect
.height() + 1) &&
3105 wtop
< (signed)(winrect
.y() + winrect
.height() - 1)) {
3107 // snap left of other window?
3108 if (dleft
< snap_distance
&& dleft
<= dright
) {
3109 dx
= winrect
.left() - frame
.rect
.width();
3112 // snap right of other window?
3113 else if (dright
< snap_distance
) {
3114 dx
= winrect
.right() + 1;
3119 if (screen
->getWindowCornerSnap()) {
3120 // try corner-snap to its other sides
3121 dtop
= abs(wtop
- winrect
.top());
3122 dbottom
= abs(wbottom
- winrect
.bottom());
3123 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3125 else if (dbottom
< snap_distance
)
3126 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
3133 if (wleft
>= (signed)(winrect
.x() - frame
.rect
.width() + 1) &&
3134 wleft
< (signed)(winrect
.x() + winrect
.width() - 1)) {
3136 // snap top of other window?
3137 if (dtop
< snap_distance
&& dtop
<= dbottom
) {
3138 dy
= winrect
.top() - frame
.rect
.height();
3141 // snap bottom of other window?
3142 else if (dbottom
< snap_distance
) {
3143 dy
= winrect
.bottom() + 1;
3148 if (screen
->getWindowCornerSnap()) {
3149 // try corner-snap to its other sides
3150 dleft
= abs(wleft
- winrect
.left());
3151 dright
= abs(wright
- winrect
.right());
3152 if (dleft
< snap_distance
&& dleft
<= dright
)
3153 dx
= winrect
.left();
3154 else if (dright
< snap_distance
)
3155 dx
= winrect
.right() - frame
.rect
.width() + 1;
3164 RectList snaplist
; // the list of rects we will try to snap to
3166 // snap to the strut (and screen boundaries for xinerama)
3168 if (screen
->isXineramaActive() && blackbox
->doXineramaSnapping()) {
3169 if (! screen
->doFullMax())
3170 snaplist
.insert(snaplist
.begin(),
3171 screen
->allAvailableAreas().begin(),
3172 screen
->allAvailableAreas().end());
3174 // always snap to the screen edges
3175 snaplist
.insert(snaplist
.begin(),
3176 screen
->getXineramaAreas().begin(),
3177 screen
->getXineramaAreas().end());
3181 if (! screen
->doFullMax())
3182 snaplist
.push_back(screen
->availableArea());
3184 // always snap to the screen edges
3185 snaplist
.push_back(screen
->getRect());
3188 RectList::const_iterator it
, end
= snaplist
.end();
3189 for (it
= snaplist
.begin(); it
!= end
; ++it
) {
3190 const Rect
&srect
= *it
;
3192 // if we're not in the rectangle then don't snap to it.
3193 if (! srect
.intersects(Rect(wleft
, wtop
, frame
.rect
.width(),
3194 frame
.rect
.height())))
3197 int dleft
= abs(wleft
- srect
.left()),
3198 dright
= abs(wright
- srect
.right()),
3199 dtop
= abs(wtop
- srect
.top()),
3200 dbottom
= abs(wbottom
- srect
.bottom());
3203 if (dleft
< snap_distance
&& dleft
<= dright
)
3206 else if (dright
< snap_distance
)
3207 dx
= srect
.right() - frame
.rect
.width() + 1;
3210 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3213 else if (dbottom
< snap_distance
)
3214 dy
= srect
.bottom() - frame
.rect
.height() + 1;
3218 if (screen
->doOpaqueMove()) {
3219 configure(dx
, dy
, frame
.rect
.width(), frame
.rect
.height());
3221 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3225 frame
.changing
.width() - 1,
3226 frame
.changing
.height() - 1);
3228 frame
.changing
.setPos(dx
, dy
);
3230 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3234 frame
.changing
.width() - 1,
3235 frame
.changing
.height() - 1);
3238 screen
->showPosition(dx
, dy
);
3242 void BlackboxWindow::endMove(void) {
3243 assert(flags
.moving
);
3244 assert(blackbox
->getChangingWindow() == this);
3246 flags
.moving
= False
;
3247 blackbox
->setChangingWindow(0);
3249 if (! screen
->doOpaqueMove()) {
3250 /* when drawing the rubber band, we need to make sure we only draw inside
3251 * the frame... frame.changing_* contain the new coords for the window,
3252 * so we need to subtract 1 from changing_w/changing_h every where we
3253 * draw the rubber band (for both moving and resizing)
3255 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3256 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3257 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3258 XUngrabServer(blackbox
->getXDisplay());
3260 configure(frame
.changing
.x(), frame
.changing
.y(),
3261 frame
.changing
.width(), frame
.changing
.height());
3263 configure(frame
.rect
.x(), frame
.rect
.y(),
3264 frame
.rect
.width(), frame
.rect
.height());
3266 screen
->hideGeometry();
3268 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3270 // if there are any left over motions from the move, drop them now
3271 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3273 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3278 void BlackboxWindow::beginResize(int x_root
, int y_root
, Corner dir
) {
3279 assert(! (flags
.resizing
|| flags
.moving
));
3282 Only one window can be moved/resized at a time. If another window is already
3283 being moved or resized, then stop it before whating to work with this one.
3285 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3286 if (changing
&& changing
!= this) {
3287 if (changing
->flags
.moving
)
3288 changing
->endMove();
3289 else // if (changing->flags.resizing)
3290 changing
->endResize();
3298 switch (resize_dir
) {
3301 cursor
= blackbox
->getLowerLeftAngleCursor();
3306 cursor
= blackbox
->getLowerRightAngleCursor();
3310 anchor
= BottomRight
;
3311 cursor
= blackbox
->getUpperLeftAngleCursor();
3315 anchor
= BottomLeft
;
3316 cursor
= blackbox
->getUpperRightAngleCursor();
3320 assert(false); // unhandled Corner
3321 return; // unreachable, for the compiler
3324 XGrabServer(blackbox
->getXDisplay());
3325 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3326 PointerMotionMask
| ButtonReleaseMask
,
3327 GrabModeAsync
, GrabModeAsync
, None
, cursor
, CurrentTime
);
3329 flags
.resizing
= True
;
3330 blackbox
->setChangingWindow(this);
3333 frame
.changing
= frame
.rect
;
3335 constrain(anchor
, &gw
, &gh
);
3337 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3338 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3339 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3341 screen
->showGeometry(gw
, gh
);
3343 frame
.grab_x
= x_root
;
3344 frame
.grab_y
= y_root
;
3348 void BlackboxWindow::doResize(int x_root
, int y_root
) {
3349 assert(flags
.resizing
);
3350 assert(blackbox
->getChangingWindow() == this);
3352 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3353 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3354 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3359 switch (resize_dir
) {
3362 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3363 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3367 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3368 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3371 anchor
= BottomRight
;
3372 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3373 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3376 anchor
= BottomLeft
;
3377 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3378 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3382 assert(false); // unhandled Corner
3383 return; // unreachable, for the compiler
3386 constrain(anchor
, &gw
, &gh
);
3388 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3389 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3390 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3392 screen
->showGeometry(gw
, gh
);
3396 void BlackboxWindow::endResize(void) {
3397 assert(flags
.resizing
);
3398 assert(blackbox
->getChangingWindow() == this);
3400 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3401 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3402 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3403 XUngrabServer(blackbox
->getXDisplay());
3405 // unset maximized state after resized when fully maximized
3406 if (flags
.maximized
== 1)
3409 flags
.resizing
= False
;
3410 blackbox
->setChangingWindow(0);
3412 configure(frame
.changing
.x(), frame
.changing
.y(),
3413 frame
.changing
.width(), frame
.changing
.height());
3414 screen
->hideGeometry();
3416 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3418 // if there are any left over motions from the resize, drop them now
3419 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3421 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3426 void BlackboxWindow::motionNotifyEvent(const XMotionEvent
*me
) {
3428 fprintf(stderr
, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n",
3433 doMove(me
->x_root
, me
->y_root
);
3434 } else if (flags
.resizing
) {
3435 doResize(me
->x_root
, me
->y_root
);
3437 if (!flags
.resizing
&& me
->state
& Button1Mask
&& (functions
& Func_Move
) &&
3438 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3439 frame
.handle
== me
->window
|| frame
.window
== me
->window
)) {
3440 beginMove(me
->x_root
, me
->y_root
);
3441 } else if ((functions
& Func_Resize
) &&
3442 (me
->state
& Button1Mask
&& (me
->window
== frame
.right_grip
||
3443 me
->window
== frame
.left_grip
)) ||
3444 (me
->state
& Button3Mask
&& me
->state
& ModMask
&&
3445 me
->window
== frame
.window
)) {
3446 unsigned int zones
= screen
->getResizeZones();
3449 if (me
->window
== frame
.left_grip
) {
3450 corner
= BottomLeft
;
3451 } else if (me
->window
== frame
.right_grip
|| zones
== 1) {
3452 corner
= BottomRight
;
3455 bool left
= (me
->x_root
- frame
.rect
.x() <=
3456 static_cast<signed>(frame
.rect
.width() / 2));
3459 else // (zones == 4)
3460 top
= (me
->y_root
- frame
.rect
.y() <=
3461 static_cast<signed>(frame
.rect
.height() / 2));
3462 corner
= (top
? (left
? TopLeft
: TopRight
) :
3463 (left
? BottomLeft
: BottomRight
));
3466 beginResize(me
->x_root
, me
->y_root
, corner
);
3473 void BlackboxWindow::shapeEvent(XShapeEvent
*) {
3474 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
3481 bool BlackboxWindow::validateClient(void) const {
3482 XSync(blackbox
->getXDisplay(), False
);
3485 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3486 DestroyNotify
, &e
) ||
3487 XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3489 XPutBackEvent(blackbox
->getXDisplay(), &e
);
3498 void BlackboxWindow::restore(bool remap
) {
3499 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeDelete
);
3500 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
3501 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, NoEventMask
);
3503 // do not leave a shaded window as an icon unless it was an icon
3504 if (flags
.shaded
&& ! flags
.iconic
)
3505 setState(NormalState
);
3507 restoreGravity(client
.rect
);
3509 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
3510 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
3512 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, client
.old_bw
);
3515 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3516 ReparentNotify
, &ev
)) {
3519 // according to the ICCCM - if the client doesn't reparent to
3520 // root, then we have to do it for them
3521 XReparentWindow(blackbox
->getXDisplay(), client
.window
,
3522 screen
->getRootWindow(),
3523 client
.rect
.x(), client
.rect
.y());
3526 if (remap
) XMapWindow(blackbox
->getXDisplay(), client
.window
);
3530 // timer for autoraise
3531 void BlackboxWindow::timeout(void) {
3532 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3536 void BlackboxWindow::changeBlackboxHints(const BlackboxHints
*net
) {
3537 if ((net
->flags
& AttribShaded
) &&
3538 ((blackbox_attrib
.attrib
& AttribShaded
) !=
3539 (net
->attrib
& AttribShaded
)))
3542 if (flags
.visible
&& // watch out for requests when we can not be seen
3543 (net
->flags
& (AttribMaxVert
| AttribMaxHoriz
)) &&
3544 ((blackbox_attrib
.attrib
& (AttribMaxVert
| AttribMaxHoriz
)) !=
3545 (net
->attrib
& (AttribMaxVert
| AttribMaxHoriz
)))) {
3546 if (flags
.maximized
) {
3551 if ((net
->flags
& AttribMaxHoriz
) && (net
->flags
& AttribMaxVert
))
3552 button
= ((net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0);
3553 else if (net
->flags
& AttribMaxVert
)
3554 button
= ((net
->attrib
& AttribMaxVert
) ? 2 : 0);
3555 else if (net
->flags
& AttribMaxHoriz
)
3556 button
= ((net
->attrib
& AttribMaxHoriz
) ? 3 : 0);
3562 if ((net
->flags
& AttribOmnipresent
) &&
3563 ((blackbox_attrib
.attrib
& AttribOmnipresent
) !=
3564 (net
->attrib
& AttribOmnipresent
)))
3567 if ((net
->flags
& AttribWorkspace
) &&
3568 (blackbox_attrib
.workspace
!= net
->workspace
)) {
3569 screen
->reassociateWindow(this, net
->workspace
, True
);
3571 if (screen
->getCurrentWorkspaceID() != net
->workspace
) {
3575 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3579 if (net
->flags
& AttribDecoration
) {
3580 switch (net
->decoration
) {
3588 decorations
|= Decor_Titlebar
| Decor_Border
| Decor_Iconify
;
3590 decorations
= ((functions
& Func_Resize
) && !isTransient() ?
3591 decorations
| Decor_Handle
:
3592 decorations
&= ~Decor_Handle
);
3593 decorations
= (functions
& Func_Maximize
?
3594 decorations
| Decor_Maximize
:
3595 decorations
&= ~Decor_Maximize
);
3600 decorations
|= Decor_Titlebar
| Decor_Iconify
;
3601 decorations
&= ~(Decor_Border
| Decor_Handle
);
3603 decorations
= (functions
& Func_Maximize
?
3604 decorations
| Decor_Maximize
:
3605 decorations
&= ~Decor_Maximize
);
3610 decorations
|= Decor_Titlebar
;
3611 decorations
&= ~(Decor_Iconify
| Decor_Border
);
3613 decorations
= ((functions
& Func_Resize
) && !isTransient() ?
3614 decorations
| Decor_Handle
:
3615 decorations
&= ~Decor_Handle
);
3616 decorations
= (functions
& Func_Maximize
?
3617 decorations
| Decor_Maximize
:
3618 decorations
&= ~Decor_Maximize
);
3623 // we can not be shaded if we lack a titlebar
3624 if (flags
.shaded
&& ! (decorations
& Decor_Titlebar
))
3627 if (flags
.visible
&& frame
.window
) {
3628 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
3629 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
3633 setState(current_state
);
3639 * Set the sizes of all components of the window frame
3640 * (the window decorations).
3641 * These values are based upon the current style settings and the client
3642 * window's dimensions.
3644 void BlackboxWindow::upsize(void) {
3645 frame
.bevel_w
= screen
->getBevelWidth();
3647 if (decorations
& Decor_Border
) {
3648 frame
.border_w
= screen
->getBorderWidth();
3649 if (! isTransient())
3650 frame
.mwm_border_w
= screen
->getFrameWidth();
3652 frame
.mwm_border_w
= 0;
3654 frame
.mwm_border_w
= frame
.border_w
= 0;
3657 if (decorations
& Decor_Titlebar
) {
3658 // the height of the titlebar is based upon the height of the font being
3659 // used to display the window's title
3660 WindowStyle
*style
= screen
->getWindowStyle();
3661 frame
.title_h
= style
->font
->height() + (frame
.bevel_w
* 2) + 2;
3663 frame
.label_h
= frame
.title_h
- (frame
.bevel_w
* 2);
3664 frame
.button_w
= (frame
.label_h
- 2);
3666 // set the top frame margin
3667 frame
.margin
.top
= frame
.border_w
+ frame
.title_h
+
3668 frame
.border_w
+ frame
.mwm_border_w
;
3674 // set the top frame margin
3675 frame
.margin
.top
= frame
.border_w
+ frame
.mwm_border_w
;
3678 // set the left/right frame margin
3679 frame
.margin
.left
= frame
.margin
.right
= frame
.border_w
+ frame
.mwm_border_w
;
3681 if (decorations
& Decor_Handle
) {
3682 frame
.grip_w
= frame
.button_w
* 2;
3683 frame
.handle_h
= screen
->getHandleWidth();
3685 // set the bottom frame margin
3686 frame
.margin
.bottom
= frame
.border_w
+ frame
.handle_h
+
3687 frame
.border_w
+ frame
.mwm_border_w
;
3692 // set the bottom frame margin
3693 frame
.margin
.bottom
= frame
.border_w
+ frame
.mwm_border_w
;
3697 We first get the normal dimensions and use this to define the inside_w/h
3698 then we modify the height if shading is in effect.
3699 If the shade state is not considered then frame.rect gets reset to the
3700 normal window size on a reconfigure() call resulting in improper
3701 dimensions appearing in move/resize and other events.
3704 height
= client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
,
3705 width
= client
.rect
.width() + frame
.margin
.left
+ frame
.margin
.right
;
3707 frame
.inside_w
= width
- (frame
.border_w
* 2);
3708 frame
.inside_h
= height
- (frame
.border_w
* 2);
3711 height
= frame
.title_h
+ (frame
.border_w
* 2);
3712 frame
.rect
.setSize(width
, height
);
3717 * Calculate the size of the client window and constrain it to the
3718 * size specified by the size hints of the client window.
3720 * The logical width and height are placed into pw and ph, if they
3721 * are non-zero. Logical size refers to the users perception of
3722 * the window size (for example an xterm resizes in cells, not in pixels).
3724 * The physical geometry is placed into frame.changing_{x,y,width,height}.
3725 * Physical geometry refers to the geometry of the window in pixels.
3727 void BlackboxWindow::constrain(Corner anchor
, int *pw
, int *ph
) {
3728 // frame.changing represents the requested frame size, we need to
3729 // strip the frame margin off and constrain the client size
3730 frame
.changing
.setCoords(frame
.changing
.left() + frame
.margin
.left
,
3731 frame
.changing
.top() + frame
.margin
.top
,
3732 frame
.changing
.right() - frame
.margin
.right
,
3733 frame
.changing
.bottom() - frame
.margin
.bottom
);
3735 int dw
= frame
.changing
.width(), dh
= frame
.changing
.height(),
3736 base_width
= (client
.base_width
) ? client
.base_width
: client
.min_width
,
3737 base_height
= (client
.base_height
) ? client
.base_height
:
3741 if (dw
< static_cast<signed>(client
.min_width
)) dw
= client
.min_width
;
3742 if (dh
< static_cast<signed>(client
.min_height
)) dh
= client
.min_height
;
3743 if (dw
> static_cast<signed>(client
.max_width
)) dw
= client
.max_width
;
3744 if (dh
> static_cast<signed>(client
.max_height
)) dh
= client
.max_height
;
3747 dw
/= client
.width_inc
;
3749 dh
/= client
.height_inc
;
3752 if (client
.width_inc
== 1)
3753 *pw
= dw
+ base_width
;
3758 if (client
.height_inc
== 1)
3759 *ph
= dh
+ base_height
;
3764 dw
*= client
.width_inc
;
3766 dh
*= client
.height_inc
;
3769 frame
.changing
.setSize(dw
, dh
);
3771 // add the frame margin back onto frame.changing
3772 frame
.changing
.setCoords(frame
.changing
.left() - frame
.margin
.left
,
3773 frame
.changing
.top() - frame
.margin
.top
,
3774 frame
.changing
.right() + frame
.margin
.right
,
3775 frame
.changing
.bottom() + frame
.margin
.bottom
);
3777 // move frame.changing to the specified anchor
3785 dx
= frame
.rect
.right() - frame
.changing
.right();
3789 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3793 dx
= frame
.rect
.right() - frame
.changing
.right();
3794 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3798 assert(false); // unhandled corner
3800 frame
.changing
.setPos(frame
.changing
.x() + dx
, frame
.changing
.y() + dy
);
3804 void WindowStyle::doJustify(const std::string
&text
, int &start_pos
,
3805 unsigned int max_length
,
3806 unsigned int modifier
) const {
3807 size_t text_len
= text
.size();
3808 unsigned int length
;
3811 length
= font
->measureString(string(text
, 0, text_len
)) + modifier
;
3812 } while (length
> max_length
&& text_len
-- > 0);
3816 start_pos
+= max_length
- length
;
3820 start_pos
+= (max_length
- length
) / 2;
3830 BWindowGroup::BWindowGroup(Blackbox
*b
, Window _group
)
3831 : blackbox(b
), group(_group
) {
3832 XWindowAttributes wattrib
;
3833 if (! XGetWindowAttributes(blackbox
->getXDisplay(), group
, &wattrib
)) {
3834 // group window doesn't seem to exist anymore
3839 XSelectInput(blackbox
->getXDisplay(), group
,
3840 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
3842 blackbox
->saveGroupSearch(group
, this);
3846 BWindowGroup::~BWindowGroup(void) {
3847 blackbox
->removeGroupSearch(group
);
3852 BWindowGroup::find(BScreen
*screen
, bool allow_transients
) const {
3853 BlackboxWindow
*ret
= blackbox
->getFocusedWindow();
3855 // does the focus window match (or any transient_fors)?
3857 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3858 if (ret
->isTransient() && allow_transients
) break;
3859 else if (! ret
->isTransient()) break;
3862 ret
= ret
->getTransientFor();
3865 if (ret
) return ret
;
3867 // the focus window didn't match, look in the group's window list
3868 BlackboxWindowList::const_iterator it
, end
= windowList
.end();
3869 for (it
= windowList
.begin(); it
!= end
; ++it
) {
3871 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
) {
3872 if (ret
->isTransient() && allow_transients
) break;
3873 else if (! ret
->isTransient()) break;