1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2 // Window.cc for Blackbox - an X11 Window manager
3 // Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry <shaleh at debian.org>
4 // Copyright (c) 1997 - 2000, 2002 Brad Hughes <bhughes at trolltech.com>
6 // Permission is hereby granted, free of charge, to any person obtaining a
7 // copy of this software and associated documentation files (the "Software"),
8 // to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 // and/or sell copies of the Software, and to permit persons to whom the
11 // Software is furnished to do so, subject to the following conditions:
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 // DEALINGS IN THE SOFTWARE.
25 # include "../config.h"
26 #endif // HAVE_CONFIG_H
29 #include <X11/Xatom.h>
30 #include <X11/keysym.h>
34 #endif // HAVE_STRING_H
39 # endif // HAVE_STDIO_H
44 #endif // HAVE_STDLIB_H
48 #include "blackbox.hh"
49 #include "Clientmenu.hh"
52 #include "Iconmenu.hh"
58 #include "Windowmenu.hh"
59 #include "Workspace.hh"
65 // change this to change what modifier keys openbox uses for mouse bindings
66 // for example: Mod1Mask | ControlMask
67 // or: ControlMask| ShiftMask
68 const unsigned int ModMask
= Mod1Mask
;
71 * Initializes the class with default values/the window's set initial values.
73 BlackboxWindow::BlackboxWindow(Blackbox
*b
, Window w
, BScreen
*s
) {
74 // fprintf(stderr, "BlackboxWindow size: %d bytes\n",
75 // sizeof(BlackboxWindow));
78 fprintf(stderr
, "BlackboxWindow::BlackboxWindow(): creating 0x%lx\n", w
);
82 set timer to zero... it is initialized properly later, so we check
83 if timer is zero in the destructor, and assume that the window is not
84 fully constructed if timer is zero...
90 xatom
= blackbox
->getXAtom();
92 if (! validateClient()) {
97 // fetch client size and placement
98 XWindowAttributes wattrib
;
99 if (! XGetWindowAttributes(blackbox
->getXDisplay(),
100 client
.window
, &wattrib
) ||
101 ! wattrib
.screen
|| wattrib
.override_redirect
) {
104 "BlackboxWindow::BlackboxWindow(): XGetWindowAttributes failed\n");
111 // set the eventmask early in the game so that we make sure we get
112 // all the events we are interested in
113 XSetWindowAttributes attrib_set
;
114 attrib_set
.event_mask
= PropertyChangeMask
| FocusChangeMask
|
116 attrib_set
.do_not_propagate_mask
= ButtonPressMask
| ButtonReleaseMask
|
118 XChangeWindowAttributes(blackbox
->getXDisplay(), client
.window
,
119 CWEventMask
|CWDontPropagate
, &attrib_set
);
121 flags
.moving
= flags
.resizing
= flags
.shaded
= flags
.visible
=
122 flags
.iconic
= flags
.focused
= flags
.stuck
= flags
.modal
=
123 flags
.send_focus_message
= flags
.shaped
= flags
.skip_taskbar
=
124 flags
.skip_pager
= flags
.fullscreen
= False
;
127 blackbox_attrib
.workspace
= window_number
= BSENTINEL
;
129 blackbox_attrib
.flags
= blackbox_attrib
.attrib
= blackbox_attrib
.stack
130 = blackbox_attrib
.decoration
= 0l;
131 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
132 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
135 frame
.window
= frame
.plate
= frame
.title
= frame
.handle
= None
;
136 frame
.close_button
= frame
.iconify_button
= frame
.maximize_button
= None
;
137 frame
.right_grip
= frame
.left_grip
= None
;
139 frame
.ulabel_pixel
= frame
.flabel_pixel
= frame
.utitle_pixel
=
140 frame
.ftitle_pixel
= frame
.uhandle_pixel
= frame
.fhandle_pixel
=
141 frame
.ubutton_pixel
= frame
.fbutton_pixel
= frame
.pbutton_pixel
=
142 frame
.uborder_pixel
= frame
.fborder_pixel
= frame
.ugrip_pixel
=
143 frame
.fgrip_pixel
= 0;
144 frame
.utitle
= frame
.ftitle
= frame
.uhandle
= frame
.fhandle
= None
;
145 frame
.ulabel
= frame
.flabel
= frame
.ubutton
= frame
.fbutton
= None
;
146 frame
.pbutton
= frame
.ugrip
= frame
.fgrip
= None
;
148 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
149 mwm_decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
150 Decor_Iconify
| Decor_Maximize
| Decor_Close
;
152 client
.normal_hint_flags
= 0;
153 client
.window_group
= None
;
154 client
.transient_for
= 0;
156 current_state
= NormalState
;
161 get the initial size and location of client window (relative to the
162 _root window_). This position is the reference point used with the
163 window's gravity to find the window's initial position.
165 client
.rect
.setRect(wattrib
.x
, wattrib
.y
, wattrib
.width
, wattrib
.height
);
166 client
.old_bw
= wattrib
.border_width
;
168 lastButtonPressTime
= 0;
170 timer
= new BTimer(blackbox
, this);
171 timer
->setTimeout(blackbox
->getAutoRaiseDelay());
173 // get size, aspect, minimum/maximum size and other hints set by the
176 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
196 if (getWindowType()) {
197 // adjust the window decorations/behavior based on the window type
198 switch (window_type
) {
202 blackbox_attrib
.workspace
= 0; // we do need to belong to a workspace
203 flags
.stuck
= True
; // we show up on all workspaces
205 // none of these windows are manipulated by the window manager
211 // these windows get less functionality
212 functions
&= ~(Func_Maximize
| Func_Resize
| Func_Iconify
);
216 // dialogs cannot be maximized
217 functions
&= ~Func_Maximize
;
221 // normal windows retain all of the possible decorations and functionality
228 // further adjeust the window's decorations/behavior based on window sizes
229 if ((client
.normal_hint_flags
& PMinSize
) &&
230 (client
.normal_hint_flags
& PMaxSize
) &&
231 client
.max_width
<= client
.min_width
&&
232 client
.max_height
<= client
.min_height
) {
233 functions
&= ~(Func_Resize
| Func_Maximize
);
240 if (decorations
& Decor_Titlebar
)
243 if (decorations
& Decor_Handle
)
246 // apply the size and gravity hint to the frame
250 bool place_window
= True
;
251 if (blackbox
->isStartup() || isTransient() ||
252 client
.normal_hint_flags
& (PPosition
|USPosition
)) {
253 applyGravity(frame
.rect
);
255 if (blackbox
->isStartup() || client
.rect
.intersects(screen
->getRect()))
256 place_window
= False
;
259 // add the window's strut. note this is done *after* placing the window.
260 screen
->addStrut(&client
.strut
);
264 the server needs to be grabbed here to prevent client's from sending
265 events while we are in the process of configuring their window.
266 We hold the grab until after we are done moving the window around.
269 XGrabServer(blackbox
->getXDisplay());
271 associateClientWindow();
273 blackbox
->saveWindowSearch(client
.window
, this);
275 if (blackbox_attrib
.workspace
>= screen
->getWorkspaceCount())
276 screen
->getCurrentWorkspace()->addWindow(this, place_window
);
278 screen
->getWorkspace(blackbox_attrib
.workspace
)->
279 addWindow(this, place_window
);
281 if (! place_window
) {
282 // don't need to call configure if we are letting the workspace
284 configure(frame
.rect
.x(), frame
.rect
.y(),
285 frame
.rect
.width(), frame
.rect
.height());
291 XUngrabServer(blackbox
->getXDisplay());
294 if (blackbox
->hasShapeExtensions() && flags
.shaped
)
298 // now that we know where to put the window and what it should look like
299 // we apply the decorations
304 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
306 // this ensures the title, buttons, and other decor are properly displayed
309 // preserve the window's initial state on first map, and its current state
311 unsigned long initial_state
= current_state
;
313 current_state
= initial_state
;
315 // get sticky state from our parent window if we've got one
316 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
317 client
.transient_for
->isStuck() != flags
.stuck
)
321 flags
.shaded
= False
;
322 initial_state
= current_state
;
326 At this point in the life of a window, current_state should only be set
327 to IconicState if the window was an *icon*, not if it was shaded.
329 if (initial_state
!= IconicState
)
330 current_state
= NormalState
;
338 if (flags
.maximized
&& (functions
& Func_Maximize
))
341 // create this last so it only needs to be configured once
342 windowmenu
= new Windowmenu(this);
346 BlackboxWindow::~BlackboxWindow(void) {
348 fprintf(stderr
, "BlackboxWindow::~BlackboxWindow: destroying 0x%lx\n",
352 if (! timer
) // window not managed...
358 screen
->removeStrut(&client
.strut
);
359 screen
->updateAvailableArea();
361 // We don't need to worry about resizing because resizing always grabs the X
362 // server. This should only ever happen if using opaque moving.
370 if (client
.window_group
) {
371 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
372 if (group
) group
->removeWindow(this);
375 // remove ourselves from our transient_for
377 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul)
378 client
.transient_for
->client
.transientList
.remove(this);
379 client
.transient_for
= (BlackboxWindow
*) 0;
382 if (client
.transientList
.size() > 0) {
383 // reset transient_for for all transients
384 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
385 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
386 (*it
)->client
.transient_for
= (BlackboxWindow
*) 0;
396 blackbox
->removeWindowSearch(frame
.plate
);
397 XDestroyWindow(blackbox
->getXDisplay(), frame
.plate
);
401 blackbox
->removeWindowSearch(frame
.window
);
402 XDestroyWindow(blackbox
->getXDisplay(), frame
.window
);
405 blackbox
->removeWindowSearch(client
.window
);
409 void BlackboxWindow::enableDecor(bool enable
) {
411 // start with everything on
413 (mwm_decorations
& Decor_Titlebar
? Decor_Titlebar
: 0) |
414 (mwm_decorations
& Decor_Border
? Decor_Border
: 0) |
415 (mwm_decorations
& Decor_Handle
? Decor_Handle
: 0) |
416 (mwm_decorations
& Decor_Iconify
? Decor_Iconify
: 0) |
417 (mwm_decorations
& Decor_Maximize
? Decor_Maximize
: 0) |
418 (mwm_decorations
& Decor_Close
? Decor_Close
: 0);
420 if (! (functions
& Func_Close
)) decorations
&= ~Decor_Close
;
421 if (! (functions
& Func_Maximize
)) decorations
&= ~Decor_Maximize
;
422 if (! (functions
& Func_Iconify
)) decorations
&= ~Decor_Iconify
;
423 if (! (functions
& Func_Resize
)) decorations
&= ~Decor_Handle
;
425 switch (window_type
) {
430 // none of these windows are decorated by the window manager at all
436 decorations
&= ~(Decor_Border
);
440 decorations
&= ~Decor_Handle
;
452 * Creates a new top level window, with a given location, size, and border
454 * Returns: the newly created window
456 Window
BlackboxWindow::createToplevelWindow(void) {
457 XSetWindowAttributes attrib_create
;
458 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
| CWColormap
|
459 CWOverrideRedirect
| CWEventMask
;
461 attrib_create
.background_pixmap
= None
;
462 attrib_create
.colormap
= screen
->getColormap();
463 attrib_create
.override_redirect
= True
;
464 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
466 EnterWindowMask
| LeaveWindowMask
;
468 return XCreateWindow(blackbox
->getXDisplay(), screen
->getRootWindow(),
469 0, 0, 1, 1, frame
.border_w
, screen
->getDepth(),
470 InputOutput
, screen
->getVisual(), create_mask
,
476 * Creates a child window, and optionally associates a given cursor with
479 Window
BlackboxWindow::createChildWindow(Window parent
, Cursor cursor
) {
480 XSetWindowAttributes attrib_create
;
481 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
|
484 attrib_create
.background_pixmap
= None
;
485 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
486 ButtonMotionMask
| ExposureMask
;
489 create_mask
|= CWCursor
;
490 attrib_create
.cursor
= cursor
;
493 return XCreateWindow(blackbox
->getXDisplay(), parent
, 0, 0, 1, 1, 0,
494 screen
->getDepth(), InputOutput
, screen
->getVisual(),
495 create_mask
, &attrib_create
);
499 void BlackboxWindow::associateClientWindow(void) {
500 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, 0);
504 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeInsert
);
506 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, SubstructureRedirectMask
);
509 note we used to grab around this call to XReparentWindow however the
510 server is now grabbed before this method is called
512 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
514 XSelectInput(blackbox
->getXDisplay(), client
.window
,
515 event_mask
& ~StructureNotifyMask
);
516 XReparentWindow(blackbox
->getXDisplay(), client
.window
, frame
.plate
, 0, 0);
517 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
519 XRaiseWindow(blackbox
->getXDisplay(), frame
.plate
);
520 XMapSubwindows(blackbox
->getXDisplay(), frame
.plate
);
523 if (blackbox
->hasShapeExtensions()) {
524 XShapeSelectInput(blackbox
->getXDisplay(), client
.window
,
531 XShapeQueryExtents(blackbox
->getXDisplay(), client
.window
, &shaped
,
532 &foo
, &foo
, &ufoo
, &ufoo
, &foo
, &foo
, &foo
,
534 flags
.shaped
= shaped
;
540 void BlackboxWindow::decorate(void) {
543 texture
= &(screen
->getWindowStyle()->b_focus
);
544 frame
.fbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
547 frame
.fbutton_pixel
= texture
->color().pixel();
549 texture
= &(screen
->getWindowStyle()->b_unfocus
);
550 frame
.ubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
553 frame
.ubutton_pixel
= texture
->color().pixel();
555 texture
= &(screen
->getWindowStyle()->b_pressed
);
556 frame
.pbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
559 frame
.pbutton_pixel
= texture
->color().pixel();
561 if (decorations
& Decor_Titlebar
) {
562 texture
= &(screen
->getWindowStyle()->t_focus
);
563 frame
.ftitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
566 frame
.ftitle_pixel
= texture
->color().pixel();
568 texture
= &(screen
->getWindowStyle()->t_unfocus
);
569 frame
.utitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
572 frame
.utitle_pixel
= texture
->color().pixel();
574 XSetWindowBorder(blackbox
->getXDisplay(), frame
.title
,
575 screen
->getBorderColor()->pixel());
580 if (decorations
& Decor_Border
) {
581 frame
.fborder_pixel
= screen
->getWindowStyle()->f_focus
.pixel();
582 frame
.uborder_pixel
= screen
->getWindowStyle()->f_unfocus
.pixel();
583 blackbox_attrib
.flags
|= AttribDecoration
;
584 blackbox_attrib
.decoration
= DecorNormal
;
586 blackbox_attrib
.flags
|= AttribDecoration
;
587 blackbox_attrib
.decoration
= DecorNone
;
590 if (decorations
& Decor_Handle
) {
591 texture
= &(screen
->getWindowStyle()->h_focus
);
592 frame
.fhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
595 frame
.fhandle_pixel
= texture
->color().pixel();
597 texture
= &(screen
->getWindowStyle()->h_unfocus
);
598 frame
.uhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
601 frame
.uhandle_pixel
= texture
->color().pixel();
603 texture
= &(screen
->getWindowStyle()->g_focus
);
604 frame
.fgrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.fgrip
);
606 frame
.fgrip_pixel
= texture
->color().pixel();
608 texture
= &(screen
->getWindowStyle()->g_unfocus
);
609 frame
.ugrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.ugrip
);
611 frame
.ugrip_pixel
= texture
->color().pixel();
613 XSetWindowBorder(blackbox
->getXDisplay(), frame
.handle
,
614 screen
->getBorderColor()->pixel());
615 XSetWindowBorder(blackbox
->getXDisplay(), frame
.left_grip
,
616 screen
->getBorderColor()->pixel());
617 XSetWindowBorder(blackbox
->getXDisplay(), frame
.right_grip
,
618 screen
->getBorderColor()->pixel());
621 XSetWindowBorder(blackbox
->getXDisplay(), frame
.window
,
622 screen
->getBorderColor()->pixel());
626 void BlackboxWindow::decorateLabel(void) {
629 texture
= &(screen
->getWindowStyle()->l_focus
);
630 frame
.flabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.flabel
);
632 frame
.flabel_pixel
= texture
->color().pixel();
634 texture
= &(screen
->getWindowStyle()->l_unfocus
);
635 frame
.ulabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.ulabel
);
637 frame
.ulabel_pixel
= texture
->color().pixel();
641 void BlackboxWindow::createHandle(void) {
642 frame
.handle
= createChildWindow(frame
.window
);
643 blackbox
->saveWindowSearch(frame
.handle
, this);
646 createChildWindow(frame
.handle
, blackbox
->getLowerLeftAngleCursor());
647 blackbox
->saveWindowSearch(frame
.left_grip
, this);
650 createChildWindow(frame
.handle
, blackbox
->getLowerRightAngleCursor());
651 blackbox
->saveWindowSearch(frame
.right_grip
, this);
655 void BlackboxWindow::destroyHandle(void) {
657 screen
->getImageControl()->removeImage(frame
.fhandle
);
660 screen
->getImageControl()->removeImage(frame
.uhandle
);
663 screen
->getImageControl()->removeImage(frame
.fgrip
);
666 screen
->getImageControl()->removeImage(frame
.ugrip
);
668 blackbox
->removeWindowSearch(frame
.left_grip
);
669 blackbox
->removeWindowSearch(frame
.right_grip
);
671 XDestroyWindow(blackbox
->getXDisplay(), frame
.left_grip
);
672 XDestroyWindow(blackbox
->getXDisplay(), frame
.right_grip
);
673 frame
.left_grip
= frame
.right_grip
= None
;
675 blackbox
->removeWindowSearch(frame
.handle
);
676 XDestroyWindow(blackbox
->getXDisplay(), frame
.handle
);
681 void BlackboxWindow::createTitlebar(void) {
682 frame
.title
= createChildWindow(frame
.window
);
683 frame
.label
= createChildWindow(frame
.title
);
684 blackbox
->saveWindowSearch(frame
.title
, this);
685 blackbox
->saveWindowSearch(frame
.label
, this);
687 if (decorations
& Decor_Iconify
) createIconifyButton();
688 if (decorations
& Decor_Maximize
) createMaximizeButton();
689 if (decorations
& Decor_Close
) createCloseButton();
693 void BlackboxWindow::destroyTitlebar(void) {
694 if (frame
.close_button
)
695 destroyCloseButton();
697 if (frame
.iconify_button
)
698 destroyIconifyButton();
700 if (frame
.maximize_button
)
701 destroyMaximizeButton();
704 screen
->getImageControl()->removeImage(frame
.ftitle
);
707 screen
->getImageControl()->removeImage(frame
.utitle
);
710 screen
->getImageControl()->removeImage(frame
.flabel
);
713 screen
->getImageControl()->removeImage(frame
.ulabel
);
716 screen
->getImageControl()->removeImage(frame
.fbutton
);
719 screen
->getImageControl()->removeImage(frame
.ubutton
);
722 screen
->getImageControl()->removeImage(frame
.pbutton
);
724 blackbox
->removeWindowSearch(frame
.title
);
725 blackbox
->removeWindowSearch(frame
.label
);
727 XDestroyWindow(blackbox
->getXDisplay(), frame
.label
);
728 XDestroyWindow(blackbox
->getXDisplay(), frame
.title
);
729 frame
.title
= frame
.label
= None
;
733 void BlackboxWindow::createCloseButton(void) {
734 if (frame
.title
!= None
) {
735 frame
.close_button
= createChildWindow(frame
.title
);
736 blackbox
->saveWindowSearch(frame
.close_button
, this);
741 void BlackboxWindow::destroyCloseButton(void) {
742 blackbox
->removeWindowSearch(frame
.close_button
);
743 XDestroyWindow(blackbox
->getXDisplay(), frame
.close_button
);
744 frame
.close_button
= None
;
748 void BlackboxWindow::createIconifyButton(void) {
749 if (frame
.title
!= None
) {
750 frame
.iconify_button
= createChildWindow(frame
.title
);
751 blackbox
->saveWindowSearch(frame
.iconify_button
, this);
756 void BlackboxWindow::destroyIconifyButton(void) {
757 blackbox
->removeWindowSearch(frame
.iconify_button
);
758 XDestroyWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
759 frame
.iconify_button
= None
;
763 void BlackboxWindow::createMaximizeButton(void) {
764 if (frame
.title
!= None
) {
765 frame
.maximize_button
= createChildWindow(frame
.title
);
766 blackbox
->saveWindowSearch(frame
.maximize_button
, this);
771 void BlackboxWindow::destroyMaximizeButton(void) {
772 blackbox
->removeWindowSearch(frame
.maximize_button
);
773 XDestroyWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
774 frame
.maximize_button
= None
;
778 void BlackboxWindow::positionButtons(bool redecorate_label
) {
779 string layout
= blackbox
->getTitlebarLayout();
782 bool hasclose
, hasiconify
, hasmaximize
, haslabel
;
783 hasclose
= hasiconify
= hasmaximize
= haslabel
= false;
785 string::const_iterator it
, end
;
786 for (it
= layout
.begin(), end
= layout
.end(); it
!= end
; ++it
) {
789 if (! hasclose
&& (decorations
& Decor_Close
)) {
795 if (! hasiconify
&& (decorations
& Decor_Iconify
)) {
801 if (! hasmaximize
&& (decorations
& Decor_Maximize
)) {
813 if (! hasclose
&& frame
.close_button
)
814 destroyCloseButton();
815 if (! hasiconify
&& frame
.iconify_button
)
816 destroyIconifyButton();
817 if (! hasmaximize
&& frame
.maximize_button
)
818 destroyMaximizeButton();
820 parsed
+= 'L'; // require that the label be in the layout
822 const unsigned int bsep
= frame
.bevel_w
+ 1; // separation between elements
823 const unsigned int by
= frame
.bevel_w
+ 1;
824 const unsigned int ty
= frame
.bevel_w
;
826 frame
.label_w
= frame
.inside_w
- bsep
* 2 -
827 (frame
.button_w
+ bsep
) * (parsed
.size() - 1);
829 unsigned int x
= bsep
;
830 for (it
= parsed
.begin(), end
= parsed
.end(); it
!= end
; ++it
) {
833 if (! frame
.close_button
) createCloseButton();
834 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.close_button
, x
, by
,
835 frame
.button_w
, frame
.button_w
);
836 x
+= frame
.button_w
+ bsep
;
839 if (! frame
.iconify_button
) createIconifyButton();
840 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.iconify_button
, x
, by
,
841 frame
.button_w
, frame
.button_w
);
842 x
+= frame
.button_w
+ bsep
;
845 if (! frame
.maximize_button
) createMaximizeButton();
846 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.maximize_button
, x
, by
,
847 frame
.button_w
, frame
.button_w
);
848 x
+= frame
.button_w
+ bsep
;
851 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.label
, x
, ty
,
852 frame
.label_w
, frame
.label_h
);
853 x
+= frame
.label_w
+ bsep
;
858 if (redecorate_label
) decorateLabel();
864 void BlackboxWindow::reconfigure(void) {
865 restoreGravity(client
.rect
);
867 applyGravity(frame
.rect
);
876 windowmenu
->move(windowmenu
->getX(), frame
.rect
.y() + frame
.title_h
);
877 windowmenu
->reconfigure();
882 void BlackboxWindow::grabButtons(void) {
883 if (! screen
->isSloppyFocus() || screen
->doClickRaise())
884 // grab button 1 for changing focus/raising
885 blackbox
->grabButton(Button1
, 0, frame
.plate
, True
, ButtonPressMask
,
886 GrabModeSync
, GrabModeSync
, frame
.plate
, None
,
887 screen
->allowScrollLock());
889 if (functions
& Func_Move
)
890 blackbox
->grabButton(Button1
, ModMask
, frame
.window
, True
,
891 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
892 GrabModeAsync
, frame
.window
, None
,
893 screen
->allowScrollLock());
894 if (functions
& Func_Resize
)
895 blackbox
->grabButton(Button3
, ModMask
, frame
.window
, True
,
896 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
897 GrabModeAsync
, frame
.window
, None
,
898 screen
->allowScrollLock());
899 // alt+middle lowers the window
900 blackbox
->grabButton(Button2
, ModMask
, frame
.window
, True
,
901 ButtonReleaseMask
, GrabModeAsync
, GrabModeAsync
,
903 screen
->allowScrollLock());
907 void BlackboxWindow::ungrabButtons(void) {
908 blackbox
->ungrabButton(Button1
, 0, frame
.plate
);
909 blackbox
->ungrabButton(Button1
, ModMask
, frame
.window
);
910 blackbox
->ungrabButton(Button2
, ModMask
, frame
.window
);
911 blackbox
->ungrabButton(Button3
, ModMask
, frame
.window
);
915 void BlackboxWindow::positionWindows(void) {
916 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.window
,
917 frame
.rect
.x(), frame
.rect
.y(), frame
.inside_w
,
918 (flags
.shaded
) ? frame
.title_h
: frame
.inside_h
);
919 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.window
,
921 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.plate
,
923 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.plate
,
924 frame
.margin
.left
- frame
.mwm_border_w
- frame
.border_w
,
925 frame
.margin
.top
- frame
.mwm_border_w
- frame
.border_w
,
926 client
.rect
.width(), client
.rect
.height());
927 XMoveResizeWindow(blackbox
->getXDisplay(), client
.window
,
928 0, 0, client
.rect
.width(), client
.rect
.height());
929 // ensure client.rect contains the real location
930 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
931 frame
.rect
.top() + frame
.margin
.top
);
933 if (decorations
& Decor_Titlebar
) {
934 if (frame
.title
== None
) createTitlebar();
936 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.title
,
938 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.title
, -frame
.border_w
,
939 -frame
.border_w
, frame
.inside_w
, frame
.title_h
);
942 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
943 XMapWindow(blackbox
->getXDisplay(), frame
.title
);
944 } else if (frame
.title
) {
947 if (decorations
& Decor_Handle
) {
948 if (frame
.handle
== None
) createHandle();
949 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.handle
,
951 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.left_grip
,
953 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.right_grip
,
956 // use client.rect here so the value is correct even if shaded
957 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.handle
,
959 client
.rect
.height() + frame
.margin
.top
+
960 frame
.mwm_border_w
- frame
.border_w
,
961 frame
.inside_w
, frame
.handle_h
);
962 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.left_grip
,
963 -frame
.border_w
, -frame
.border_w
,
964 frame
.grip_w
, frame
.handle_h
);
965 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.right_grip
,
966 frame
.inside_w
- frame
.grip_w
- frame
.border_w
,
967 -frame
.border_w
, frame
.grip_w
, frame
.handle_h
);
969 XMapSubwindows(blackbox
->getXDisplay(), frame
.handle
);
970 XMapWindow(blackbox
->getXDisplay(), frame
.handle
);
971 } else if (frame
.handle
) {
974 XSync(blackbox
->getXDisplay(), False
);
978 void BlackboxWindow::updateStrut(void) {
979 unsigned long num
= 4;
981 if (! xatom
->getValue(client
.window
, XAtom::net_wm_strut
, XAtom::cardinal
,
986 client
.strut
.left
= data
[0];
987 client
.strut
.right
= data
[1];
988 client
.strut
.top
= data
[2];
989 client
.strut
.bottom
= data
[3];
991 screen
->updateAvailableArea();
998 bool BlackboxWindow::getWindowType(void) {
1000 if (xatom
->getValue(client
.window
, XAtom::net_wm_window_type
, XAtom::atom
,
1002 if (val
== xatom
->getAtom(XAtom::net_wm_window_type_desktop
))
1003 window_type
= Type_Desktop
;
1004 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_dock
))
1005 window_type
= Type_Dock
;
1006 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_toolbar
))
1007 window_type
= Type_Toolbar
;
1008 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_menu
))
1009 window_type
= Type_Menu
;
1010 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_utility
))
1011 window_type
= Type_Utility
;
1012 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_splash
))
1013 window_type
= Type_Splash
;
1014 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_dialog
))
1015 window_type
= Type_Dialog
;
1016 else //if (val[0] == xatom->getAtom(XAtom::net_wm_window_type_normal))
1017 window_type
= Type_Normal
;
1023 * the window type hint was not set, which means we either classify ourself
1024 * as a normal window or a dialog, depending on if we are a transient.
1027 window_type
= Type_Dialog
;
1029 window_type
= Type_Normal
;
1035 void BlackboxWindow::getWMName(void) {
1036 if (xatom
->getValue(client
.window
, XAtom::net_wm_name
,
1037 XAtom::utf8
, client
.title
) &&
1038 !client
.title
.empty()) {
1039 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
1042 //fall through to using WM_NAME
1043 if (xatom
->getValue(client
.window
, XAtom::wm_name
, XAtom::ansi
, client
.title
)
1044 && !client
.title
.empty()) {
1045 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
1048 // fall back to an internal default
1049 client
.title
= i18n(WindowSet
, WindowUnnamed
, "Unnamed");
1050 xatom
->setValue(client
.window
, XAtom::net_wm_visible_name
, XAtom::utf8
,
1055 void BlackboxWindow::getWMIconName(void) {
1056 if (xatom
->getValue(client
.window
, XAtom::net_wm_icon_name
,
1057 XAtom::utf8
, client
.icon_title
) &&
1058 !client
.icon_title
.empty()) {
1059 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1062 //fall through to using WM_ICON_NAME
1063 if (xatom
->getValue(client
.window
, XAtom::wm_icon_name
, XAtom::ansi
,
1064 client
.icon_title
) &&
1065 !client
.icon_title
.empty()) {
1066 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1069 // fall back to using the main name
1070 client
.icon_title
= client
.title
;
1071 xatom
->setValue(client
.window
, XAtom::net_wm_visible_icon_name
, XAtom::utf8
,
1077 * Retrieve which WM Protocols are supported by the client window.
1078 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
1079 * window's decorations and allow the close behavior.
1080 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
1083 void BlackboxWindow::getWMProtocols(void) {
1087 if (XGetWMProtocols(blackbox
->getXDisplay(), client
.window
,
1088 &proto
, &num_return
)) {
1089 for (int i
= 0; i
< num_return
; ++i
) {
1090 if (proto
[i
] == xatom
->getAtom(XAtom::wm_delete_window
)) {
1091 decorations
|= Decor_Close
;
1092 functions
|= Func_Close
;
1093 } else if (proto
[i
] == xatom
->getAtom(XAtom::wm_take_focus
))
1094 flags
.send_focus_message
= True
;
1095 else if (proto
[i
] == xatom
->getAtom(XAtom::blackbox_structure_messages
))
1096 screen
->addNetizen(new Netizen(screen
, client
.window
));
1105 * Gets the value of the WM_HINTS property.
1106 * If the property is not set, then use a set of default values.
1108 void BlackboxWindow::getWMHints(void) {
1109 focus_mode
= F_Passive
;
1111 // remove from current window group
1112 if (client
.window_group
) {
1113 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1114 if (group
) group
->removeWindow(this);
1116 client
.window_group
= None
;
1118 XWMHints
*wmhint
= XGetWMHints(blackbox
->getXDisplay(), client
.window
);
1123 if (wmhint
->flags
& InputHint
) {
1124 if (wmhint
->input
== True
) {
1125 if (flags
.send_focus_message
)
1126 focus_mode
= F_LocallyActive
;
1128 if (flags
.send_focus_message
)
1129 focus_mode
= F_GloballyActive
;
1131 focus_mode
= F_NoInput
;
1135 if (wmhint
->flags
& StateHint
)
1136 current_state
= wmhint
->initial_state
;
1138 if (wmhint
->flags
& WindowGroupHint
) {
1139 client
.window_group
= wmhint
->window_group
;
1141 // add window to the appropriate group
1142 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1143 if (! group
) { // no group found, create it!
1144 new BWindowGroup(blackbox
, client
.window_group
);
1145 group
= blackbox
->searchGroup(client
.window_group
);
1148 group
->addWindow(this);
1156 * Gets the value of the WM_NORMAL_HINTS property.
1157 * If the property is not set, then use a set of default values.
1159 void BlackboxWindow::getWMNormalHints(void) {
1161 XSizeHints sizehint
;
1163 client
.min_width
= client
.min_height
=
1164 client
.width_inc
= client
.height_inc
= 1;
1165 client
.base_width
= client
.base_height
= 0;
1166 client
.win_gravity
= NorthWestGravity
;
1168 client
.min_aspect_x
= client
.min_aspect_y
=
1169 client
.max_aspect_x
= client
.max_aspect_y
= 1;
1173 use the full screen, not the strut modified size. otherwise when the
1174 availableArea changes max_width/height will be incorrect and lead to odd
1177 const Rect
& screen_area
= screen
->getRect();
1178 client
.max_width
= screen_area
.width();
1179 client
.max_height
= screen_area
.height();
1181 if (! XGetWMNormalHints(blackbox
->getXDisplay(), client
.window
,
1182 &sizehint
, &icccm_mask
))
1185 client
.normal_hint_flags
= sizehint
.flags
;
1187 if (sizehint
.flags
& PMinSize
) {
1188 if (sizehint
.min_width
>= 0)
1189 client
.min_width
= sizehint
.min_width
;
1190 if (sizehint
.min_height
>= 0)
1191 client
.min_height
= sizehint
.min_height
;
1194 if (sizehint
.flags
& PMaxSize
) {
1195 if (sizehint
.max_width
> static_cast<signed>(client
.min_width
))
1196 client
.max_width
= sizehint
.max_width
;
1198 client
.max_width
= client
.min_width
;
1200 if (sizehint
.max_height
> static_cast<signed>(client
.min_height
))
1201 client
.max_height
= sizehint
.max_height
;
1203 client
.max_height
= client
.min_height
;
1206 if (sizehint
.flags
& PResizeInc
) {
1207 client
.width_inc
= sizehint
.width_inc
;
1208 client
.height_inc
= sizehint
.height_inc
;
1211 #if 0 // we do not support this at the moment
1212 if (sizehint
.flags
& PAspect
) {
1213 client
.min_aspect_x
= sizehint
.min_aspect
.x
;
1214 client
.min_aspect_y
= sizehint
.min_aspect
.y
;
1215 client
.max_aspect_x
= sizehint
.max_aspect
.x
;
1216 client
.max_aspect_y
= sizehint
.max_aspect
.y
;
1220 if (sizehint
.flags
& PBaseSize
) {
1221 client
.base_width
= sizehint
.base_width
;
1222 client
.base_height
= sizehint
.base_height
;
1225 if (sizehint
.flags
& PWinGravity
)
1226 client
.win_gravity
= sizehint
.win_gravity
;
1231 * Gets the NETWM hints for the class' contained window.
1233 void BlackboxWindow::getNetWMHints(void) {
1234 unsigned long workspace
;
1236 if (xatom
->getValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1238 if (workspace
== 0xffffffff)
1241 blackbox_attrib
.workspace
= workspace
;
1244 unsigned long *state
;
1245 unsigned long num
= (unsigned) -1;
1246 if (xatom
->getValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
1250 for (unsigned long i
= 0; i
< num
; ++i
) {
1251 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
))
1253 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_shaded
))
1254 flags
.shaded
= True
;
1255 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
))
1256 flags
.skip_taskbar
= True
;
1257 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_pager
))
1258 flags
.skip_pager
= True
;
1259 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_fullscreen
))
1260 flags
.fullscreen
= True
;
1261 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_hidden
))
1262 setState(IconicState
);
1263 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_vert
))
1265 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_horz
))
1269 flags
.maximized
= 1;
1271 flags
.maximized
= 2;
1273 flags
.maximized
= 3;
1281 * Gets the MWM hints for the class' contained window.
1282 * This is used while initializing the window to its first state, and not
1284 * Returns: true if the MWM hints are successfully retreived and applied;
1285 * false if they are not.
1287 void BlackboxWindow::getMWMHints(void) {
1291 num
= PropMwmHintsElements
;
1292 if (! xatom
->getValue(client
.window
, XAtom::motif_wm_hints
,
1293 XAtom::motif_wm_hints
, num
,
1294 (unsigned long **)&mwm_hint
))
1296 if (num
< PropMwmHintsElements
) {
1301 if (mwm_hint
->flags
& MwmHintsDecorations
) {
1302 if (mwm_hint
->decorations
& MwmDecorAll
) {
1303 mwm_decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
1304 Decor_Iconify
| Decor_Maximize
| Decor_Close
;
1306 mwm_decorations
= 0;
1308 if (mwm_hint
->decorations
& MwmDecorBorder
)
1309 mwm_decorations
|= Decor_Border
;
1310 if (mwm_hint
->decorations
& MwmDecorHandle
)
1311 mwm_decorations
|= Decor_Handle
;
1312 if (mwm_hint
->decorations
& MwmDecorTitle
)
1313 mwm_decorations
|= Decor_Titlebar
;
1314 if (mwm_hint
->decorations
& MwmDecorIconify
)
1315 mwm_decorations
|= Decor_Iconify
;
1316 if (mwm_hint
->decorations
& MwmDecorMaximize
)
1317 mwm_decorations
|= Decor_Maximize
;
1321 if (mwm_hint
->flags
& MwmHintsFunctions
) {
1322 if (mwm_hint
->functions
& MwmFuncAll
) {
1323 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
|
1328 if (mwm_hint
->functions
& MwmFuncResize
)
1329 functions
|= Func_Resize
;
1330 if (mwm_hint
->functions
& MwmFuncMove
)
1331 functions
|= Func_Move
;
1332 if (mwm_hint
->functions
& MwmFuncIconify
)
1333 functions
|= Func_Iconify
;
1334 if (mwm_hint
->functions
& MwmFuncMaximize
)
1335 functions
|= Func_Maximize
;
1336 if (mwm_hint
->functions
& MwmFuncClose
)
1337 functions
|= Func_Close
;
1345 * Gets the blackbox hints from the class' contained window.
1346 * This is used while initializing the window to its first state, and not
1348 * Returns: true if the hints are successfully retreived and applied; false if
1351 bool BlackboxWindow::getBlackboxHints(void) {
1353 BlackboxHints
*blackbox_hint
;
1355 num
= PropBlackboxHintsElements
;
1356 if (! xatom
->getValue(client
.window
, XAtom::blackbox_hints
,
1357 XAtom::blackbox_hints
, num
,
1358 (unsigned long **)&blackbox_hint
))
1360 if (num
< PropBlackboxHintsElements
) {
1361 delete [] blackbox_hint
;
1365 if (blackbox_hint
->flags
& AttribShaded
)
1366 flags
.shaded
= (blackbox_hint
->attrib
& AttribShaded
);
1368 if ((blackbox_hint
->flags
& AttribMaxHoriz
) &&
1369 (blackbox_hint
->flags
& AttribMaxVert
))
1370 flags
.maximized
= (blackbox_hint
->attrib
&
1371 (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1372 else if (blackbox_hint
->flags
& AttribMaxVert
)
1373 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxVert
) ? 2 : 0;
1374 else if (blackbox_hint
->flags
& AttribMaxHoriz
)
1375 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1377 if (blackbox_hint
->flags
& AttribOmnipresent
)
1378 flags
.stuck
= (blackbox_hint
->attrib
& AttribOmnipresent
);
1380 if (blackbox_hint
->flags
& AttribWorkspace
)
1381 blackbox_attrib
.workspace
= blackbox_hint
->workspace
;
1383 // if (blackbox_hint->flags & AttribStack)
1384 // don't yet have always on top/bottom for blackbox yet... working
1387 if (blackbox_hint
->flags
& AttribDecoration
) {
1388 switch (blackbox_hint
->decoration
) {
1404 delete [] blackbox_hint
;
1410 void BlackboxWindow::getTransientInfo(void) {
1411 if (client
.transient_for
&&
1412 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1413 // reset transient_for in preparation of looking for a new owner
1414 client
.transient_for
->client
.transientList
.remove(this);
1417 // we have no transient_for until we find a new one
1418 client
.transient_for
= 0;
1421 if (! XGetTransientForHint(blackbox
->getXDisplay(), client
.window
,
1423 // transient_for hint not set
1427 if (trans_for
== client
.window
) {
1428 // wierd client... treat this window as a normal window
1432 if (trans_for
== None
|| trans_for
== screen
->getRootWindow()) {
1433 // this is an undocumented interpretation of the ICCCM. a transient
1434 // associated with None/Root/itself is assumed to be a modal root
1435 // transient. we don't support the concept of a global transient,
1436 // so we just associate this transient with nothing, and perhaps
1437 // we will add support later for global modality.
1438 client
.transient_for
= (BlackboxWindow
*) ~0ul;
1443 client
.transient_for
= blackbox
->searchWindow(trans_for
);
1444 if (! client
.transient_for
&&
1445 client
.window_group
&& trans_for
== client
.window_group
) {
1446 // no direct transient_for, perhaps this is a group transient?
1447 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1448 if (group
) client
.transient_for
= group
->find(screen
);
1451 if (! client
.transient_for
|| client
.transient_for
== this) {
1452 // no transient_for found, or we have a wierd client that wants to be
1453 // a transient for itself, so we treat this window as a normal window
1454 client
.transient_for
= (BlackboxWindow
*) 0;
1458 // Check for a circular transient state: this can lock up Blackbox
1459 // when it tries to find the non-transient window for a transient.
1460 BlackboxWindow
*w
= this;
1461 while(w
->client
.transient_for
&&
1462 w
->client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1463 if(w
->client
.transient_for
== this) {
1464 client
.transient_for
= (BlackboxWindow
*) 0;
1467 w
= w
->client
.transient_for
;
1470 if (client
.transient_for
&&
1471 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1472 // register ourselves with our new transient_for
1473 client
.transient_for
->client
.transientList
.push_back(this);
1474 flags
.stuck
= client
.transient_for
->flags
.stuck
;
1479 BlackboxWindow
*BlackboxWindow::getTransientFor(void) const {
1480 if (client
.transient_for
&&
1481 client
.transient_for
!= (BlackboxWindow
*) ~0ul)
1482 return client
.transient_for
;
1488 * This function is responsible for updating both the client and the frame
1490 * According to the ICCCM a client message is not sent for a resize, only a
1493 void BlackboxWindow::configure(int dx
, int dy
,
1494 unsigned int dw
, unsigned int dh
) {
1495 bool send_event
= ((frame
.rect
.x() != dx
|| frame
.rect
.y() != dy
) &&
1498 if (dw
!= frame
.rect
.width() || dh
!= frame
.rect
.height()) {
1499 frame
.rect
.setRect(dx
, dy
, dw
, dh
);
1500 frame
.inside_w
= frame
.rect
.width() - (frame
.border_w
* 2);
1501 frame
.inside_h
= frame
.rect
.height() - (frame
.border_w
* 2);
1503 if (frame
.rect
.right() <= 0 || frame
.rect
.bottom() <= 0)
1504 frame
.rect
.setPos(0, 0);
1506 client
.rect
.setCoords(frame
.rect
.left() + frame
.margin
.left
,
1507 frame
.rect
.top() + frame
.margin
.top
,
1508 frame
.rect
.right() - frame
.margin
.right
,
1509 frame
.rect
.bottom() - frame
.margin
.bottom
);
1512 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
1519 redrawWindowFrame();
1521 frame
.rect
.setPos(dx
, dy
);
1523 XMoveWindow(blackbox
->getXDisplay(), frame
.window
,
1524 frame
.rect
.x(), frame
.rect
.y());
1526 we may have been called just after an opaque window move, so even though
1527 the old coords match the new ones no ConfigureNotify has been sent yet.
1528 There are likely other times when this will be relevant as well.
1530 if (! flags
.moving
) send_event
= True
;
1534 // if moving, the update and event will occur when the move finishes
1535 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1536 frame
.rect
.top() + frame
.margin
.top
);
1539 event
.type
= ConfigureNotify
;
1541 event
.xconfigure
.display
= blackbox
->getXDisplay();
1542 event
.xconfigure
.event
= client
.window
;
1543 event
.xconfigure
.window
= client
.window
;
1544 event
.xconfigure
.x
= client
.rect
.x();
1545 event
.xconfigure
.y
= client
.rect
.y();
1546 event
.xconfigure
.width
= client
.rect
.width();
1547 event
.xconfigure
.height
= client
.rect
.height();
1548 event
.xconfigure
.border_width
= client
.old_bw
;
1549 event
.xconfigure
.above
= frame
.window
;
1550 event
.xconfigure
.override_redirect
= False
;
1552 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1553 StructureNotifyMask
, &event
);
1554 screen
->updateNetizenConfigNotify(&event
);
1555 XFlush(blackbox
->getXDisplay());
1561 void BlackboxWindow::configureShape(void) {
1562 XShapeCombineShape(blackbox
->getXDisplay(), frame
.window
, ShapeBounding
,
1563 frame
.margin
.left
- frame
.border_w
,
1564 frame
.margin
.top
- frame
.border_w
,
1565 client
.window
, ShapeBounding
, ShapeSet
);
1568 XRectangle xrect
[2];
1570 if (decorations
& Decor_Titlebar
) {
1571 xrect
[0].x
= xrect
[0].y
= -frame
.border_w
;
1572 xrect
[0].width
= frame
.rect
.width();
1573 xrect
[0].height
= frame
.title_h
+ (frame
.border_w
* 2);
1577 if (decorations
& Decor_Handle
) {
1578 xrect
[1].x
= -frame
.border_w
;
1579 xrect
[1].y
= frame
.rect
.height() - frame
.margin
.bottom
+
1580 frame
.mwm_border_w
- frame
.border_w
;
1581 xrect
[1].width
= frame
.rect
.width();
1582 xrect
[1].height
= frame
.handle_h
+ (frame
.border_w
* 2);
1586 XShapeCombineRectangles(blackbox
->getXDisplay(), frame
.window
,
1587 ShapeBounding
, 0, 0, xrect
, num
,
1588 ShapeUnion
, Unsorted
);
1593 bool BlackboxWindow::setInputFocus(void) {
1594 if (flags
.focused
) return True
;
1596 assert(flags
.stuck
|| // window must be on the current workspace or sticky
1597 blackbox_attrib
.workspace
== screen
->getCurrentWorkspaceID());
1600 We only do this check for normal windows and dialogs because other windows
1601 do this on purpose, such as kde's kicker, and we don't want to go moving
1604 if (window_type
== Type_Normal
|| window_type
== Type_Dialog
)
1605 if (! frame
.rect
.intersects(screen
->getRect())) {
1606 // client is outside the screen, move it to the center
1607 configure((screen
->getWidth() - frame
.rect
.width()) / 2,
1608 (screen
->getHeight() - frame
.rect
.height()) / 2,
1609 frame
.rect
.width(), frame
.rect
.height());
1612 if (client
.transientList
.size() > 0) {
1613 // transfer focus to any modal transients
1614 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1615 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1616 if ((*it
)->flags
.modal
) return (*it
)->setInputFocus();
1620 if (focus_mode
== F_LocallyActive
|| focus_mode
== F_Passive
) {
1621 XSetInputFocus(blackbox
->getXDisplay(), client
.window
,
1622 RevertToPointerRoot
, CurrentTime
);
1624 /* we could set the focus to none, since the window doesn't accept focus,
1625 * but we shouldn't set focus to nothing since this would surely make
1631 if (flags
.send_focus_message
) {
1633 ce
.xclient
.type
= ClientMessage
;
1634 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1635 ce
.xclient
.display
= blackbox
->getXDisplay();
1636 ce
.xclient
.window
= client
.window
;
1637 ce
.xclient
.format
= 32;
1638 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_take_focus
);
1639 ce
.xclient
.data
.l
[1] = blackbox
->getLastTime();
1640 ce
.xclient
.data
.l
[2] = 0l;
1641 ce
.xclient
.data
.l
[3] = 0l;
1642 ce
.xclient
.data
.l
[4] = 0l;
1643 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1645 XFlush(blackbox
->getXDisplay());
1652 void BlackboxWindow::iconify(void) {
1653 if (flags
.iconic
) return;
1655 // We don't need to worry about resizing because resizing always grabs the X
1656 // server. This should only ever happen if using opaque moving.
1660 if (windowmenu
) windowmenu
->hide();
1663 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1664 * we need to clear the event mask on client.window for a split second.
1665 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1666 * split second, leaving us with a ghost window... so, we need to do this
1667 * while the X server is grabbed
1669 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1670 StructureNotifyMask
;
1671 XGrabServer(blackbox
->getXDisplay());
1672 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1673 event_mask
& ~StructureNotifyMask
);
1674 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1675 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1676 XUngrabServer(blackbox
->getXDisplay());
1678 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1679 flags
.visible
= False
;
1680 flags
.iconic
= True
;
1682 setState(IconicState
);
1684 screen
->getWorkspace(blackbox_attrib
.workspace
)->removeWindow(this);
1686 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
1687 if (i
!= blackbox_attrib
.workspace
)
1688 screen
->getWorkspace(i
)->removeWindow(this, True
);
1691 if (isTransient()) {
1692 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1693 ! client
.transient_for
->flags
.iconic
) {
1694 // iconify our transient_for
1695 client
.transient_for
->iconify();
1699 screen
->addIcon(this);
1701 if (client
.transientList
.size() > 0) {
1702 // iconify all transients
1703 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1704 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1705 if (! (*it
)->flags
.iconic
) (*it
)->iconify();
1708 screen
->updateStackingList();
1712 void BlackboxWindow::show(void) {
1713 flags
.visible
= True
;
1714 flags
.iconic
= False
;
1716 current_state
= (flags
.shaded
) ? IconicState
: NormalState
;
1717 setState(current_state
);
1719 XMapWindow(blackbox
->getXDisplay(), client
.window
);
1720 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
1721 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
1726 XTranslateCoordinates(blackbox
->getXDisplay(), client
.window
,
1727 screen
->getRootWindow(),
1728 0, 0, &real_x
, &real_y
, &child
);
1729 fprintf(stderr
, "%s -- assumed: (%d, %d), real: (%d, %d)\n", getTitle(),
1730 client
.rect
.left(), client
.rect
.top(), real_x
, real_y
);
1731 assert(client
.rect
.left() == real_x
&& client
.rect
.top() == real_y
);
1736 void BlackboxWindow::deiconify(bool reassoc
, bool raise
) {
1737 if (flags
.iconic
|| reassoc
)
1738 screen
->reassociateWindow(this, BSENTINEL
, False
);
1739 else if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID())
1744 // reassociate and deiconify all transients
1745 if (reassoc
&& client
.transientList
.size() > 0) {
1746 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1747 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1748 (*it
)->deiconify(True
, False
);
1752 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1756 void BlackboxWindow::close(void) {
1758 ce
.xclient
.type
= ClientMessage
;
1759 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1760 ce
.xclient
.display
= blackbox
->getXDisplay();
1761 ce
.xclient
.window
= client
.window
;
1762 ce
.xclient
.format
= 32;
1763 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_delete_window
);
1764 ce
.xclient
.data
.l
[1] = CurrentTime
;
1765 ce
.xclient
.data
.l
[2] = 0l;
1766 ce
.xclient
.data
.l
[3] = 0l;
1767 ce
.xclient
.data
.l
[4] = 0l;
1768 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
, NoEventMask
, &ce
);
1769 XFlush(blackbox
->getXDisplay());
1773 void BlackboxWindow::withdraw(void) {
1774 // We don't need to worry about resizing because resizing always grabs the X
1775 // server. This should only ever happen if using opaque moving.
1779 flags
.visible
= False
;
1780 flags
.iconic
= False
;
1782 setState(current_state
);
1784 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1786 XGrabServer(blackbox
->getXDisplay());
1788 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1789 StructureNotifyMask
;
1790 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1791 event_mask
& ~StructureNotifyMask
);
1792 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1793 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1795 XUngrabServer(blackbox
->getXDisplay());
1797 if (windowmenu
) windowmenu
->hide();
1801 void BlackboxWindow::maximize(unsigned int button
) {
1802 // We don't need to worry about resizing because resizing always grabs the X
1803 // server. This should only ever happen if using opaque moving.
1807 // handle case where menu is open then the max button is used instead
1808 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
1810 if (flags
.maximized
) {
1811 flags
.maximized
= 0;
1813 blackbox_attrib
.flags
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1814 blackbox_attrib
.attrib
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1817 when a resize finishes, maximize(0) is called to clear any maximization
1818 flags currently set. Otherwise it still thinks it is maximized.
1819 so we do not need to call configure() because resizing will handle it
1821 if (! flags
.resizing
)
1822 configure(blackbox_attrib
.premax_x
, blackbox_attrib
.premax_y
,
1823 blackbox_attrib
.premax_w
, blackbox_attrib
.premax_h
);
1825 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
1826 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
1828 redrawAllButtons(); // in case it is not called in configure()
1829 setState(current_state
);
1833 blackbox_attrib
.premax_x
= frame
.rect
.x();
1834 blackbox_attrib
.premax_y
= frame
.rect
.y();
1835 blackbox_attrib
.premax_w
= frame
.rect
.width();
1836 // use client.rect so that clients can be restored even if shaded
1837 blackbox_attrib
.premax_h
=
1838 client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
;
1841 if (screen
->isXineramaActive() && blackbox
->doXineramaMaximizing()) {
1842 // find the area to use
1843 RectList availableAreas
= screen
->allAvailableAreas();
1844 RectList::iterator it
, end
= availableAreas
.end();
1846 for (it
= availableAreas
.begin(); it
!= end
; ++it
)
1847 if (it
->intersects(frame
.rect
)) break;
1848 if (it
== end
) // the window isn't inside an area
1849 it
= availableAreas
.begin(); // so just default to the first one
1851 frame
.changing
= *it
;
1854 frame
.changing
= screen
->availableArea();
1858 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1859 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1863 blackbox_attrib
.flags
|= AttribMaxVert
;
1864 blackbox_attrib
.attrib
|= AttribMaxVert
;
1866 frame
.changing
.setX(frame
.rect
.x());
1867 frame
.changing
.setWidth(frame
.rect
.width());
1871 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1872 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1874 frame
.changing
.setY(frame
.rect
.y());
1875 frame
.changing
.setHeight(frame
.rect
.height());
1882 blackbox_attrib
.flags
^= AttribShaded
;
1883 blackbox_attrib
.attrib
^= AttribShaded
;
1884 flags
.shaded
= False
;
1887 flags
.maximized
= button
;
1889 configure(frame
.changing
.x(), frame
.changing
.y(),
1890 frame
.changing
.width(), frame
.changing
.height());
1892 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1893 redrawAllButtons(); // in case it is not called in configure()
1894 setState(current_state
);
1898 // re-maximizes the window to take into account availableArea changes
1899 void BlackboxWindow::remaximize(void) {
1901 // we only update the window's attributes otherwise we lose the shade bit
1902 switch(flags
.maximized
) {
1904 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1905 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1909 blackbox_attrib
.flags
|= AttribMaxVert
;
1910 blackbox_attrib
.attrib
|= AttribMaxVert
;
1914 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1915 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1921 // save the original dimensions because maximize will wipe them out
1922 int premax_x
= blackbox_attrib
.premax_x
,
1923 premax_y
= blackbox_attrib
.premax_y
,
1924 premax_w
= blackbox_attrib
.premax_w
,
1925 premax_h
= blackbox_attrib
.premax_h
;
1927 unsigned int button
= flags
.maximized
;
1928 flags
.maximized
= 0; // trick maximize() into working
1931 // restore saved values
1932 blackbox_attrib
.premax_x
= premax_x
;
1933 blackbox_attrib
.premax_y
= premax_y
;
1934 blackbox_attrib
.premax_w
= premax_w
;
1935 blackbox_attrib
.premax_h
= premax_h
;
1939 void BlackboxWindow::setWorkspace(unsigned int n
) {
1940 blackbox_attrib
.flags
|= AttribWorkspace
;
1941 blackbox_attrib
.workspace
= n
;
1942 if (n
== BSENTINEL
) { // iconified window
1944 we set the workspace to 'all workspaces' so that taskbars will show the
1945 window. otherwise, it made uniconifying a window imposible without the
1946 blackbox workspace menu
1950 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
, n
);
1954 void BlackboxWindow::shade(void) {
1956 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1957 frame
.inside_w
, frame
.inside_h
);
1958 flags
.shaded
= False
;
1959 blackbox_attrib
.flags
^= AttribShaded
;
1960 blackbox_attrib
.attrib
^= AttribShaded
;
1962 setState(NormalState
);
1964 // set the frame rect to the normal size
1965 frame
.rect
.setHeight(client
.rect
.height() + frame
.margin
.top
+
1966 frame
.margin
.bottom
);
1968 if (! (decorations
& Decor_Titlebar
))
1969 return; // can't shade it without a titlebar!
1971 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1972 frame
.inside_w
, frame
.title_h
);
1973 flags
.shaded
= True
;
1974 blackbox_attrib
.flags
|= AttribShaded
;
1975 blackbox_attrib
.attrib
|= AttribShaded
;
1977 setState(IconicState
);
1979 // set the frame rect to the shaded size
1980 frame
.rect
.setHeight(frame
.title_h
+ (frame
.border_w
* 2));
1986 * (Un)Sticks a window and its relatives.
1988 void BlackboxWindow::stick(void) {
1990 blackbox_attrib
.flags
^= AttribOmnipresent
;
1991 blackbox_attrib
.attrib
^= AttribOmnipresent
;
1993 flags
.stuck
= False
;
1995 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
1996 if (i
!= blackbox_attrib
.workspace
)
1997 screen
->getWorkspace(i
)->removeWindow(this, True
);
2000 screen
->reassociateWindow(this, BSENTINEL
, True
);
2001 // temporary fix since sticky windows suck. set the hint to what we
2002 // actually hold in our data.
2003 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
2004 blackbox_attrib
.workspace
);
2006 setState(current_state
);
2010 blackbox_attrib
.flags
|= AttribOmnipresent
;
2011 blackbox_attrib
.attrib
|= AttribOmnipresent
;
2013 // temporary fix since sticky windows suck. set the hint to a different
2014 // value than that contained in the class' data.
2015 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
2018 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
2019 if (i
!= blackbox_attrib
.workspace
)
2020 screen
->getWorkspace(i
)->addWindow(this, False
, True
);
2022 setState(current_state
);
2025 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
2026 client
.transient_for
->isStuck() != flags
.stuck
)
2027 client
.transient_for
->stick();
2028 // go down the chain
2029 BlackboxWindowList::iterator it
;
2030 const BlackboxWindowList::iterator end
= client
.transientList
.end();
2031 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
2032 if ((*it
)->isStuck() != flags
.stuck
)
2037 void BlackboxWindow::redrawWindowFrame(void) const {
2038 if (decorations
& Decor_Titlebar
) {
2039 if (flags
.focused
) {
2041 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2042 frame
.title
, frame
.ftitle
);
2044 XSetWindowBackground(blackbox
->getXDisplay(),
2045 frame
.title
, frame
.ftitle_pixel
);
2048 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2049 frame
.title
, frame
.utitle
);
2051 XSetWindowBackground(blackbox
->getXDisplay(),
2052 frame
.title
, frame
.utitle_pixel
);
2054 XClearWindow(blackbox
->getXDisplay(), frame
.title
);
2060 if (decorations
& Decor_Handle
) {
2061 if (flags
.focused
) {
2063 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2064 frame
.handle
, frame
.fhandle
);
2066 XSetWindowBackground(blackbox
->getXDisplay(),
2067 frame
.handle
, frame
.fhandle_pixel
);
2070 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2071 frame
.left_grip
, frame
.fgrip
);
2072 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2073 frame
.right_grip
, frame
.fgrip
);
2075 XSetWindowBackground(blackbox
->getXDisplay(),
2076 frame
.left_grip
, frame
.fgrip_pixel
);
2077 XSetWindowBackground(blackbox
->getXDisplay(),
2078 frame
.right_grip
, frame
.fgrip_pixel
);
2082 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2083 frame
.handle
, frame
.uhandle
);
2085 XSetWindowBackground(blackbox
->getXDisplay(),
2086 frame
.handle
, frame
.uhandle_pixel
);
2089 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2090 frame
.left_grip
, frame
.ugrip
);
2091 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2092 frame
.right_grip
, frame
.ugrip
);
2094 XSetWindowBackground(blackbox
->getXDisplay(),
2095 frame
.left_grip
, frame
.ugrip_pixel
);
2096 XSetWindowBackground(blackbox
->getXDisplay(),
2097 frame
.right_grip
, frame
.ugrip_pixel
);
2100 XClearWindow(blackbox
->getXDisplay(), frame
.handle
);
2101 XClearWindow(blackbox
->getXDisplay(), frame
.left_grip
);
2102 XClearWindow(blackbox
->getXDisplay(), frame
.right_grip
);
2105 if (decorations
& Decor_Border
) {
2107 XSetWindowBorder(blackbox
->getXDisplay(),
2108 frame
.plate
, frame
.fborder_pixel
);
2110 XSetWindowBorder(blackbox
->getXDisplay(),
2111 frame
.plate
, frame
.uborder_pixel
);
2116 void BlackboxWindow::setFocusFlag(bool focus
) {
2117 // only focus a window if it is visible
2118 if (focus
&& ! flags
.visible
)
2121 flags
.focused
= focus
;
2123 redrawWindowFrame();
2126 blackbox
->setFocusedWindow(this);
2128 if (! flags
.iconic
) {
2129 // iconic windows arent in a workspace menu!
2131 screen
->getCurrentWorkspace()->setFocused(this, isFocused());
2133 screen
->getWorkspace(blackbox_attrib
.workspace
)->
2134 setFocused(this, flags
.focused
);
2139 void BlackboxWindow::installColormap(bool install
) {
2140 int i
= 0, ncmap
= 0;
2141 Colormap
*cmaps
= XListInstalledColormaps(blackbox
->getXDisplay(),
2142 client
.window
, &ncmap
);
2144 XWindowAttributes wattrib
;
2145 if (XGetWindowAttributes(blackbox
->getXDisplay(),
2146 client
.window
, &wattrib
)) {
2148 // install the window's colormap
2149 for (i
= 0; i
< ncmap
; i
++) {
2150 if (*(cmaps
+ i
) == wattrib
.colormap
)
2151 // this window is using an installed color map... do not install
2154 // otherwise, install the window's colormap
2156 XInstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2158 // uninstall the window's colormap
2159 for (i
= 0; i
< ncmap
; i
++) {
2160 if (*(cmaps
+ i
) == wattrib
.colormap
)
2161 // we found the colormap to uninstall
2162 XUninstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2172 void BlackboxWindow::setAllowedActions(void) {
2176 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_shade
);
2177 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_change_desktop
);
2178 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_close
);
2180 if (functions
& Func_Move
)
2181 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_move
);
2182 if (functions
& Func_Resize
)
2183 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_resize
);
2184 if (functions
& Func_Maximize
) {
2185 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_horz
);
2186 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_vert
);
2189 xatom
->setValue(client
.window
, XAtom::net_wm_allowed_actions
, XAtom::atom
,
2194 void BlackboxWindow::setState(unsigned long new_state
) {
2195 current_state
= new_state
;
2197 unsigned long state
[2];
2198 state
[0] = current_state
;
2200 xatom
->setValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
, state
, 2);
2202 xatom
->setValue(client
.window
, XAtom::blackbox_attributes
,
2203 XAtom::blackbox_attributes
, (unsigned long *)&blackbox_attrib
,
2204 PropBlackboxAttributesElements
);
2209 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_modal
);
2211 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_shaded
);
2213 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_hidden
);
2214 if (flags
.skip_taskbar
)
2215 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
);
2216 if (flags
.skip_pager
)
2217 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_pager
);
2218 if (flags
.fullscreen
)
2219 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_fullscreen
);
2220 if (flags
.maximized
== 1 || flags
.maximized
== 2)
2221 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_vert
);
2222 if (flags
.maximized
== 1 || flags
.maximized
== 3)
2223 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_horz
);
2224 xatom
->setValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
2229 bool BlackboxWindow::getState(void) {
2230 bool ret
= xatom
->getValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
,
2232 if (! ret
) current_state
= 0;
2237 void BlackboxWindow::restoreAttributes(void) {
2238 unsigned long num
= PropBlackboxAttributesElements
;
2239 BlackboxAttributes
*net
;
2240 if (! xatom
->getValue(client
.window
, XAtom::blackbox_attributes
,
2241 XAtom::blackbox_attributes
, num
,
2242 (unsigned long **)&net
))
2244 if (num
< PropBlackboxAttributesElements
) {
2249 if (net
->flags
& AttribShaded
&& net
->attrib
& AttribShaded
) {
2250 flags
.shaded
= False
;
2251 unsigned long orig_state
= current_state
;
2255 At this point in the life of a window, current_state should only be set
2256 to IconicState if the window was an *icon*, not if it was shaded.
2258 if (orig_state
!= IconicState
)
2259 current_state
= WithdrawnState
;
2262 if (net
->workspace
!= screen
->getCurrentWorkspaceID() &&
2263 net
->workspace
< screen
->getWorkspaceCount())
2264 screen
->reassociateWindow(this, net
->workspace
, True
);
2266 if ((blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID()) &&
2267 (blackbox_attrib
.workspace
< screen
->getWorkspaceCount())) {
2268 // set to WithdrawnState so it will be mapped on the new workspace
2269 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2270 } else if (current_state
== WithdrawnState
) {
2271 // the window is on this workspace and is Withdrawn, so it is waiting to
2273 current_state
= NormalState
;
2276 if (net
->flags
& AttribOmnipresent
&& net
->attrib
& AttribOmnipresent
&&
2280 // if the window was on another workspace, it was going to be hidden. this
2281 // specifies that the window should be mapped since it is sticky.
2282 if (current_state
== WithdrawnState
) current_state
= NormalState
;
2285 if (net
->flags
& AttribMaxHoriz
|| net
->flags
& AttribMaxVert
) {
2286 int x
= net
->premax_x
, y
= net
->premax_y
;
2287 unsigned int w
= net
->premax_w
, h
= net
->premax_h
;
2288 flags
.maximized
= 0;
2291 if ((net
->flags
& AttribMaxHoriz
) &&
2292 (net
->flags
& AttribMaxVert
))
2293 m
= (net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
2294 else if (net
->flags
& AttribMaxVert
)
2295 m
= (net
->attrib
& AttribMaxVert
) ? 2 : 0;
2296 else if (net
->flags
& AttribMaxHoriz
)
2297 m
= (net
->attrib
& AttribMaxHoriz
) ? 3 : 0;
2301 blackbox_attrib
.premax_x
= x
;
2302 blackbox_attrib
.premax_y
= y
;
2303 blackbox_attrib
.premax_w
= w
;
2304 blackbox_attrib
.premax_h
= h
;
2307 if (net
->flags
& AttribDecoration
) {
2308 switch (net
->decoration
) {
2313 /* since tools only let you toggle this anyways, we'll just make that all
2314 it supports for now.
2324 // we can not be shaded if we lack a titlebar
2325 if (! (decorations
& Decor_Titlebar
) && flags
.shaded
)
2328 if (flags
.visible
&& frame
.window
) {
2329 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
2330 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
2334 setState(current_state
);
2337 // with the state set it will then be the map event's job to read the
2338 // window's state and behave accordingly
2345 * Positions the Rect r according the the client window position and
2348 void BlackboxWindow::applyGravity(Rect
&r
) {
2349 // apply horizontal window gravity
2350 switch (client
.win_gravity
) {
2352 case NorthWestGravity
:
2353 case SouthWestGravity
:
2355 r
.setX(client
.rect
.x());
2361 r
.setX(client
.rect
.x() - (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2364 case NorthEastGravity
:
2365 case SouthEastGravity
:
2367 r
.setX(client
.rect
.x() - frame
.margin
.left
- frame
.margin
.right
+ 2);
2372 r
.setX(client
.rect
.x() - frame
.margin
.left
);
2376 // apply vertical window gravity
2377 switch (client
.win_gravity
) {
2379 case NorthWestGravity
:
2380 case NorthEastGravity
:
2382 r
.setY(client
.rect
.y());
2388 r
.setY(client
.rect
.y() - (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2391 case SouthWestGravity
:
2392 case SouthEastGravity
:
2394 r
.setY(client
.rect
.y() - frame
.margin
.top
- frame
.margin
.bottom
+ 2);
2399 r
.setY(client
.rect
.y() - frame
.margin
.top
);
2406 * The reverse of the applyGravity function.
2408 * Positions the Rect r according to the frame window position and
2411 void BlackboxWindow::restoreGravity(Rect
&r
) {
2412 // restore horizontal window gravity
2413 switch (client
.win_gravity
) {
2415 case NorthWestGravity
:
2416 case SouthWestGravity
:
2418 r
.setX(frame
.rect
.x());
2424 r
.setX(frame
.rect
.x() + (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2427 case NorthEastGravity
:
2428 case SouthEastGravity
:
2430 r
.setX(frame
.rect
.x() + frame
.margin
.left
+ frame
.margin
.right
- 2);
2435 r
.setX(frame
.rect
.x() + frame
.margin
.left
);
2439 // restore vertical window gravity
2440 switch (client
.win_gravity
) {
2442 case NorthWestGravity
:
2443 case NorthEastGravity
:
2445 r
.setY(frame
.rect
.y());
2451 r
.setY(frame
.rect
.y() + (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2454 case SouthWestGravity
:
2455 case SouthEastGravity
:
2457 r
.setY(frame
.rect
.y() + frame
.margin
.top
+ frame
.margin
.bottom
- 2);
2462 r
.setY(frame
.rect
.y() + frame
.margin
.top
);
2468 void BlackboxWindow::redrawLabel(void) const {
2469 if (flags
.focused
) {
2471 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2472 frame
.label
, frame
.flabel
);
2474 XSetWindowBackground(blackbox
->getXDisplay(),
2475 frame
.label
, frame
.flabel_pixel
);
2478 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2479 frame
.label
, frame
.ulabel
);
2481 XSetWindowBackground(blackbox
->getXDisplay(),
2482 frame
.label
, frame
.ulabel_pixel
);
2484 XClearWindow(blackbox
->getXDisplay(), frame
.label
);
2486 WindowStyle
*style
= screen
->getWindowStyle();
2488 int pos
= frame
.bevel_w
* 2;
2489 style
->doJustify(client
.title
.c_str(), pos
, frame
.label_w
, frame
.bevel_w
* 4);
2490 style
->font
->drawString(frame
.label
, pos
, 1,
2491 (flags
.focused
? style
->l_text_focus
:
2492 style
->l_text_unfocus
),
2497 void BlackboxWindow::redrawAllButtons(void) const {
2498 if (frame
.iconify_button
) redrawIconifyButton(False
);
2499 if (frame
.maximize_button
) redrawMaximizeButton(flags
.maximized
);
2500 if (frame
.close_button
) redrawCloseButton(False
);
2504 void BlackboxWindow::redrawIconifyButton(bool pressed
) const {
2506 if (flags
.focused
) {
2508 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2509 frame
.iconify_button
, frame
.fbutton
);
2511 XSetWindowBackground(blackbox
->getXDisplay(),
2512 frame
.iconify_button
, frame
.fbutton_pixel
);
2515 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2516 frame
.iconify_button
, frame
.ubutton
);
2518 XSetWindowBackground(blackbox
->getXDisplay(), frame
.iconify_button
,
2519 frame
.ubutton_pixel
);
2523 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2524 frame
.iconify_button
, frame
.pbutton
);
2526 XSetWindowBackground(blackbox
->getXDisplay(),
2527 frame
.iconify_button
, frame
.pbutton_pixel
);
2529 XClearWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
2531 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2532 screen
->getWindowStyle()->b_pic_unfocus
);
2533 XDrawRectangle(blackbox
->getXDisplay(), frame
.iconify_button
, pen
.gc(),
2534 2, (frame
.button_w
- 5), (frame
.button_w
- 5), 2);
2538 void BlackboxWindow::redrawMaximizeButton(bool pressed
) const {
2540 if (flags
.focused
) {
2542 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2543 frame
.maximize_button
, frame
.fbutton
);
2545 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2546 frame
.fbutton_pixel
);
2549 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2550 frame
.maximize_button
, frame
.ubutton
);
2552 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2553 frame
.ubutton_pixel
);
2557 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2558 frame
.maximize_button
, frame
.pbutton
);
2560 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2561 frame
.pbutton_pixel
);
2563 XClearWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
2565 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2566 screen
->getWindowStyle()->b_pic_unfocus
);
2567 XDrawRectangle(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2568 2, 2, (frame
.button_w
- 5), (frame
.button_w
- 5));
2569 XDrawLine(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2570 2, 3, (frame
.button_w
- 3), 3);
2574 void BlackboxWindow::redrawCloseButton(bool pressed
) const {
2576 if (flags
.focused
) {
2578 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2581 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2582 frame
.fbutton_pixel
);
2585 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2588 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2589 frame
.ubutton_pixel
);
2593 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2594 frame
.close_button
, frame
.pbutton
);
2596 XSetWindowBackground(blackbox
->getXDisplay(),
2597 frame
.close_button
, frame
.pbutton_pixel
);
2599 XClearWindow(blackbox
->getXDisplay(), frame
.close_button
);
2601 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2602 screen
->getWindowStyle()->b_pic_unfocus
);
2603 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2604 2, 2, (frame
.button_w
- 3), (frame
.button_w
- 3));
2605 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2606 2, (frame
.button_w
- 3), (frame
.button_w
- 3), 2);
2610 void BlackboxWindow::mapRequestEvent(const XMapRequestEvent
*re
) {
2611 if (re
->window
!= client
.window
)
2615 fprintf(stderr
, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2619 switch (current_state
) {
2624 case WithdrawnState
:
2633 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2635 if (! blackbox
->isStartup()) {
2636 XSync(blackbox
->getXDisplay(), False
); // make sure the frame is mapped
2637 if (screen
->doFocusNew()|| (isTransient() && getTransientFor() &&
2638 getTransientFor()->isFocused())) {
2641 if (screen
->getPlacementPolicy() == BScreen::ClickMousePlacement
) {
2645 XQueryPointer(blackbox
->getXDisplay(), screen
->getRootWindow(),
2646 &r
, &c
, &rx
, &ry
, &x
, &y
, &m
);
2656 void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent
*ue
) {
2657 if (ue
->window
!= client
.window
)
2661 fprintf(stderr
, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2665 screen
->unmanageWindow(this, False
);
2669 void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent
*de
) {
2670 if (de
->window
!= client
.window
)
2674 fprintf(stderr
, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2678 screen
->unmanageWindow(this, False
);
2682 void BlackboxWindow::reparentNotifyEvent(const XReparentEvent
*re
) {
2683 if (re
->window
!= client
.window
|| re
->parent
== frame
.plate
)
2687 fprintf(stderr
, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2688 "0x%lx.\n", client
.window
, re
->parent
);
2693 XPutBackEvent(blackbox
->getXDisplay(), &ev
);
2694 screen
->unmanageWindow(this, True
);
2698 void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent
*pe
) {
2699 if (pe
->state
== PropertyDelete
)
2703 fprintf(stderr
, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n",
2709 case XA_WM_CLIENT_MACHINE
:
2713 case XA_WM_TRANSIENT_FOR
: {
2714 // determine if this is a transient window
2717 // adjust the window decorations based on transience
2718 if (isTransient()) {
2719 functions
&= ~Func_Maximize
;
2720 setAllowedActions();
2732 case XA_WM_ICON_NAME
:
2734 if (flags
.iconic
) screen
->propagateWindowName(this);
2737 case XAtom::net_wm_name
:
2741 if (decorations
& Decor_Titlebar
)
2744 screen
->propagateWindowName(this);
2747 case XA_WM_NORMAL_HINTS
: {
2750 if ((client
.normal_hint_flags
& PMinSize
) &&
2751 (client
.normal_hint_flags
& PMaxSize
)) {
2752 // the window now can/can't resize itself, so the buttons need to be
2755 if (client
.max_width
<= client
.min_width
&&
2756 client
.max_height
<= client
.min_height
) {
2757 functions
&= ~(Func_Resize
| Func_Maximize
);
2759 if (! isTransient())
2760 functions
|= Func_Maximize
;
2761 functions
|= Func_Resize
;
2764 setAllowedActions();
2768 Rect old_rect
= frame
.rect
;
2772 if (old_rect
!= frame
.rect
)
2779 if (pe
->atom
== xatom
->getAtom(XAtom::wm_protocols
)) {
2782 if ((decorations
& Decor_Close
) && (! frame
.close_button
)) {
2783 createCloseButton();
2784 if (decorations
& Decor_Titlebar
) {
2785 positionButtons(True
);
2786 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
2788 if (windowmenu
) windowmenu
->reconfigure();
2790 } else if (pe
->atom
== xatom
->getAtom(XAtom::net_wm_strut
)) {
2799 void BlackboxWindow::exposeEvent(const XExposeEvent
*ee
) {
2801 fprintf(stderr
, "BlackboxWindow::exposeEvent() for 0x%lx\n", client
.window
);
2804 if (frame
.label
== ee
->window
&& (decorations
& Decor_Titlebar
))
2806 else if (frame
.close_button
== ee
->window
)
2807 redrawCloseButton(False
);
2808 else if (frame
.maximize_button
== ee
->window
)
2809 redrawMaximizeButton(flags
.maximized
);
2810 else if (frame
.iconify_button
== ee
->window
)
2811 redrawIconifyButton(False
);
2815 void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent
*cr
) {
2816 if (cr
->window
!= client
.window
|| flags
.iconic
)
2819 if (cr
->value_mask
& CWBorderWidth
)
2820 client
.old_bw
= cr
->border_width
;
2822 if (cr
->value_mask
& (CWX
| CWY
| CWWidth
| CWHeight
)) {
2823 Rect req
= frame
.rect
;
2825 if (cr
->value_mask
& (CWX
| CWY
)) {
2826 if (cr
->value_mask
& CWX
)
2827 client
.rect
.setX(cr
->x
);
2828 if (cr
->value_mask
& CWY
)
2829 client
.rect
.setY(cr
->y
);
2834 if (cr
->value_mask
& CWWidth
)
2835 req
.setWidth(cr
->width
+ frame
.margin
.left
+ frame
.margin
.right
);
2837 if (cr
->value_mask
& CWHeight
)
2838 req
.setHeight(cr
->height
+ frame
.margin
.top
+ frame
.margin
.bottom
);
2840 configure(req
.x(), req
.y(), req
.width(), req
.height());
2843 if (cr
->value_mask
& CWStackMode
&& !isDesktop()) {
2844 switch (cr
->detail
) {
2847 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2853 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2860 void BlackboxWindow::buttonPressEvent(const XButtonEvent
*be
) {
2862 fprintf(stderr
, "BlackboxWindow::buttonPressEvent() for 0x%lx\n",
2866 if (frame
.maximize_button
== be
->window
&& be
->button
<= 3) {
2867 redrawMaximizeButton(True
);
2868 } else if (be
->button
== 1 || (be
->button
== 3 && be
->state
== ModMask
)) {
2869 if (! flags
.focused
)
2872 if (frame
.iconify_button
== be
->window
) {
2873 redrawIconifyButton(True
);
2874 } else if (frame
.close_button
== be
->window
) {
2875 redrawCloseButton(True
);
2876 } else if (frame
.plate
== be
->window
) {
2877 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2879 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2881 XAllowEvents(blackbox
->getXDisplay(), ReplayPointer
, be
->time
);
2883 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
2884 if (((be
->time
- lastButtonPressTime
) <=
2885 blackbox
->getDoubleClickInterval()) ||
2886 (be
->state
== ControlMask
)) {
2887 lastButtonPressTime
= 0;
2890 lastButtonPressTime
= be
->time
;
2894 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2896 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2898 } else if (be
->button
== 2 && (be
->window
!= frame
.iconify_button
) &&
2899 (be
->window
!= frame
.close_button
)) {
2900 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2901 } else if (windowmenu
&& be
->button
== 3 &&
2902 (frame
.title
== be
->window
|| frame
.label
== be
->window
||
2903 frame
.handle
== be
->window
|| frame
.window
== be
->window
)) {
2904 if (windowmenu
->isVisible()) {
2907 int mx
= be
->x_root
- windowmenu
->getWidth() / 2,
2908 my
= be
->y_root
- windowmenu
->getHeight() / 2;
2910 // snap the window menu into a corner/side if necessary
2911 int left_edge
, right_edge
, top_edge
, bottom_edge
;
2914 the " + (frame.border_w * 2) - 1" bits are to get the proper width
2915 and height of the menu, as the sizes returned by it do not include
2918 left_edge
= frame
.rect
.x();
2919 right_edge
= frame
.rect
.right() -
2920 (windowmenu
->getWidth() + (frame
.border_w
* 2) - 1);
2921 top_edge
= client
.rect
.top() - (frame
.border_w
+ frame
.mwm_border_w
);
2922 bottom_edge
= client
.rect
.bottom() -
2923 (windowmenu
->getHeight() + (frame
.border_w
* 2) - 1) +
2924 (frame
.border_w
+ frame
.mwm_border_w
);
2928 if (mx
> right_edge
)
2932 if (my
> bottom_edge
)
2935 windowmenu
->move(mx
, my
);
2937 XRaiseWindow(blackbox
->getXDisplay(), windowmenu
->getWindowID());
2938 XRaiseWindow(blackbox
->getXDisplay(),
2939 windowmenu
->getSendToMenu()->getWindowID());
2942 } else if (be
->button
== 4) {
2943 if ((be
->window
== frame
.label
||
2944 be
->window
== frame
.title
||
2945 be
->window
== frame
.maximize_button
||
2946 be
->window
== frame
.iconify_button
||
2947 be
->window
== frame
.close_button
) &&
2951 } else if (be
->button
== 5) {
2952 if ((be
->window
== frame
.label
||
2953 be
->window
== frame
.title
||
2954 be
->window
== frame
.maximize_button
||
2955 be
->window
== frame
.iconify_button
||
2956 be
->window
== frame
.close_button
) &&
2963 void BlackboxWindow::buttonReleaseEvent(const XButtonEvent
*re
) {
2965 fprintf(stderr
, "BlackboxWindow::buttonReleaseEvent() for 0x%lx\n",
2969 if (re
->window
== frame
.maximize_button
&&
2970 re
->button
>= 1 && re
->button
<= 3) {
2971 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2972 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2973 maximize(re
->button
);
2975 redrawMaximizeButton(flags
.maximized
);
2977 } else if (re
->window
== frame
.iconify_button
&& re
->button
== 1) {
2978 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2979 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2982 redrawIconifyButton(False
);
2984 } else if (re
->window
== frame
.close_button
& re
->button
== 1) {
2985 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2986 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
)))
2988 redrawCloseButton(False
);
2989 } else if (flags
.moving
) {
2991 } else if (flags
.resizing
) {
2993 } else if (re
->window
== frame
.window
) {
2994 if (re
->button
== 2 && re
->state
== ModMask
)
2995 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3001 void BlackboxWindow::beginMove(int x_root
, int y_root
) {
3002 assert(! (flags
.resizing
|| flags
.moving
));
3005 Only one window can be moved/resized at a time. If another window is already
3006 being moved or resized, then stop it before whating to work with this one.
3008 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3009 if (changing
&& changing
!= this) {
3010 if (changing
->flags
.moving
)
3011 changing
->endMove();
3012 else // if (changing->flags.resizing)
3013 changing
->endResize();
3016 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3017 PointerMotionMask
| ButtonReleaseMask
,
3018 GrabModeAsync
, GrabModeAsync
,
3019 None
, blackbox
->getMoveCursor(), CurrentTime
);
3021 if (windowmenu
&& windowmenu
->isVisible())
3024 flags
.moving
= True
;
3025 blackbox
->setChangingWindow(this);
3027 if (! screen
->doOpaqueMove()) {
3028 XGrabServer(blackbox
->getXDisplay());
3030 frame
.changing
= frame
.rect
;
3031 screen
->showPosition(frame
.changing
.x(), frame
.changing
.y());
3033 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3037 frame
.changing
.width() - 1,
3038 frame
.changing
.height() - 1);
3041 frame
.grab_x
= x_root
- frame
.rect
.x() - frame
.border_w
;
3042 frame
.grab_y
= y_root
- frame
.rect
.y() - frame
.border_w
;
3046 void BlackboxWindow::doMove(int x_root
, int y_root
) {
3047 assert(flags
.moving
);
3048 assert(blackbox
->getChangingWindow() == this);
3050 int dx
= x_root
- frame
.grab_x
, dy
= y_root
- frame
.grab_y
;
3051 dx
-= frame
.border_w
;
3052 dy
-= frame
.border_w
;
3054 if (screen
->doWorkspaceWarping())
3055 if (doWorkspaceWarping(x_root
, y_root
, dx
, dy
))
3058 doWindowSnapping(dx
, dy
);
3060 if (screen
->doOpaqueMove()) {
3061 configure(dx
, dy
, frame
.rect
.width(), frame
.rect
.height());
3063 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3067 frame
.changing
.width() - 1,
3068 frame
.changing
.height() - 1);
3070 frame
.changing
.setPos(dx
, dy
);
3072 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3076 frame
.changing
.width() - 1,
3077 frame
.changing
.height() - 1);
3080 screen
->showPosition(dx
, dy
);
3084 bool BlackboxWindow::doWorkspaceWarping(int x_root
, int y_root
,
3086 // workspace warping
3088 unsigned int dest
= screen
->getCurrentWorkspaceID();
3092 if (dest
> 0) dest
--;
3093 else dest
= screen
->getNumberOfWorkspaces() - 1;
3095 } else if (x_root
>= screen
->getRect().right()) {
3098 if (dest
< screen
->getNumberOfWorkspaces() - 1) dest
++;
3105 bool focus
= flags
.focused
; // had focus while moving?
3107 screen
->reassociateWindow(this, dest
, False
);
3108 screen
->changeWorkspaceID(dest
);
3113 We grab the X server here because we are moving the window and then the
3114 mouse cursor. When one moves, it could end up putting the mouse cursor
3115 over another window for a moment. This can cause the warp to iniate a
3116 move on another window.
3118 XGrabServer(blackbox
->getXDisplay());
3121 dest_x
= screen
->getRect().right() - 1;
3122 configure(dx
+ (screen
->getRect().width() - 1), dy
,
3123 frame
.rect
.width(), frame
.rect
.height());
3126 configure(dx
- (screen
->getRect().width() - 1), dy
,
3127 frame
.rect
.width(), frame
.rect
.height());
3129 XWarpPointer(blackbox
->getXDisplay(), None
,
3130 screen
->getRootWindow(), 0, 0, 0, 0,
3132 XUngrabServer(blackbox
->getXDisplay());
3134 beginMove(dest_x
, y_root
);
3139 void BlackboxWindow::doWindowSnapping(int &dx
, int &dy
) {
3140 // how much resistance to edges to provide
3141 const int resistance_size
= screen
->getResistanceSize();
3143 // how far away to snap
3144 const int snap_distance
= screen
->getSnapThreshold();
3146 // how to snap windows
3147 const int snap_to_windows
= screen
->getWindowToWindowSnap();
3148 const int snap_to_edges
= screen
->getWindowToEdgeSnap();
3149 // the amount of space away from the edge to provide resistance/snap
3150 const int snap_offset
= screen
->getSnapOffset();
3152 // find the geomeetery where the moving window currently is
3153 const Rect
&moving
= screen
->doOpaqueMove() ? frame
.rect
: frame
.changing
;
3156 const int wleft
= dx
,
3157 wright
= dx
+ frame
.rect
.width() - 1,
3159 wbottom
= dy
+ frame
.rect
.height() - 1;
3161 if (snap_to_windows
) {
3164 Workspace
*w
= screen
->getWorkspace(getWorkspaceNumber());
3167 // add windows on the workspace to the rect list
3168 const BlackboxWindowList
& stack_list
= w
->getStackingList();
3169 BlackboxWindowList::const_iterator st_it
, st_end
= stack_list
.end();
3170 for (st_it
= stack_list
.begin(); st_it
!= st_end
; ++st_it
)
3171 if (*st_it
!= this) // don't snap to ourself
3172 rectlist
.push_back( (*st_it
)->frameRect() );
3174 // add the toolbar and the slit to the rect list.
3175 // (only if they are not hidden)
3176 Toolbar
*tbar
= screen
->getToolbar();
3177 Slit
*slit
= screen
->getSlit();
3178 Rect tbar_rect
, slit_rect
;
3179 unsigned int bwidth
= screen
->getBorderWidth() * 2;
3181 if (! (screen
->doHideToolbar() || tbar
->isHidden())) {
3182 tbar_rect
.setRect(tbar
->getX(), tbar
->getY(), tbar
->getWidth() + bwidth
,
3183 tbar
->getHeight() + bwidth
);
3184 rectlist
.push_back(tbar_rect
);
3187 if (! slit
->isHidden()) {
3188 slit_rect
.setRect(slit
->getX(), slit
->getY(), slit
->getWidth() + bwidth
,
3189 slit
->getHeight() + bwidth
);
3190 rectlist
.push_back(slit_rect
);
3193 RectList::const_iterator it
, end
= rectlist
.end();
3194 for (it
= rectlist
.begin(); it
!= end
; ++it
) {
3195 bool snapped
= False
;
3196 const Rect
&winrect
= *it
;
3198 offsetrect
.setCoords(winrect
.left() - snap_offset
,
3199 winrect
.top() - snap_offset
,
3200 winrect
.right() + snap_offset
,
3201 winrect
.bottom() + snap_offset
);
3203 if (snap_to_windows
== BScreen::WindowResistance
)
3204 // if the window is already over top of this snap target, then
3205 // resistance is futile, so just ignore it
3206 if (winrect
.intersects(moving
))
3209 int dleft
, dright
, dtop
, dbottom
;
3211 // if the windows are in the same plane vertically
3212 if (wtop
>= (signed)(winrect
.y() - frame
.rect
.height() + 1) &&
3213 wtop
< (signed)(winrect
.y() + winrect
.height() - 1)) {
3215 if (snap_to_windows
== BScreen::WindowResistance
) {
3216 dleft
= wright
- offsetrect
.left();
3217 dright
= offsetrect
.right() - wleft
;
3219 // snap left of other window?
3220 if (dleft
>= 0 && dleft
< resistance_size
&&
3221 dleft
< (wright
- wleft
)) {
3222 dx
= offsetrect
.left() - frame
.rect
.width();
3225 // snap right of other window?
3226 else if (dright
>= 0 && dright
< resistance_size
&&
3227 dright
< (wright
- wleft
)) {
3228 dx
= offsetrect
.right() + 1;
3231 } else { // BScreen::WindowSnap
3232 dleft
= abs(wright
- offsetrect
.left());
3233 dright
= abs(wleft
- offsetrect
.right());
3235 // snap left of other window?
3236 if (dleft
< snap_distance
&& dleft
<= dright
) {
3237 dx
= offsetrect
.left() - frame
.rect
.width();
3240 // snap right of other window?
3241 else if (dright
< snap_distance
) {
3242 dx
= offsetrect
.right() + 1;
3248 if (screen
->getWindowCornerSnap()) {
3249 // try corner-snap to its other sides
3250 if (snap_to_windows
== BScreen::WindowResistance
) {
3251 dtop
= winrect
.top() - wtop
;
3252 dbottom
= wbottom
- winrect
.bottom();
3253 if (dtop
> 0 && dtop
< resistance_size
) {
3254 // if we're already past the top edge, then don't provide
3256 if (moving
.top() >= winrect
.top())
3258 } else if (dbottom
> 0 && dbottom
< resistance_size
) {
3259 // if we're already past the bottom edge, then don't provide
3261 if (moving
.bottom() <= winrect
.bottom())
3262 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
3264 } else { // BScreen::WindowSnap
3265 dtop
= abs(wtop
- winrect
.top());
3266 dbottom
= abs(wbottom
- winrect
.bottom());
3267 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3269 else if (dbottom
< snap_distance
)
3270 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
3278 // if the windows are on the same plane horizontally
3279 if (wleft
>= (signed)(winrect
.x() - frame
.rect
.width() + 1) &&
3280 wleft
< (signed)(winrect
.x() + winrect
.width() - 1)) {
3282 if (snap_to_windows
== BScreen::WindowResistance
) {
3283 dtop
= wbottom
- offsetrect
.top();
3284 dbottom
= offsetrect
.bottom() - wtop
;
3286 // snap top of other window?
3287 if (dtop
>= 0 && dtop
< resistance_size
&& dtop
< (wbottom
- wtop
)) {
3288 dy
= offsetrect
.top() - frame
.rect
.height();
3291 // snap bottom of other window?
3292 else if (dbottom
>= 0 && dbottom
< resistance_size
&&
3293 dbottom
< (wbottom
- wtop
)) {
3294 dy
= offsetrect
.bottom() + 1;
3297 } else { // BScreen::WindowSnap
3298 dtop
= abs(wbottom
- offsetrect
.top());
3299 dbottom
= abs(wtop
- offsetrect
.bottom());
3301 // snap top of other window?
3302 if (dtop
< snap_distance
&& dtop
<= dbottom
) {
3303 dy
= offsetrect
.top() - frame
.rect
.height();
3306 // snap bottom of other window?
3307 else if (dbottom
< snap_distance
) {
3308 dy
= offsetrect
.bottom() + 1;
3315 if (screen
->getWindowCornerSnap()) {
3316 // try corner-snap to its other sides
3317 if (snap_to_windows
== BScreen::WindowResistance
) {
3318 dleft
= winrect
.left() - wleft
;
3319 dright
= wright
- winrect
.right();
3320 if (dleft
> 0 && dleft
< resistance_size
) {
3321 // if we're already past the left edge, then don't provide
3323 if (moving
.left() >= winrect
.left())
3324 dx
= winrect
.left();
3325 } else if (dright
> 0 && dright
< resistance_size
) {
3326 // if we're already past the right edge, then don't provide
3328 if (moving
.right() <= winrect
.right())
3329 dx
= winrect
.right() - frame
.rect
.width() + 1;
3331 } else { // BScreen::WindowSnap
3332 dleft
= abs(wleft
- winrect
.left());
3333 dright
= abs(wright
- winrect
.right());
3334 if (dleft
< snap_distance
&& dleft
<= dright
)
3335 dx
= winrect
.left();
3336 else if (dright
< snap_distance
)
3337 dx
= winrect
.right() - frame
.rect
.width() + 1;
3347 if (snap_to_edges
) {
3350 // snap to the screen edges (and screen boundaries for xinerama)
3352 if (screen
->isXineramaActive() && blackbox
->doXineramaSnapping()) {
3353 rectlist
.insert(rectlist
.begin(),
3354 screen
->getXineramaAreas().begin(),
3355 screen
->getXineramaAreas().end());
3358 rectlist
.push_back(screen
->getRect());
3360 RectList::const_iterator it
, end
= rectlist
.end();
3361 for (it
= rectlist
.begin(); it
!= end
; ++it
) {
3362 const Rect
&srect
= *it
;
3364 offsetrect
.setCoords(srect
.left() + snap_offset
,
3365 srect
.top() + snap_offset
,
3366 srect
.right() - snap_offset
,
3367 srect
.bottom() - snap_offset
);
3369 if (snap_to_edges
== BScreen::WindowResistance
) {
3370 // if we're not in the rectangle then don't snap to it.
3371 if (! srect
.contains(moving
))
3373 } else { // BScreen::WindowSnap
3374 // if we're not in the rectangle then don't snap to it.
3375 if (! srect
.intersects(Rect(wleft
, wtop
, frame
.rect
.width(),
3376 frame
.rect
.height())))
3380 if (snap_to_edges
== BScreen::WindowResistance
) {
3381 int dleft
= offsetrect
.left() - wleft
,
3382 dright
= wright
- offsetrect
.right(),
3383 dtop
= offsetrect
.top() - wtop
,
3384 dbottom
= wbottom
- offsetrect
.bottom();
3387 if (dleft
> 0 && dleft
< resistance_size
)
3388 dx
= offsetrect
.left();
3390 else if (dright
> 0 && dright
< resistance_size
)
3391 dx
= offsetrect
.right() - frame
.rect
.width() + 1;
3394 if (dtop
> 0 && dtop
< resistance_size
)
3395 dy
= offsetrect
.top();
3397 else if (dbottom
> 0 && dbottom
< resistance_size
)
3398 dy
= offsetrect
.bottom() - frame
.rect
.height() + 1;
3399 } else { // BScreen::WindowSnap
3400 int dleft
= abs(wleft
- offsetrect
.left()),
3401 dright
= abs(wright
- offsetrect
.right()),
3402 dtop
= abs(wtop
- offsetrect
.top()),
3403 dbottom
= abs(wbottom
- offsetrect
.bottom());
3406 if (dleft
< snap_distance
&& dleft
<= dright
)
3407 dx
= offsetrect
.left();
3409 else if (dright
< snap_distance
)
3410 dx
= offsetrect
.right() - frame
.rect
.width() + 1;
3413 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3414 dy
= offsetrect
.top();
3416 else if (dbottom
< snap_distance
)
3417 dy
= offsetrect
.bottom() - frame
.rect
.height() + 1;
3424 void BlackboxWindow::endMove(void) {
3425 assert(flags
.moving
);
3426 assert(blackbox
->getChangingWindow() == this);
3428 flags
.moving
= False
;
3429 blackbox
->setChangingWindow(0);
3431 if (! screen
->doOpaqueMove()) {
3432 /* when drawing the rubber band, we need to make sure we only draw inside
3433 * the frame... frame.changing_* contain the new coords for the window,
3434 * so we need to subtract 1 from changing_w/changing_h every where we
3435 * draw the rubber band (for both moving and resizing)
3437 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3438 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3439 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3440 XUngrabServer(blackbox
->getXDisplay());
3442 configure(frame
.changing
.x(), frame
.changing
.y(),
3443 frame
.changing
.width(), frame
.changing
.height());
3445 configure(frame
.rect
.x(), frame
.rect
.y(),
3446 frame
.rect
.width(), frame
.rect
.height());
3448 screen
->hideGeometry();
3450 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3452 // if there are any left over motions from the move, drop them now
3453 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3455 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3460 void BlackboxWindow::beginResize(int x_root
, int y_root
, Corner dir
) {
3461 assert(! (flags
.resizing
|| flags
.moving
));
3464 Only one window can be moved/resized at a time. If another window is already
3465 being moved or resized, then stop it before whating to work with this one.
3467 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3468 if (changing
&& changing
!= this) {
3469 if (changing
->flags
.moving
)
3470 changing
->endMove();
3471 else // if (changing->flags.resizing)
3472 changing
->endResize();
3480 switch (resize_dir
) {
3483 cursor
= blackbox
->getLowerLeftAngleCursor();
3488 cursor
= blackbox
->getLowerRightAngleCursor();
3492 anchor
= BottomRight
;
3493 cursor
= blackbox
->getUpperLeftAngleCursor();
3497 anchor
= BottomLeft
;
3498 cursor
= blackbox
->getUpperRightAngleCursor();
3502 assert(false); // unhandled Corner
3503 return; // unreachable, for the compiler
3506 XGrabServer(blackbox
->getXDisplay());
3507 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3508 PointerMotionMask
| ButtonReleaseMask
,
3509 GrabModeAsync
, GrabModeAsync
, None
, cursor
, CurrentTime
);
3511 flags
.resizing
= True
;
3512 blackbox
->setChangingWindow(this);
3514 unsigned int gw
, gh
;
3515 frame
.changing
= frame
.rect
;
3517 constrain(anchor
, &gw
, &gh
);
3519 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3520 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3521 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3523 screen
->showGeometry(gw
, gh
);
3525 frame
.grab_x
= x_root
;
3526 frame
.grab_y
= y_root
;
3530 void BlackboxWindow::doResize(int x_root
, int y_root
) {
3531 assert(flags
.resizing
);
3532 assert(blackbox
->getChangingWindow() == this);
3534 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3535 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3536 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3538 unsigned int gw
, gh
;
3541 switch (resize_dir
) {
3544 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3545 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3549 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3550 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3553 anchor
= BottomRight
;
3554 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3555 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3558 anchor
= BottomLeft
;
3559 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3560 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3564 assert(false); // unhandled Corner
3565 return; // unreachable, for the compiler
3568 constrain(anchor
, &gw
, &gh
);
3570 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3571 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3572 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3574 screen
->showGeometry(gw
, gh
);
3578 void BlackboxWindow::endResize(void) {
3579 assert(flags
.resizing
);
3580 assert(blackbox
->getChangingWindow() == this);
3582 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3583 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3584 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3585 XUngrabServer(blackbox
->getXDisplay());
3587 // unset maximized state after resized when fully maximized
3588 if (flags
.maximized
== 1)
3591 flags
.resizing
= False
;
3592 blackbox
->setChangingWindow(0);
3594 configure(frame
.changing
.x(), frame
.changing
.y(),
3595 frame
.changing
.width(), frame
.changing
.height());
3596 screen
->hideGeometry();
3598 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3600 // if there are any left over motions from the resize, drop them now
3601 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3603 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3608 void BlackboxWindow::motionNotifyEvent(const XMotionEvent
*me
) {
3610 fprintf(stderr
, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n",
3615 doMove(me
->x_root
, me
->y_root
);
3616 } else if (flags
.resizing
) {
3617 doResize(me
->x_root
, me
->y_root
);
3619 if (!flags
.resizing
&& me
->state
& Button1Mask
&& (functions
& Func_Move
) &&
3620 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3621 frame
.handle
== me
->window
|| frame
.window
== me
->window
)) {
3622 beginMove(me
->x_root
, me
->y_root
);
3623 } else if ((functions
& Func_Resize
) &&
3624 (me
->state
& Button1Mask
&& (me
->window
== frame
.right_grip
||
3625 me
->window
== frame
.left_grip
)) ||
3626 (me
->state
& Button3Mask
&& me
->state
& ModMask
&&
3627 me
->window
== frame
.window
)) {
3628 unsigned int zones
= screen
->getResizeZones();
3631 if (me
->window
== frame
.left_grip
) {
3632 corner
= BottomLeft
;
3633 } else if (me
->window
== frame
.right_grip
|| zones
== 1) {
3634 corner
= BottomRight
;
3637 bool left
= (me
->x_root
- frame
.rect
.x() <=
3638 static_cast<signed>(frame
.rect
.width() / 2));
3641 else // (zones == 4)
3642 top
= (me
->y_root
- frame
.rect
.y() <=
3643 static_cast<signed>(frame
.rect
.height() / 2));
3644 corner
= (top
? (left
? TopLeft
: TopRight
) :
3645 (left
? BottomLeft
: BottomRight
));
3648 beginResize(me
->x_root
, me
->y_root
, corner
);
3654 void BlackboxWindow::enterNotifyEvent(const XCrossingEvent
* ce
) {
3655 if (! (screen
->isSloppyFocus() && isVisible() && isNormal()))
3659 bool leave
= False
, inferior
= False
;
3661 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), ce
->window
,
3663 if (e
.type
== LeaveNotify
&& e
.xcrossing
.mode
== NotifyNormal
) {
3665 inferior
= (e
.xcrossing
.detail
== NotifyInferior
);
3669 if ((! leave
|| inferior
) && ! isFocused()) {
3670 bool success
= setInputFocus();
3671 if (success
) // if focus succeeded install the colormap
3672 installColormap(True
); // XXX: shouldnt we honour no install?
3675 if (screen
->doAutoRaise())
3680 void BlackboxWindow::leaveNotifyEvent(const XCrossingEvent
*) {
3681 if (! (screen
->isSloppyFocus() && screen
->doAutoRaise() && isNormal()))
3684 installColormap(False
);
3686 if (timer
->isTiming())
3692 void BlackboxWindow::shapeEvent(XShapeEvent
*) {
3693 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
3700 bool BlackboxWindow::validateClient(void) const {
3701 XSync(blackbox
->getXDisplay(), False
);
3704 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3705 DestroyNotify
, &e
) ||
3706 XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3708 XPutBackEvent(blackbox
->getXDisplay(), &e
);
3717 void BlackboxWindow::restore(bool remap
) {
3718 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeDelete
);
3719 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
3720 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, NoEventMask
);
3722 // do not leave a shaded window as an icon unless it was an icon
3723 if (flags
.shaded
&& ! flags
.iconic
)
3724 setState(NormalState
);
3726 restoreGravity(client
.rect
);
3728 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
3729 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
3731 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, client
.old_bw
);
3734 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3735 ReparentNotify
, &ev
)) {
3738 // according to the ICCCM - if the client doesn't reparent to
3739 // root, then we have to do it for them
3740 XReparentWindow(blackbox
->getXDisplay(), client
.window
,
3741 screen
->getRootWindow(),
3742 client
.rect
.x(), client
.rect
.y());
3745 if (remap
) XMapWindow(blackbox
->getXDisplay(), client
.window
);
3749 // timer for autoraise
3750 void BlackboxWindow::timeout(void) {
3751 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3755 void BlackboxWindow::changeBlackboxHints(const BlackboxHints
*net
) {
3756 if ((net
->flags
& AttribShaded
) &&
3757 ((blackbox_attrib
.attrib
& AttribShaded
) !=
3758 (net
->attrib
& AttribShaded
)))
3761 if (flags
.visible
&& // watch out for requests when we can not be seen
3762 (net
->flags
& (AttribMaxVert
| AttribMaxHoriz
)) &&
3763 ((blackbox_attrib
.attrib
& (AttribMaxVert
| AttribMaxHoriz
)) !=
3764 (net
->attrib
& (AttribMaxVert
| AttribMaxHoriz
)))) {
3765 if (flags
.maximized
) {
3770 if ((net
->flags
& AttribMaxHoriz
) && (net
->flags
& AttribMaxVert
))
3771 button
= ((net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0);
3772 else if (net
->flags
& AttribMaxVert
)
3773 button
= ((net
->attrib
& AttribMaxVert
) ? 2 : 0);
3774 else if (net
->flags
& AttribMaxHoriz
)
3775 button
= ((net
->attrib
& AttribMaxHoriz
) ? 3 : 0);
3781 if ((net
->flags
& AttribOmnipresent
) &&
3782 ((blackbox_attrib
.attrib
& AttribOmnipresent
) !=
3783 (net
->attrib
& AttribOmnipresent
)))
3786 if ((net
->flags
& AttribWorkspace
) &&
3787 (blackbox_attrib
.workspace
!= net
->workspace
)) {
3788 screen
->reassociateWindow(this, net
->workspace
, True
);
3790 if (screen
->getCurrentWorkspaceID() != net
->workspace
) {
3794 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3798 if (net
->flags
& AttribDecoration
) {
3799 switch (net
->decoration
) {
3812 // we can not be shaded if we lack a titlebar
3813 if (flags
.shaded
&& ! (decorations
& Decor_Titlebar
))
3816 if (flags
.visible
&& frame
.window
) {
3817 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
3818 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
3822 setState(current_state
);
3828 * Set the sizes of all components of the window frame
3829 * (the window decorations).
3830 * These values are based upon the current style settings and the client
3831 * window's dimensions.
3833 void BlackboxWindow::upsize(void) {
3834 frame
.bevel_w
= screen
->getBevelWidth();
3836 if (decorations
& Decor_Border
) {
3837 frame
.border_w
= screen
->getBorderWidth();
3838 if (! isTransient())
3839 frame
.mwm_border_w
= screen
->getFrameWidth();
3841 frame
.mwm_border_w
= 0;
3843 frame
.mwm_border_w
= frame
.border_w
= 0;
3846 if (decorations
& Decor_Titlebar
) {
3847 // the height of the titlebar is based upon the height of the font being
3848 // used to display the window's title
3849 WindowStyle
*style
= screen
->getWindowStyle();
3850 frame
.title_h
= style
->font
->height() + (frame
.bevel_w
* 2) + 2;
3852 frame
.label_h
= frame
.title_h
- (frame
.bevel_w
* 2);
3853 frame
.button_w
= (frame
.label_h
- 2);
3855 // set the top frame margin
3856 frame
.margin
.top
= frame
.border_w
+ frame
.title_h
+
3857 frame
.border_w
+ frame
.mwm_border_w
;
3863 // set the top frame margin
3864 frame
.margin
.top
= frame
.border_w
+ frame
.mwm_border_w
;
3867 // set the left/right frame margin
3868 frame
.margin
.left
= frame
.margin
.right
= frame
.border_w
+ frame
.mwm_border_w
;
3870 if (decorations
& Decor_Handle
) {
3871 frame
.grip_w
= frame
.button_w
* 2;
3872 frame
.handle_h
= screen
->getHandleWidth();
3874 // set the bottom frame margin
3875 frame
.margin
.bottom
= frame
.border_w
+ frame
.handle_h
+
3876 frame
.border_w
+ frame
.mwm_border_w
;
3881 // set the bottom frame margin
3882 frame
.margin
.bottom
= frame
.border_w
+ frame
.mwm_border_w
;
3886 We first get the normal dimensions and use this to define the inside_w/h
3887 then we modify the height if shading is in effect.
3888 If the shade state is not considered then frame.rect gets reset to the
3889 normal window size on a reconfigure() call resulting in improper
3890 dimensions appearing in move/resize and other events.
3893 height
= client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
,
3894 width
= client
.rect
.width() + frame
.margin
.left
+ frame
.margin
.right
;
3896 frame
.inside_w
= width
- (frame
.border_w
* 2);
3897 frame
.inside_h
= height
- (frame
.border_w
* 2);
3900 height
= frame
.title_h
+ (frame
.border_w
* 2);
3901 frame
.rect
.setSize(width
, height
);
3906 * Calculate the size of the client window and constrain it to the
3907 * size specified by the size hints of the client window.
3909 * The logical width and height are placed into pw and ph, if they
3910 * are non-zero. Logical size refers to the users perception of
3911 * the window size (for example an xterm resizes in cells, not in pixels).
3912 * pw and ph are then used to display the geometry during window moves, resize,
3915 * The physical geometry is placed into frame.changing_{x,y,width,height}.
3916 * Physical geometry refers to the geometry of the window in pixels.
3918 void BlackboxWindow::constrain(Corner anchor
,
3919 unsigned int *pw
, unsigned int *ph
) {
3920 // frame.changing represents the requested frame size, we need to
3921 // strip the frame margin off and constrain the client size
3922 frame
.changing
.setCoords(frame
.changing
.left() + frame
.margin
.left
,
3923 frame
.changing
.top() + frame
.margin
.top
,
3924 frame
.changing
.right() - frame
.margin
.right
,
3925 frame
.changing
.bottom() - frame
.margin
.bottom
);
3927 unsigned int dw
= frame
.changing
.width(), dh
= frame
.changing
.height(),
3928 base_width
= (client
.base_width
) ? client
.base_width
: client
.min_width
,
3929 base_height
= (client
.base_height
) ? client
.base_height
:
3933 if (dw
< client
.min_width
) dw
= client
.min_width
;
3934 if (dh
< client
.min_height
) dh
= client
.min_height
;
3935 if (dw
> client
.max_width
) dw
= client
.max_width
;
3936 if (dh
> client
.max_height
) dh
= client
.max_height
;
3938 assert(dw
>= base_width
&& dh
>= base_height
);
3940 if (client
.width_inc
> 1) {
3942 dw
/= client
.width_inc
;
3944 if (client
.height_inc
> 1) {
3946 dh
/= client
.height_inc
;
3955 if (client
.width_inc
> 1) {
3956 dw
*= client
.width_inc
;
3959 if (client
.height_inc
> 1) {
3960 dh
*= client
.height_inc
;
3964 frame
.changing
.setSize(dw
, dh
);
3966 // add the frame margin back onto frame.changing
3967 frame
.changing
.setCoords(frame
.changing
.left() - frame
.margin
.left
,
3968 frame
.changing
.top() - frame
.margin
.top
,
3969 frame
.changing
.right() + frame
.margin
.right
,
3970 frame
.changing
.bottom() + frame
.margin
.bottom
);
3972 // move frame.changing to the specified anchor
3980 dx
= frame
.rect
.right() - frame
.changing
.right();
3984 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3988 dx
= frame
.rect
.right() - frame
.changing
.right();
3989 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3993 assert(false); // unhandled corner
3995 frame
.changing
.setPos(frame
.changing
.x() + dx
, frame
.changing
.y() + dy
);
3999 void WindowStyle::doJustify(const std::string
&text
, int &start_pos
,
4000 unsigned int max_length
,
4001 unsigned int modifier
) const {
4002 size_t text_len
= text
.size();
4003 unsigned int length
;
4006 length
= font
->measureString(string(text
, 0, text_len
)) + modifier
;
4007 } while (length
> max_length
&& text_len
-- > 0);
4011 start_pos
+= max_length
- length
;
4015 start_pos
+= (max_length
- length
) / 2;
4025 BWindowGroup::BWindowGroup(Blackbox
*b
, Window _group
)
4026 : blackbox(b
), group(_group
) {
4027 XWindowAttributes wattrib
;
4028 if (! XGetWindowAttributes(blackbox
->getXDisplay(), group
, &wattrib
)) {
4029 // group window doesn't seem to exist anymore
4034 XSelectInput(blackbox
->getXDisplay(), group
,
4035 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
4037 blackbox
->saveGroupSearch(group
, this);
4041 BWindowGroup::~BWindowGroup(void) {
4042 blackbox
->removeGroupSearch(group
);
4047 BWindowGroup::find(BScreen
*screen
, bool allow_transients
) const {
4048 BlackboxWindow
*ret
= blackbox
->getFocusedWindow();
4050 // does the focus window match (or any transient_fors)?
4051 for (; ret
; ret
= ret
->getTransientFor()) {
4052 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
&&
4053 (! ret
->isTransient() || allow_transients
))
4057 if (ret
) return ret
;
4059 // the focus window didn't match, look in the group's window list
4060 BlackboxWindowList::const_iterator it
, end
= windowList
.end();
4061 for (it
= windowList
.begin(); it
!= end
; ++it
) {
4063 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
&&
4064 (! ret
->isTransient() || allow_transients
))