1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2 // Window.cc for Blackbox - an X11 Window manager
3 // Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry <shaleh at debian.org>
4 // Copyright (c) 1997 - 2000, 2002 Brad Hughes <bhughes at trolltech.com>
6 // Permission is hereby granted, free of charge, to any person obtaining a
7 // copy of this software and associated documentation files (the "Software"),
8 // to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 // and/or sell copies of the Software, and to permit persons to whom the
11 // Software is furnished to do so, subject to the following conditions:
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 // DEALINGS IN THE SOFTWARE.
25 # include "../config.h"
26 #endif // HAVE_CONFIG_H
29 #include <X11/Xatom.h>
30 #include <X11/keysym.h>
34 #endif // HAVE_STRING_H
39 # endif // HAVE_STDIO_H
44 #endif // HAVE_STDLIB_H
48 #include "blackbox.hh"
49 #include "Clientmenu.hh"
52 #include "Iconmenu.hh"
58 #include "Windowmenu.hh"
59 #include "Workspace.hh"
66 * Initializes the class with default values/the window's set initial values.
68 BlackboxWindow::BlackboxWindow(Blackbox
*b
, Window w
, BScreen
*s
) {
69 // fprintf(stderr, "BlackboxWindow size: %d bytes\n",
70 // sizeof(BlackboxWindow));
73 fprintf(stderr
, "BlackboxWindow::BlackboxWindow(): creating 0x%lx\n", w
);
77 set timer to zero... it is initialized properly later, so we check
78 if timer is zero in the destructor, and assume that the window is not
79 fully constructed if timer is zero...
85 xatom
= blackbox
->getXAtom();
87 if (! validateClient()) {
92 // fetch client size and placement
93 XWindowAttributes wattrib
;
94 if (! XGetWindowAttributes(blackbox
->getXDisplay(),
95 client
.window
, &wattrib
) ||
96 ! wattrib
.screen
|| wattrib
.override_redirect
) {
99 "BlackboxWindow::BlackboxWindow(): XGetWindowAttributes failed\n");
106 // set the eventmask early in the game so that we make sure we get
107 // all the events we are interested in
108 XSetWindowAttributes attrib_set
;
109 attrib_set
.event_mask
= PropertyChangeMask
| FocusChangeMask
|
111 attrib_set
.do_not_propagate_mask
= ButtonPressMask
| ButtonReleaseMask
|
113 XChangeWindowAttributes(blackbox
->getXDisplay(), client
.window
,
114 CWEventMask
|CWDontPropagate
, &attrib_set
);
116 flags
.moving
= flags
.resizing
= flags
.shaded
= flags
.visible
=
117 flags
.iconic
= flags
.focused
= flags
.stuck
= flags
.modal
=
118 flags
.send_focus_message
= flags
.shaped
= flags
.skip_taskbar
=
119 flags
.skip_pager
= flags
.fullscreen
= False
;
122 blackbox_attrib
.workspace
= window_number
= BSENTINEL
;
124 blackbox_attrib
.flags
= blackbox_attrib
.attrib
= blackbox_attrib
.stack
= 0l;
125 blackbox_attrib
.decoration
= DecorNormal
;
126 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
127 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
130 frame
.window
= frame
.plate
= frame
.title
= frame
.handle
= None
;
131 frame
.close_button
= frame
.iconify_button
= frame
.maximize_button
= None
;
132 frame
.right_grip
= frame
.left_grip
= None
;
134 frame
.ulabel_pixel
= frame
.flabel_pixel
= frame
.utitle_pixel
=
135 frame
.ftitle_pixel
= frame
.uhandle_pixel
= frame
.fhandle_pixel
=
136 frame
.ubutton_pixel
= frame
.fbutton_pixel
= frame
.pbutton_pixel
=
137 frame
.uborder_pixel
= frame
.fborder_pixel
= frame
.ugrip_pixel
=
138 frame
.fgrip_pixel
= 0;
139 frame
.utitle
= frame
.ftitle
= frame
.uhandle
= frame
.fhandle
= None
;
140 frame
.ulabel
= frame
.flabel
= frame
.ubutton
= frame
.fbutton
= None
;
141 frame
.pbutton
= frame
.ugrip
= frame
.fgrip
= None
;
143 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
144 mwm_decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
145 Decor_Iconify
| Decor_Maximize
| Decor_Close
;
147 client
.normal_hint_flags
= 0;
148 client
.window_group
= None
;
149 client
.transient_for
= 0;
151 current_state
= NormalState
;
156 get the initial size and location of client window (relative to the
157 _root window_). This position is the reference point used with the
158 window's gravity to find the window's initial position.
160 client
.rect
.setRect(wattrib
.x
, wattrib
.y
, wattrib
.width
, wattrib
.height
);
161 client
.old_bw
= wattrib
.border_width
;
163 lastButtonPressTime
= 0;
165 timer
= new BTimer(blackbox
, this);
166 timer
->setTimeout(blackbox
->getAutoRaiseDelay());
168 // get size, aspect, minimum/maximum size and other hints set by the
171 if (! getBlackboxHints())
178 frame
.window
= createToplevelWindow();
180 blackbox
->saveWindowSearch(frame
.window
, this);
182 frame
.plate
= createChildWindow(frame
.window
);
183 blackbox
->saveWindowSearch(frame
.plate
, this);
185 // determine if this is a transient window
188 // determine the window's type, so we can decide its decorations and
189 // functionality, or if we should not manage it at all
190 if (getWindowType()) {
191 // adjust the window decorations/behavior based on the window type
192 switch (window_type
) {
196 blackbox_attrib
.workspace
= 0; // we do need to belong to a workspace
197 flags
.stuck
= True
; // we show up on all workspaces
199 // none of these windows are manipulated by the window manager
205 // these windows get less functionality
206 functions
&= ~(Func_Maximize
| Func_Resize
| Func_Iconify
);
210 // dialogs cannot be maximized
211 functions
&= ~Func_Maximize
;
215 // normal windows retain all of the possible decorations and functionality
222 // further adjeust the window's decorations/behavior based on window sizes
223 if ((client
.normal_hint_flags
& PMinSize
) &&
224 (client
.normal_hint_flags
& PMaxSize
) &&
225 client
.max_width
<= client
.min_width
&&
226 client
.max_height
<= client
.min_height
) {
227 functions
&= ~(Func_Resize
| Func_Maximize
);
234 if (decorations
& Decor_Titlebar
)
237 if (decorations
& Decor_Handle
)
240 // apply the size and gravity hint to the frame
244 bool place_window
= True
;
245 if (blackbox
->isStartup() || isTransient() ||
246 client
.normal_hint_flags
& (PPosition
|USPosition
)) {
247 applyGravity(frame
.rect
);
249 if (blackbox
->isStartup() || client
.rect
.intersects(screen
->getRect()))
250 place_window
= False
;
253 // add the window's strut. note this is done *after* placing the window.
254 screen
->addStrut(&client
.strut
);
258 the server needs to be grabbed here to prevent client's from sending
259 events while we are in the process of configuring their window.
260 We hold the grab until after we are done moving the window around.
263 XGrabServer(blackbox
->getXDisplay());
265 associateClientWindow();
267 blackbox
->saveWindowSearch(client
.window
, this);
269 if (blackbox_attrib
.workspace
>= screen
->getWorkspaceCount())
270 screen
->getCurrentWorkspace()->addWindow(this, place_window
);
272 screen
->getWorkspace(blackbox_attrib
.workspace
)->
273 addWindow(this, place_window
);
275 if (! place_window
) {
276 // don't need to call configure if we are letting the workspace
278 configure(frame
.rect
.x(), frame
.rect
.y(),
279 frame
.rect
.width(), frame
.rect
.height());
285 XUngrabServer(blackbox
->getXDisplay());
288 if (blackbox
->hasShapeExtensions() && flags
.shaped
)
292 // now that we know where to put the window and what it should look like
293 // we apply the decorations
298 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
300 // this ensures the title, buttons, and other decor are properly displayed
303 // preserve the window's initial state on first map, and its current state
305 unsigned long initial_state
= current_state
;
307 current_state
= initial_state
;
309 // get sticky state from our parent window if we've got one
310 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
311 client
.transient_for
->isStuck() != flags
.stuck
)
315 flags
.shaded
= False
;
316 initial_state
= current_state
;
320 At this point in the life of a window, current_state should only be set
321 to IconicState if the window was an *icon*, not if it was shaded.
323 if (initial_state
!= IconicState
)
324 current_state
= NormalState
;
332 if (flags
.maximized
&& (functions
& Func_Maximize
))
335 // create this last so it only needs to be configured once
336 windowmenu
= new Windowmenu(this);
340 BlackboxWindow::~BlackboxWindow(void) {
342 fprintf(stderr
, "BlackboxWindow::~BlackboxWindow: destroying 0x%lx\n",
346 if (! timer
) // window not managed...
352 screen
->removeStrut(&client
.strut
);
353 screen
->updateAvailableArea();
355 // We don't need to worry about resizing because resizing always grabs the X
356 // server. This should only ever happen if using opaque moving.
364 if (client
.window_group
) {
365 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
366 if (group
) group
->removeWindow(this);
369 // remove ourselves from our transient_for
371 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul)
372 client
.transient_for
->client
.transientList
.remove(this);
373 client
.transient_for
= (BlackboxWindow
*) 0;
376 if (client
.transientList
.size() > 0) {
377 // reset transient_for for all transients
378 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
379 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
380 (*it
)->client
.transient_for
= (BlackboxWindow
*) 0;
390 blackbox
->removeWindowSearch(frame
.plate
);
391 XDestroyWindow(blackbox
->getXDisplay(), frame
.plate
);
395 blackbox
->removeWindowSearch(frame
.window
);
396 XDestroyWindow(blackbox
->getXDisplay(), frame
.window
);
399 blackbox
->removeWindowSearch(client
.window
);
403 void BlackboxWindow::enableDecor(bool enable
) {
404 blackbox_attrib
.flags
|= AttribDecoration
;
405 blackbox_attrib
.decoration
= enable
? DecorNormal
: DecorNone
;
408 // we can not be shaded if we lack a titlebar
409 if (! (decorations
& Decor_Titlebar
) && flags
.shaded
)
412 if (flags
.visible
&& frame
.window
) {
413 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
414 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
418 setState(current_state
);
422 void BlackboxWindow::setupDecor() {
423 if (blackbox_attrib
.decoration
!= DecorNone
) {
424 // start with everything on
426 (mwm_decorations
& Decor_Titlebar
? Decor_Titlebar
: 0) |
427 (mwm_decorations
& Decor_Border
? Decor_Border
: 0) |
428 (mwm_decorations
& Decor_Handle
? Decor_Handle
: 0) |
429 (mwm_decorations
& Decor_Iconify
? Decor_Iconify
: 0) |
430 (mwm_decorations
& Decor_Maximize
? Decor_Maximize
: 0) |
431 (mwm_decorations
& Decor_Close
? Decor_Close
: 0);
433 if (! (functions
& Func_Close
)) decorations
&= ~Decor_Close
;
434 if (! (functions
& Func_Maximize
)) decorations
&= ~Decor_Maximize
;
435 if (! (functions
& Func_Iconify
)) decorations
&= ~Decor_Iconify
;
436 if (! (functions
& Func_Resize
)) decorations
&= ~Decor_Handle
;
438 switch (window_type
) {
443 // none of these windows are decorated by the window manager at all
449 decorations
&= ~(Decor_Border
);
453 decorations
&= ~Decor_Handle
;
465 * Creates a new top level window, with a given location, size, and border
467 * Returns: the newly created window
469 Window
BlackboxWindow::createToplevelWindow(void) {
470 XSetWindowAttributes attrib_create
;
471 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
| CWColormap
|
472 CWOverrideRedirect
| CWEventMask
;
474 attrib_create
.background_pixmap
= None
;
475 attrib_create
.colormap
= screen
->getColormap();
476 attrib_create
.override_redirect
= True
;
477 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
479 EnterWindowMask
| LeaveWindowMask
;
481 return XCreateWindow(blackbox
->getXDisplay(), screen
->getRootWindow(),
482 0, 0, 1, 1, frame
.border_w
, screen
->getDepth(),
483 InputOutput
, screen
->getVisual(), create_mask
,
489 * Creates a child window, and optionally associates a given cursor with
492 Window
BlackboxWindow::createChildWindow(Window parent
, Cursor cursor
) {
493 XSetWindowAttributes attrib_create
;
494 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
|
497 attrib_create
.background_pixmap
= None
;
498 attrib_create
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
499 ButtonMotionMask
| ExposureMask
;
502 create_mask
|= CWCursor
;
503 attrib_create
.cursor
= cursor
;
506 return XCreateWindow(blackbox
->getXDisplay(), parent
, 0, 0, 1, 1, 0,
507 screen
->getDepth(), InputOutput
, screen
->getVisual(),
508 create_mask
, &attrib_create
);
512 void BlackboxWindow::associateClientWindow(void) {
513 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, 0);
517 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeInsert
);
519 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, SubstructureRedirectMask
);
522 note we used to grab around this call to XReparentWindow however the
523 server is now grabbed before this method is called
525 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
527 XSelectInput(blackbox
->getXDisplay(), client
.window
,
528 event_mask
& ~StructureNotifyMask
);
529 XReparentWindow(blackbox
->getXDisplay(), client
.window
, frame
.plate
, 0, 0);
530 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
532 XRaiseWindow(blackbox
->getXDisplay(), frame
.plate
);
533 XMapSubwindows(blackbox
->getXDisplay(), frame
.plate
);
536 if (blackbox
->hasShapeExtensions()) {
537 XShapeSelectInput(blackbox
->getXDisplay(), client
.window
,
544 XShapeQueryExtents(blackbox
->getXDisplay(), client
.window
, &shaped
,
545 &foo
, &foo
, &ufoo
, &ufoo
, &foo
, &foo
, &foo
,
547 flags
.shaped
= shaped
;
553 void BlackboxWindow::decorate(void) {
556 texture
= &(screen
->getWindowStyle()->b_focus
);
557 frame
.fbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
560 frame
.fbutton_pixel
= texture
->color().pixel();
562 texture
= &(screen
->getWindowStyle()->b_unfocus
);
563 frame
.ubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
566 frame
.ubutton_pixel
= texture
->color().pixel();
568 texture
= &(screen
->getWindowStyle()->b_pressed
);
569 frame
.pbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
572 frame
.pbutton_pixel
= texture
->color().pixel();
574 if (decorations
& Decor_Titlebar
) {
575 texture
= &(screen
->getWindowStyle()->t_focus
);
576 frame
.ftitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
579 frame
.ftitle_pixel
= texture
->color().pixel();
581 texture
= &(screen
->getWindowStyle()->t_unfocus
);
582 frame
.utitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
585 frame
.utitle_pixel
= texture
->color().pixel();
587 XSetWindowBorder(blackbox
->getXDisplay(), frame
.title
,
588 screen
->getBorderColor()->pixel());
593 if (decorations
& Decor_Border
) {
594 frame
.fborder_pixel
= screen
->getWindowStyle()->f_focus
.pixel();
595 frame
.uborder_pixel
= screen
->getWindowStyle()->f_unfocus
.pixel();
598 if (decorations
& Decor_Handle
) {
599 texture
= &(screen
->getWindowStyle()->h_focus
);
600 frame
.fhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
603 frame
.fhandle_pixel
= texture
->color().pixel();
605 texture
= &(screen
->getWindowStyle()->h_unfocus
);
606 frame
.uhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
609 frame
.uhandle_pixel
= texture
->color().pixel();
611 texture
= &(screen
->getWindowStyle()->g_focus
);
612 frame
.fgrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.fgrip
);
614 frame
.fgrip_pixel
= texture
->color().pixel();
616 texture
= &(screen
->getWindowStyle()->g_unfocus
);
617 frame
.ugrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.ugrip
);
619 frame
.ugrip_pixel
= texture
->color().pixel();
621 XSetWindowBorder(blackbox
->getXDisplay(), frame
.handle
,
622 screen
->getBorderColor()->pixel());
623 XSetWindowBorder(blackbox
->getXDisplay(), frame
.left_grip
,
624 screen
->getBorderColor()->pixel());
625 XSetWindowBorder(blackbox
->getXDisplay(), frame
.right_grip
,
626 screen
->getBorderColor()->pixel());
629 XSetWindowBorder(blackbox
->getXDisplay(), frame
.window
,
630 screen
->getBorderColor()->pixel());
634 void BlackboxWindow::decorateLabel(void) {
637 texture
= &(screen
->getWindowStyle()->l_focus
);
638 frame
.flabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.flabel
);
640 frame
.flabel_pixel
= texture
->color().pixel();
642 texture
= &(screen
->getWindowStyle()->l_unfocus
);
643 frame
.ulabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.ulabel
);
645 frame
.ulabel_pixel
= texture
->color().pixel();
649 void BlackboxWindow::createHandle(void) {
650 frame
.handle
= createChildWindow(frame
.window
);
651 blackbox
->saveWindowSearch(frame
.handle
, this);
654 createChildWindow(frame
.handle
, blackbox
->getLowerLeftAngleCursor());
655 blackbox
->saveWindowSearch(frame
.left_grip
, this);
658 createChildWindow(frame
.handle
, blackbox
->getLowerRightAngleCursor());
659 blackbox
->saveWindowSearch(frame
.right_grip
, this);
663 void BlackboxWindow::destroyHandle(void) {
665 screen
->getImageControl()->removeImage(frame
.fhandle
);
668 screen
->getImageControl()->removeImage(frame
.uhandle
);
671 screen
->getImageControl()->removeImage(frame
.fgrip
);
674 screen
->getImageControl()->removeImage(frame
.ugrip
);
676 blackbox
->removeWindowSearch(frame
.left_grip
);
677 blackbox
->removeWindowSearch(frame
.right_grip
);
679 XDestroyWindow(blackbox
->getXDisplay(), frame
.left_grip
);
680 XDestroyWindow(blackbox
->getXDisplay(), frame
.right_grip
);
681 frame
.left_grip
= frame
.right_grip
= None
;
683 blackbox
->removeWindowSearch(frame
.handle
);
684 XDestroyWindow(blackbox
->getXDisplay(), frame
.handle
);
689 void BlackboxWindow::createTitlebar(void) {
690 frame
.title
= createChildWindow(frame
.window
);
691 frame
.label
= createChildWindow(frame
.title
);
692 blackbox
->saveWindowSearch(frame
.title
, this);
693 blackbox
->saveWindowSearch(frame
.label
, this);
695 if (decorations
& Decor_Iconify
) createIconifyButton();
696 if (decorations
& Decor_Maximize
) createMaximizeButton();
697 if (decorations
& Decor_Close
) createCloseButton();
701 void BlackboxWindow::destroyTitlebar(void) {
702 if (frame
.close_button
)
703 destroyCloseButton();
705 if (frame
.iconify_button
)
706 destroyIconifyButton();
708 if (frame
.maximize_button
)
709 destroyMaximizeButton();
712 screen
->getImageControl()->removeImage(frame
.ftitle
);
715 screen
->getImageControl()->removeImage(frame
.utitle
);
718 screen
->getImageControl()->removeImage(frame
.flabel
);
721 screen
->getImageControl()->removeImage(frame
.ulabel
);
724 screen
->getImageControl()->removeImage(frame
.fbutton
);
727 screen
->getImageControl()->removeImage(frame
.ubutton
);
730 screen
->getImageControl()->removeImage(frame
.pbutton
);
732 blackbox
->removeWindowSearch(frame
.title
);
733 blackbox
->removeWindowSearch(frame
.label
);
735 XDestroyWindow(blackbox
->getXDisplay(), frame
.label
);
736 XDestroyWindow(blackbox
->getXDisplay(), frame
.title
);
737 frame
.title
= frame
.label
= None
;
741 void BlackboxWindow::createCloseButton(void) {
742 if (frame
.title
!= None
) {
743 frame
.close_button
= createChildWindow(frame
.title
);
744 blackbox
->saveWindowSearch(frame
.close_button
, this);
749 void BlackboxWindow::destroyCloseButton(void) {
750 blackbox
->removeWindowSearch(frame
.close_button
);
751 XDestroyWindow(blackbox
->getXDisplay(), frame
.close_button
);
752 frame
.close_button
= None
;
756 void BlackboxWindow::createIconifyButton(void) {
757 if (frame
.title
!= None
) {
758 frame
.iconify_button
= createChildWindow(frame
.title
);
759 blackbox
->saveWindowSearch(frame
.iconify_button
, this);
764 void BlackboxWindow::destroyIconifyButton(void) {
765 blackbox
->removeWindowSearch(frame
.iconify_button
);
766 XDestroyWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
767 frame
.iconify_button
= None
;
771 void BlackboxWindow::createMaximizeButton(void) {
772 if (frame
.title
!= None
) {
773 frame
.maximize_button
= createChildWindow(frame
.title
);
774 blackbox
->saveWindowSearch(frame
.maximize_button
, this);
779 void BlackboxWindow::destroyMaximizeButton(void) {
780 blackbox
->removeWindowSearch(frame
.maximize_button
);
781 XDestroyWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
782 frame
.maximize_button
= None
;
786 void BlackboxWindow::positionButtons(bool redecorate_label
) {
787 string layout
= blackbox
->getTitlebarLayout();
790 bool hasclose
, hasiconify
, hasmaximize
, haslabel
;
791 hasclose
= hasiconify
= hasmaximize
= haslabel
= false;
793 string::const_iterator it
, end
;
794 for (it
= layout
.begin(), end
= layout
.end(); it
!= end
; ++it
) {
797 if (! hasclose
&& (decorations
& Decor_Close
)) {
803 if (! hasiconify
&& (decorations
& Decor_Iconify
)) {
809 if (! hasmaximize
&& (decorations
& Decor_Maximize
)) {
821 if (! hasclose
&& frame
.close_button
)
822 destroyCloseButton();
823 if (! hasiconify
&& frame
.iconify_button
)
824 destroyIconifyButton();
825 if (! hasmaximize
&& frame
.maximize_button
)
826 destroyMaximizeButton();
828 parsed
+= 'L'; // require that the label be in the layout
830 const unsigned int bsep
= frame
.bevel_w
+ 1; // separation between elements
831 const unsigned int by
= frame
.bevel_w
+ 1;
832 const unsigned int ty
= frame
.bevel_w
;
834 frame
.label_w
= frame
.inside_w
- bsep
* 2 -
835 (frame
.button_w
+ bsep
) * (parsed
.size() - 1);
837 unsigned int x
= bsep
;
838 for (it
= parsed
.begin(), end
= parsed
.end(); it
!= end
; ++it
) {
841 if (! frame
.close_button
) createCloseButton();
842 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.close_button
, x
, by
,
843 frame
.button_w
, frame
.button_w
);
844 x
+= frame
.button_w
+ bsep
;
847 if (! frame
.iconify_button
) createIconifyButton();
848 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.iconify_button
, x
, by
,
849 frame
.button_w
, frame
.button_w
);
850 x
+= frame
.button_w
+ bsep
;
853 if (! frame
.maximize_button
) createMaximizeButton();
854 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.maximize_button
, x
, by
,
855 frame
.button_w
, frame
.button_w
);
856 x
+= frame
.button_w
+ bsep
;
859 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.label
, x
, ty
,
860 frame
.label_w
, frame
.label_h
);
861 x
+= frame
.label_w
+ bsep
;
866 if (redecorate_label
) decorateLabel();
872 void BlackboxWindow::reconfigure(void) {
873 restoreGravity(client
.rect
);
875 applyGravity(frame
.rect
);
884 windowmenu
->move(windowmenu
->getX(), frame
.rect
.y() + frame
.title_h
);
885 windowmenu
->reconfigure();
890 void BlackboxWindow::grabButtons(void) {
891 mod_mask
= blackbox
->getMouseModMask();
893 if (! screen
->isSloppyFocus() || screen
->doClickRaise())
894 // grab button 1 for changing focus/raising
895 blackbox
->grabButton(Button1
, 0, frame
.plate
, True
, ButtonPressMask
,
896 GrabModeSync
, GrabModeSync
, frame
.plate
, None
,
897 screen
->allowScrollLock());
899 if (functions
& Func_Move
)
900 blackbox
->grabButton(Button1
, mod_mask
, frame
.window
, True
,
901 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
902 GrabModeAsync
, frame
.window
, None
,
903 screen
->allowScrollLock());
904 if (functions
& Func_Resize
)
905 blackbox
->grabButton(Button3
, mod_mask
, frame
.window
, True
,
906 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
907 GrabModeAsync
, frame
.window
, None
,
908 screen
->allowScrollLock());
909 // alt+middle lowers the window
910 blackbox
->grabButton(Button2
, mod_mask
, frame
.window
, True
,
911 ButtonReleaseMask
, GrabModeAsync
, GrabModeAsync
,
913 screen
->allowScrollLock());
917 void BlackboxWindow::ungrabButtons(void) {
918 blackbox
->ungrabButton(Button1
, 0, frame
.plate
);
919 blackbox
->ungrabButton(Button1
, mod_mask
, frame
.window
);
920 blackbox
->ungrabButton(Button2
, mod_mask
, frame
.window
);
921 blackbox
->ungrabButton(Button3
, mod_mask
, frame
.window
);
925 void BlackboxWindow::positionWindows(void) {
926 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.window
,
927 frame
.rect
.x(), frame
.rect
.y(), frame
.inside_w
,
928 (flags
.shaded
) ? frame
.title_h
: frame
.inside_h
);
929 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.window
,
931 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.plate
,
933 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.plate
,
934 frame
.margin
.left
- frame
.mwm_border_w
- frame
.border_w
,
935 frame
.margin
.top
- frame
.mwm_border_w
- frame
.border_w
,
936 client
.rect
.width(), client
.rect
.height());
937 XMoveResizeWindow(blackbox
->getXDisplay(), client
.window
,
938 0, 0, client
.rect
.width(), client
.rect
.height());
939 // ensure client.rect contains the real location
940 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
941 frame
.rect
.top() + frame
.margin
.top
);
943 if (decorations
& Decor_Titlebar
) {
944 if (frame
.title
== None
) createTitlebar();
946 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.title
,
948 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.title
, -frame
.border_w
,
949 -frame
.border_w
, frame
.inside_w
, frame
.title_h
);
952 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
953 XMapWindow(blackbox
->getXDisplay(), frame
.title
);
954 } else if (frame
.title
) {
957 if (decorations
& Decor_Handle
) {
958 if (frame
.handle
== None
) createHandle();
959 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.handle
,
961 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.left_grip
,
963 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.right_grip
,
966 // use client.rect here so the value is correct even if shaded
967 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.handle
,
969 client
.rect
.height() + frame
.margin
.top
+
970 frame
.mwm_border_w
- frame
.border_w
,
971 frame
.inside_w
, frame
.handle_h
);
972 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.left_grip
,
973 -frame
.border_w
, -frame
.border_w
,
974 frame
.grip_w
, frame
.handle_h
);
975 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.right_grip
,
976 frame
.inside_w
- frame
.grip_w
- frame
.border_w
,
977 -frame
.border_w
, frame
.grip_w
, frame
.handle_h
);
979 XMapSubwindows(blackbox
->getXDisplay(), frame
.handle
);
980 XMapWindow(blackbox
->getXDisplay(), frame
.handle
);
981 } else if (frame
.handle
) {
984 XSync(blackbox
->getXDisplay(), False
);
988 void BlackboxWindow::updateStrut(void) {
989 unsigned long num
= 4;
991 if (! xatom
->getValue(client
.window
, XAtom::net_wm_strut
, XAtom::cardinal
,
996 client
.strut
.left
= data
[0];
997 client
.strut
.right
= data
[1];
998 client
.strut
.top
= data
[2];
999 client
.strut
.bottom
= data
[3];
1001 screen
->updateAvailableArea();
1008 bool BlackboxWindow::getWindowType(void) {
1010 if (xatom
->getValue(client
.window
, XAtom::net_wm_window_type
, XAtom::atom
,
1012 if (val
== xatom
->getAtom(XAtom::net_wm_window_type_desktop
))
1013 window_type
= Type_Desktop
;
1014 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_dock
))
1015 window_type
= Type_Dock
;
1016 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_toolbar
))
1017 window_type
= Type_Toolbar
;
1018 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_menu
))
1019 window_type
= Type_Menu
;
1020 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_utility
))
1021 window_type
= Type_Utility
;
1022 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_splash
))
1023 window_type
= Type_Splash
;
1024 else if (val
== xatom
->getAtom(XAtom::net_wm_window_type_dialog
))
1025 window_type
= Type_Dialog
;
1026 else //if (val[0] == xatom->getAtom(XAtom::net_wm_window_type_normal))
1027 window_type
= Type_Normal
;
1033 * the window type hint was not set, which means we either classify ourself
1034 * as a normal window or a dialog, depending on if we are a transient.
1037 window_type
= Type_Dialog
;
1039 window_type
= Type_Normal
;
1045 void BlackboxWindow::getWMName(void) {
1046 if (xatom
->getValue(client
.window
, XAtom::net_wm_name
,
1047 XAtom::utf8
, client
.title
) &&
1048 !client
.title
.empty()) {
1049 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
1052 //fall through to using WM_NAME
1053 if (xatom
->getValue(client
.window
, XAtom::wm_name
, XAtom::ansi
, client
.title
)
1054 && !client
.title
.empty()) {
1055 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
1058 // fall back to an internal default
1059 client
.title
= i18n(WindowSet
, WindowUnnamed
, "Unnamed");
1060 xatom
->setValue(client
.window
, XAtom::net_wm_visible_name
, XAtom::utf8
,
1065 void BlackboxWindow::getWMIconName(void) {
1066 if (xatom
->getValue(client
.window
, XAtom::net_wm_icon_name
,
1067 XAtom::utf8
, client
.icon_title
) &&
1068 !client
.icon_title
.empty()) {
1069 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1072 //fall through to using WM_ICON_NAME
1073 if (xatom
->getValue(client
.window
, XAtom::wm_icon_name
, XAtom::ansi
,
1074 client
.icon_title
) &&
1075 !client
.icon_title
.empty()) {
1076 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1079 // fall back to using the main name
1080 client
.icon_title
= client
.title
;
1081 xatom
->setValue(client
.window
, XAtom::net_wm_visible_icon_name
, XAtom::utf8
,
1087 * Retrieve which WM Protocols are supported by the client window.
1088 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
1089 * window's decorations and allow the close behavior.
1090 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
1093 void BlackboxWindow::getWMProtocols(void) {
1097 if (XGetWMProtocols(blackbox
->getXDisplay(), client
.window
,
1098 &proto
, &num_return
)) {
1099 for (int i
= 0; i
< num_return
; ++i
) {
1100 if (proto
[i
] == xatom
->getAtom(XAtom::wm_delete_window
)) {
1101 decorations
|= Decor_Close
;
1102 functions
|= Func_Close
;
1103 } else if (proto
[i
] == xatom
->getAtom(XAtom::wm_take_focus
))
1104 flags
.send_focus_message
= True
;
1105 else if (proto
[i
] == xatom
->getAtom(XAtom::blackbox_structure_messages
))
1106 screen
->addNetizen(new Netizen(screen
, client
.window
));
1115 * Gets the value of the WM_HINTS property.
1116 * If the property is not set, then use a set of default values.
1118 void BlackboxWindow::getWMHints(void) {
1119 focus_mode
= F_Passive
;
1121 // remove from current window group
1122 if (client
.window_group
) {
1123 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1124 if (group
) group
->removeWindow(this);
1126 client
.window_group
= None
;
1128 XWMHints
*wmhint
= XGetWMHints(blackbox
->getXDisplay(), client
.window
);
1133 if (wmhint
->flags
& InputHint
) {
1134 if (wmhint
->input
== True
) {
1135 if (flags
.send_focus_message
)
1136 focus_mode
= F_LocallyActive
;
1138 if (flags
.send_focus_message
)
1139 focus_mode
= F_GloballyActive
;
1141 focus_mode
= F_NoInput
;
1145 if (wmhint
->flags
& StateHint
)
1146 current_state
= wmhint
->initial_state
;
1148 if (wmhint
->flags
& WindowGroupHint
) {
1149 client
.window_group
= wmhint
->window_group
;
1151 // add window to the appropriate group
1152 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1153 if (! group
) { // no group found, create it!
1154 new BWindowGroup(blackbox
, client
.window_group
);
1155 group
= blackbox
->searchGroup(client
.window_group
);
1158 group
->addWindow(this);
1166 * Gets the value of the WM_NORMAL_HINTS property.
1167 * If the property is not set, then use a set of default values.
1169 void BlackboxWindow::getWMNormalHints(void) {
1171 XSizeHints sizehint
;
1173 client
.min_width
= client
.min_height
=
1174 client
.width_inc
= client
.height_inc
= 1;
1175 client
.base_width
= client
.base_height
= 0;
1176 client
.win_gravity
= NorthWestGravity
;
1178 client
.min_aspect_x
= client
.min_aspect_y
=
1179 client
.max_aspect_x
= client
.max_aspect_y
= 1;
1183 use the full screen, not the strut modified size. otherwise when the
1184 availableArea changes max_width/height will be incorrect and lead to odd
1187 const Rect
& screen_area
= screen
->getRect();
1188 client
.max_width
= screen_area
.width();
1189 client
.max_height
= screen_area
.height();
1191 if (! XGetWMNormalHints(blackbox
->getXDisplay(), client
.window
,
1192 &sizehint
, &icccm_mask
))
1195 client
.normal_hint_flags
= sizehint
.flags
;
1197 if (sizehint
.flags
& PMinSize
) {
1198 if (sizehint
.min_width
>= 0)
1199 client
.min_width
= sizehint
.min_width
;
1200 if (sizehint
.min_height
>= 0)
1201 client
.min_height
= sizehint
.min_height
;
1204 if (sizehint
.flags
& PMaxSize
) {
1205 if (sizehint
.max_width
> static_cast<signed>(client
.min_width
))
1206 client
.max_width
= sizehint
.max_width
;
1208 client
.max_width
= client
.min_width
;
1210 if (sizehint
.max_height
> static_cast<signed>(client
.min_height
))
1211 client
.max_height
= sizehint
.max_height
;
1213 client
.max_height
= client
.min_height
;
1216 if (sizehint
.flags
& PResizeInc
) {
1217 client
.width_inc
= sizehint
.width_inc
;
1218 client
.height_inc
= sizehint
.height_inc
;
1221 #if 0 // we do not support this at the moment
1222 if (sizehint
.flags
& PAspect
) {
1223 client
.min_aspect_x
= sizehint
.min_aspect
.x
;
1224 client
.min_aspect_y
= sizehint
.min_aspect
.y
;
1225 client
.max_aspect_x
= sizehint
.max_aspect
.x
;
1226 client
.max_aspect_y
= sizehint
.max_aspect
.y
;
1230 if (sizehint
.flags
& PBaseSize
) {
1231 client
.base_width
= sizehint
.base_width
;
1232 client
.base_height
= sizehint
.base_height
;
1235 if (sizehint
.flags
& PWinGravity
)
1236 client
.win_gravity
= sizehint
.win_gravity
;
1241 * Gets the NETWM hints for the class' contained window.
1243 void BlackboxWindow::getNetWMHints(void) {
1244 unsigned long workspace
;
1246 if (xatom
->getValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1248 if (workspace
== 0xffffffff)
1251 blackbox_attrib
.workspace
= workspace
;
1254 unsigned long *state
;
1255 unsigned long num
= (unsigned) -1;
1256 if (xatom
->getValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
1260 for (unsigned long i
= 0; i
< num
; ++i
) {
1261 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
))
1263 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_shaded
))
1264 flags
.shaded
= True
;
1265 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
))
1266 flags
.skip_taskbar
= True
;
1267 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_pager
))
1268 flags
.skip_pager
= True
;
1269 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_fullscreen
))
1270 flags
.fullscreen
= True
;
1271 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_hidden
))
1272 setState(IconicState
);
1273 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_vert
))
1275 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_horz
))
1279 flags
.maximized
= 1;
1281 flags
.maximized
= 2;
1283 flags
.maximized
= 3;
1291 * Gets the MWM hints for the class' contained window.
1292 * This is used while initializing the window to its first state, and not
1294 * Returns: true if the MWM hints are successfully retreived and applied;
1295 * false if they are not.
1297 void BlackboxWindow::getMWMHints(void) {
1301 num
= PropMwmHintsElements
;
1302 if (! xatom
->getValue(client
.window
, XAtom::motif_wm_hints
,
1303 XAtom::motif_wm_hints
, num
,
1304 (unsigned long **)&mwm_hint
))
1306 if (num
< PropMwmHintsElements
) {
1311 if (mwm_hint
->flags
& MwmHintsDecorations
) {
1312 if (mwm_hint
->decorations
& MwmDecorAll
) {
1313 mwm_decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
1314 Decor_Iconify
| Decor_Maximize
| Decor_Close
;
1316 mwm_decorations
= 0;
1318 if (mwm_hint
->decorations
& MwmDecorBorder
)
1319 mwm_decorations
|= Decor_Border
;
1320 if (mwm_hint
->decorations
& MwmDecorHandle
)
1321 mwm_decorations
|= Decor_Handle
;
1322 if (mwm_hint
->decorations
& MwmDecorTitle
)
1323 mwm_decorations
|= Decor_Titlebar
;
1324 if (mwm_hint
->decorations
& MwmDecorIconify
)
1325 mwm_decorations
|= Decor_Iconify
;
1326 if (mwm_hint
->decorations
& MwmDecorMaximize
)
1327 mwm_decorations
|= Decor_Maximize
;
1331 if (mwm_hint
->flags
& MwmHintsFunctions
) {
1332 if (mwm_hint
->functions
& MwmFuncAll
) {
1333 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
|
1338 if (mwm_hint
->functions
& MwmFuncResize
)
1339 functions
|= Func_Resize
;
1340 if (mwm_hint
->functions
& MwmFuncMove
)
1341 functions
|= Func_Move
;
1342 if (mwm_hint
->functions
& MwmFuncIconify
)
1343 functions
|= Func_Iconify
;
1344 if (mwm_hint
->functions
& MwmFuncMaximize
)
1345 functions
|= Func_Maximize
;
1346 if (mwm_hint
->functions
& MwmFuncClose
)
1347 functions
|= Func_Close
;
1355 * Gets the blackbox hints from the class' contained window.
1356 * This is used while initializing the window to its first state, and not
1358 * Returns: true if the hints are successfully retreived and applied; false if
1361 bool BlackboxWindow::getBlackboxHints(void) {
1363 BlackboxHints
*blackbox_hint
;
1365 num
= PropBlackboxHintsElements
;
1366 if (! xatom
->getValue(client
.window
, XAtom::blackbox_hints
,
1367 XAtom::blackbox_hints
, num
,
1368 (unsigned long **)&blackbox_hint
))
1370 if (num
< PropBlackboxHintsElements
) {
1371 delete [] blackbox_hint
;
1375 if (blackbox_hint
->flags
& AttribShaded
)
1376 flags
.shaded
= (blackbox_hint
->attrib
& AttribShaded
);
1378 if ((blackbox_hint
->flags
& AttribMaxHoriz
) &&
1379 (blackbox_hint
->flags
& AttribMaxVert
))
1380 flags
.maximized
= (blackbox_hint
->attrib
&
1381 (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1382 else if (blackbox_hint
->flags
& AttribMaxVert
)
1383 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxVert
) ? 2 : 0;
1384 else if (blackbox_hint
->flags
& AttribMaxHoriz
)
1385 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1387 if (blackbox_hint
->flags
& AttribOmnipresent
)
1388 flags
.stuck
= (blackbox_hint
->attrib
& AttribOmnipresent
);
1390 if (blackbox_hint
->flags
& AttribWorkspace
)
1391 blackbox_attrib
.workspace
= blackbox_hint
->workspace
;
1393 // if (blackbox_hint->flags & AttribStack)
1394 // don't yet have always on top/bottom for blackbox yet... working
1397 if (blackbox_hint
->flags
& AttribDecoration
) {
1398 switch (blackbox_hint
->decoration
) {
1400 blackbox_attrib
.decoration
= DecorNone
;
1407 // blackbox_attrib.decoration defaults to DecorNormal
1412 delete [] blackbox_hint
;
1418 void BlackboxWindow::getTransientInfo(void) {
1419 if (client
.transient_for
&&
1420 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1421 // reset transient_for in preparation of looking for a new owner
1422 client
.transient_for
->client
.transientList
.remove(this);
1425 // we have no transient_for until we find a new one
1426 client
.transient_for
= (BlackboxWindow
*) 0;
1429 if (! XGetTransientForHint(blackbox
->getXDisplay(), client
.window
,
1431 // transient_for hint not set
1435 if (trans_for
== client
.window
) {
1436 // wierd client... treat this window as a normal window
1440 if (trans_for
== None
|| trans_for
== screen
->getRootWindow()) {
1441 // this is an undocumented interpretation of the ICCCM. a transient
1442 // associated with None/Root/itself is assumed to be a modal root
1443 // transient. we don't support the concept of a global transient,
1444 // so we just associate this transient with nothing, and perhaps
1445 // we will add support later for global modality.
1446 client
.transient_for
= (BlackboxWindow
*) ~0ul;
1451 client
.transient_for
= blackbox
->searchWindow(trans_for
);
1452 if (! client
.transient_for
&&
1453 client
.window_group
&& trans_for
== client
.window_group
) {
1454 // no direct transient_for, perhaps this is a group transient?
1455 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1456 if (group
) client
.transient_for
= group
->find(screen
);
1459 if (! client
.transient_for
|| client
.transient_for
== this) {
1460 // no transient_for found, or we have a wierd client that wants to be
1461 // a transient for itself, so we treat this window as a normal window
1462 client
.transient_for
= (BlackboxWindow
*) 0;
1466 // Check for a circular transient state: this can lock up Blackbox
1467 // when it tries to find the non-transient window for a transient.
1468 BlackboxWindow
*w
= this;
1469 while(w
->client
.transient_for
&&
1470 w
->client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1471 if(w
->client
.transient_for
== this) {
1472 client
.transient_for
= (BlackboxWindow
*) 0;
1475 w
= w
->client
.transient_for
;
1478 if (client
.transient_for
&&
1479 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1480 // register ourselves with our new transient_for
1481 client
.transient_for
->client
.transientList
.push_back(this);
1482 flags
.stuck
= client
.transient_for
->flags
.stuck
;
1487 BlackboxWindow
*BlackboxWindow::getTransientFor(void) const {
1488 if (client
.transient_for
&&
1489 client
.transient_for
!= (BlackboxWindow
*) ~0ul)
1490 return client
.transient_for
;
1496 * This function is responsible for updating both the client and the frame
1498 * According to the ICCCM a client message is not sent for a resize, only a
1501 void BlackboxWindow::configure(int dx
, int dy
,
1502 unsigned int dw
, unsigned int dh
) {
1503 bool send_event
= ((frame
.rect
.x() != dx
|| frame
.rect
.y() != dy
) &&
1506 if (dw
!= frame
.rect
.width() || dh
!= frame
.rect
.height()) {
1507 frame
.rect
.setRect(dx
, dy
, dw
, dh
);
1508 frame
.inside_w
= frame
.rect
.width() - (frame
.border_w
* 2);
1509 frame
.inside_h
= frame
.rect
.height() - (frame
.border_w
* 2);
1511 if (frame
.rect
.right() <= 0 || frame
.rect
.bottom() <= 0)
1512 frame
.rect
.setPos(0, 0);
1514 client
.rect
.setCoords(frame
.rect
.left() + frame
.margin
.left
,
1515 frame
.rect
.top() + frame
.margin
.top
,
1516 frame
.rect
.right() - frame
.margin
.right
,
1517 frame
.rect
.bottom() - frame
.margin
.bottom
);
1520 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
1527 redrawWindowFrame();
1529 frame
.rect
.setPos(dx
, dy
);
1531 XMoveWindow(blackbox
->getXDisplay(), frame
.window
,
1532 frame
.rect
.x(), frame
.rect
.y());
1534 we may have been called just after an opaque window move, so even though
1535 the old coords match the new ones no ConfigureNotify has been sent yet.
1536 There are likely other times when this will be relevant as well.
1538 if (! flags
.moving
) send_event
= True
;
1542 // if moving, the update and event will occur when the move finishes
1543 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1544 frame
.rect
.top() + frame
.margin
.top
);
1547 event
.type
= ConfigureNotify
;
1549 event
.xconfigure
.display
= blackbox
->getXDisplay();
1550 event
.xconfigure
.event
= client
.window
;
1551 event
.xconfigure
.window
= client
.window
;
1552 event
.xconfigure
.x
= client
.rect
.x();
1553 event
.xconfigure
.y
= client
.rect
.y();
1554 event
.xconfigure
.width
= client
.rect
.width();
1555 event
.xconfigure
.height
= client
.rect
.height();
1556 event
.xconfigure
.border_width
= client
.old_bw
;
1557 event
.xconfigure
.above
= frame
.window
;
1558 event
.xconfigure
.override_redirect
= False
;
1560 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1561 StructureNotifyMask
, &event
);
1562 screen
->updateNetizenConfigNotify(&event
);
1563 XFlush(blackbox
->getXDisplay());
1569 void BlackboxWindow::configureShape(void) {
1570 XShapeCombineShape(blackbox
->getXDisplay(), frame
.window
, ShapeBounding
,
1571 frame
.margin
.left
- frame
.border_w
,
1572 frame
.margin
.top
- frame
.border_w
,
1573 client
.window
, ShapeBounding
, ShapeSet
);
1576 XRectangle xrect
[2];
1578 if (decorations
& Decor_Titlebar
) {
1579 xrect
[0].x
= xrect
[0].y
= -frame
.border_w
;
1580 xrect
[0].width
= frame
.rect
.width();
1581 xrect
[0].height
= frame
.title_h
+ (frame
.border_w
* 2);
1585 if (decorations
& Decor_Handle
) {
1586 xrect
[1].x
= -frame
.border_w
;
1587 xrect
[1].y
= frame
.rect
.height() - frame
.margin
.bottom
+
1588 frame
.mwm_border_w
- frame
.border_w
;
1589 xrect
[1].width
= frame
.rect
.width();
1590 xrect
[1].height
= frame
.handle_h
+ (frame
.border_w
* 2);
1594 XShapeCombineRectangles(blackbox
->getXDisplay(), frame
.window
,
1595 ShapeBounding
, 0, 0, xrect
, num
,
1596 ShapeUnion
, Unsorted
);
1601 bool BlackboxWindow::setInputFocus(void) {
1602 if (flags
.focused
) return True
;
1604 assert(flags
.stuck
|| // window must be on the current workspace or sticky
1605 blackbox_attrib
.workspace
== screen
->getCurrentWorkspaceID());
1608 We only do this check for normal windows and dialogs because other windows
1609 do this on purpose, such as kde's kicker, and we don't want to go moving
1612 if (window_type
== Type_Normal
|| window_type
== Type_Dialog
)
1613 if (! frame
.rect
.intersects(screen
->getRect())) {
1614 // client is outside the screen, move it to the center
1615 configure((screen
->getWidth() - frame
.rect
.width()) / 2,
1616 (screen
->getHeight() - frame
.rect
.height()) / 2,
1617 frame
.rect
.width(), frame
.rect
.height());
1620 if (client
.transientList
.size() > 0) {
1621 // transfer focus to any modal transients
1622 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1623 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1624 if ((*it
)->flags
.modal
) return (*it
)->setInputFocus();
1628 if (focus_mode
== F_LocallyActive
|| focus_mode
== F_Passive
) {
1629 XSetInputFocus(blackbox
->getXDisplay(), client
.window
,
1630 RevertToPointerRoot
, CurrentTime
);
1632 /* we could set the focus to none, since the window doesn't accept focus,
1633 * but we shouldn't set focus to nothing since this would surely make
1639 if (flags
.send_focus_message
) {
1641 ce
.xclient
.type
= ClientMessage
;
1642 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1643 ce
.xclient
.display
= blackbox
->getXDisplay();
1644 ce
.xclient
.window
= client
.window
;
1645 ce
.xclient
.format
= 32;
1646 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_take_focus
);
1647 ce
.xclient
.data
.l
[1] = blackbox
->getLastTime();
1648 ce
.xclient
.data
.l
[2] = 0l;
1649 ce
.xclient
.data
.l
[3] = 0l;
1650 ce
.xclient
.data
.l
[4] = 0l;
1651 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1653 XFlush(blackbox
->getXDisplay());
1660 void BlackboxWindow::iconify(void) {
1661 if (flags
.iconic
) return;
1663 // We don't need to worry about resizing because resizing always grabs the X
1664 // server. This should only ever happen if using opaque moving.
1668 if (windowmenu
) windowmenu
->hide();
1671 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1672 * we need to clear the event mask on client.window for a split second.
1673 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1674 * split second, leaving us with a ghost window... so, we need to do this
1675 * while the X server is grabbed
1677 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1678 StructureNotifyMask
;
1679 XGrabServer(blackbox
->getXDisplay());
1680 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1681 event_mask
& ~StructureNotifyMask
);
1682 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1683 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1684 XUngrabServer(blackbox
->getXDisplay());
1686 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1687 flags
.visible
= False
;
1688 flags
.iconic
= True
;
1690 setState(IconicState
);
1692 screen
->getWorkspace(blackbox_attrib
.workspace
)->removeWindow(this);
1694 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
1695 if (i
!= blackbox_attrib
.workspace
)
1696 screen
->getWorkspace(i
)->removeWindow(this, True
);
1699 if (isTransient()) {
1700 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1701 ! client
.transient_for
->flags
.iconic
) {
1702 // iconify our transient_for
1703 client
.transient_for
->iconify();
1707 screen
->addIcon(this);
1709 if (client
.transientList
.size() > 0) {
1710 // iconify all transients
1711 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1712 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1713 if (! (*it
)->flags
.iconic
) (*it
)->iconify();
1716 screen
->updateStackingList();
1720 void BlackboxWindow::show(void) {
1721 flags
.visible
= True
;
1722 flags
.iconic
= False
;
1724 current_state
= (flags
.shaded
) ? IconicState
: NormalState
;
1725 setState(current_state
);
1727 XMapWindow(blackbox
->getXDisplay(), client
.window
);
1728 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
1729 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
1734 XTranslateCoordinates(blackbox
->getXDisplay(), client
.window
,
1735 screen
->getRootWindow(),
1736 0, 0, &real_x
, &real_y
, &child
);
1737 fprintf(stderr
, "%s -- assumed: (%d, %d), real: (%d, %d)\n", getTitle(),
1738 client
.rect
.left(), client
.rect
.top(), real_x
, real_y
);
1739 assert(client
.rect
.left() == real_x
&& client
.rect
.top() == real_y
);
1744 void BlackboxWindow::deiconify(bool reassoc
, bool raise
) {
1745 if (flags
.iconic
|| reassoc
)
1746 screen
->reassociateWindow(this, BSENTINEL
, False
);
1747 else if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID())
1752 // reassociate and deiconify all transients
1753 if (reassoc
&& client
.transientList
.size() > 0) {
1754 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1755 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1756 (*it
)->deiconify(True
, False
);
1760 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1764 void BlackboxWindow::close(void) {
1766 ce
.xclient
.type
= ClientMessage
;
1767 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1768 ce
.xclient
.display
= blackbox
->getXDisplay();
1769 ce
.xclient
.window
= client
.window
;
1770 ce
.xclient
.format
= 32;
1771 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_delete_window
);
1772 ce
.xclient
.data
.l
[1] = CurrentTime
;
1773 ce
.xclient
.data
.l
[2] = 0l;
1774 ce
.xclient
.data
.l
[3] = 0l;
1775 ce
.xclient
.data
.l
[4] = 0l;
1776 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
, NoEventMask
, &ce
);
1777 XFlush(blackbox
->getXDisplay());
1781 void BlackboxWindow::withdraw(void) {
1782 // We don't need to worry about resizing because resizing always grabs the X
1783 // server. This should only ever happen if using opaque moving.
1787 flags
.visible
= False
;
1788 flags
.iconic
= False
;
1790 setState(current_state
);
1792 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1794 XGrabServer(blackbox
->getXDisplay());
1796 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1797 StructureNotifyMask
;
1798 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1799 event_mask
& ~StructureNotifyMask
);
1800 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1801 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1803 XUngrabServer(blackbox
->getXDisplay());
1805 if (windowmenu
) windowmenu
->hide();
1809 void BlackboxWindow::maximize(unsigned int button
) {
1810 // We don't need to worry about resizing because resizing always grabs the X
1811 // server. This should only ever happen if using opaque moving.
1815 // handle case where menu is open then the max button is used instead
1816 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
1818 if (flags
.maximized
) {
1819 flags
.maximized
= 0;
1821 blackbox_attrib
.flags
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1822 blackbox_attrib
.attrib
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1825 when a resize finishes, maximize(0) is called to clear any maximization
1826 flags currently set. Otherwise it still thinks it is maximized.
1827 so we do not need to call configure() because resizing will handle it
1829 if (! flags
.resizing
)
1830 configure(blackbox_attrib
.premax_x
, blackbox_attrib
.premax_y
,
1831 blackbox_attrib
.premax_w
, blackbox_attrib
.premax_h
);
1833 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
1834 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
1836 redrawAllButtons(); // in case it is not called in configure()
1837 setState(current_state
);
1841 blackbox_attrib
.premax_x
= frame
.rect
.x();
1842 blackbox_attrib
.premax_y
= frame
.rect
.y();
1843 blackbox_attrib
.premax_w
= frame
.rect
.width();
1844 // use client.rect so that clients can be restored even if shaded
1845 blackbox_attrib
.premax_h
=
1846 client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
;
1849 if (screen
->isXineramaActive() && blackbox
->doXineramaMaximizing()) {
1850 // find the area to use
1851 RectList availableAreas
= screen
->allAvailableAreas();
1852 RectList::iterator it
, end
= availableAreas
.end();
1854 for (it
= availableAreas
.begin(); it
!= end
; ++it
)
1855 if (it
->intersects(frame
.rect
)) break;
1856 if (it
== end
) // the window isn't inside an area
1857 it
= availableAreas
.begin(); // so just default to the first one
1859 frame
.changing
= *it
;
1862 frame
.changing
= screen
->availableArea();
1866 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1867 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1871 blackbox_attrib
.flags
|= AttribMaxVert
;
1872 blackbox_attrib
.attrib
|= AttribMaxVert
;
1874 frame
.changing
.setX(frame
.rect
.x());
1875 frame
.changing
.setWidth(frame
.rect
.width());
1879 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1880 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1882 frame
.changing
.setY(frame
.rect
.y());
1883 frame
.changing
.setHeight(frame
.rect
.height());
1890 blackbox_attrib
.flags
^= AttribShaded
;
1891 blackbox_attrib
.attrib
^= AttribShaded
;
1892 flags
.shaded
= False
;
1895 flags
.maximized
= button
;
1897 configure(frame
.changing
.x(), frame
.changing
.y(),
1898 frame
.changing
.width(), frame
.changing
.height());
1900 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1901 redrawAllButtons(); // in case it is not called in configure()
1902 setState(current_state
);
1906 // re-maximizes the window to take into account availableArea changes
1907 void BlackboxWindow::remaximize(void) {
1909 // we only update the window's attributes otherwise we lose the shade bit
1910 switch(flags
.maximized
) {
1912 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1913 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1917 blackbox_attrib
.flags
|= AttribMaxVert
;
1918 blackbox_attrib
.attrib
|= AttribMaxVert
;
1922 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1923 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1929 // save the original dimensions because maximize will wipe them out
1930 int premax_x
= blackbox_attrib
.premax_x
,
1931 premax_y
= blackbox_attrib
.premax_y
,
1932 premax_w
= blackbox_attrib
.premax_w
,
1933 premax_h
= blackbox_attrib
.premax_h
;
1935 unsigned int button
= flags
.maximized
;
1936 flags
.maximized
= 0; // trick maximize() into working
1939 // restore saved values
1940 blackbox_attrib
.premax_x
= premax_x
;
1941 blackbox_attrib
.premax_y
= premax_y
;
1942 blackbox_attrib
.premax_w
= premax_w
;
1943 blackbox_attrib
.premax_h
= premax_h
;
1947 void BlackboxWindow::setWorkspace(unsigned int n
) {
1948 blackbox_attrib
.flags
|= AttribWorkspace
;
1949 blackbox_attrib
.workspace
= n
;
1950 if (n
== BSENTINEL
) { // iconified window
1952 we set the workspace to 'all workspaces' so that taskbars will show the
1953 window. otherwise, it made uniconifying a window imposible without the
1954 blackbox workspace menu
1958 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
, n
);
1962 void BlackboxWindow::shade(void) {
1964 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1965 frame
.inside_w
, frame
.inside_h
);
1966 flags
.shaded
= False
;
1967 blackbox_attrib
.flags
^= AttribShaded
;
1968 blackbox_attrib
.attrib
^= AttribShaded
;
1970 setState(NormalState
);
1972 // set the frame rect to the normal size
1973 frame
.rect
.setHeight(client
.rect
.height() + frame
.margin
.top
+
1974 frame
.margin
.bottom
);
1976 if (! (decorations
& Decor_Titlebar
))
1977 return; // can't shade it without a titlebar!
1979 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
1980 frame
.inside_w
, frame
.title_h
);
1981 flags
.shaded
= True
;
1982 blackbox_attrib
.flags
|= AttribShaded
;
1983 blackbox_attrib
.attrib
|= AttribShaded
;
1985 setState(IconicState
);
1987 // set the frame rect to the shaded size
1988 frame
.rect
.setHeight(frame
.title_h
+ (frame
.border_w
* 2));
1994 * (Un)Sticks a window and its relatives.
1996 void BlackboxWindow::stick(void) {
1998 blackbox_attrib
.flags
^= AttribOmnipresent
;
1999 blackbox_attrib
.attrib
^= AttribOmnipresent
;
2001 flags
.stuck
= False
;
2003 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
2004 if (i
!= blackbox_attrib
.workspace
)
2005 screen
->getWorkspace(i
)->removeWindow(this, True
);
2008 screen
->reassociateWindow(this, BSENTINEL
, True
);
2009 // temporary fix since sticky windows suck. set the hint to what we
2010 // actually hold in our data.
2011 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
2012 blackbox_attrib
.workspace
);
2014 setState(current_state
);
2018 blackbox_attrib
.flags
|= AttribOmnipresent
;
2019 blackbox_attrib
.attrib
|= AttribOmnipresent
;
2021 // temporary fix since sticky windows suck. set the hint to a different
2022 // value than that contained in the class' data.
2023 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
2026 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
2027 if (i
!= blackbox_attrib
.workspace
)
2028 screen
->getWorkspace(i
)->addWindow(this, False
, True
);
2030 setState(current_state
);
2033 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
2034 client
.transient_for
->isStuck() != flags
.stuck
)
2035 client
.transient_for
->stick();
2036 // go down the chain
2037 BlackboxWindowList::iterator it
;
2038 const BlackboxWindowList::iterator end
= client
.transientList
.end();
2039 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
2040 if ((*it
)->isStuck() != flags
.stuck
)
2045 void BlackboxWindow::redrawWindowFrame(void) const {
2046 if (decorations
& Decor_Titlebar
) {
2047 if (flags
.focused
) {
2049 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2050 frame
.title
, frame
.ftitle
);
2052 XSetWindowBackground(blackbox
->getXDisplay(),
2053 frame
.title
, frame
.ftitle_pixel
);
2056 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2057 frame
.title
, frame
.utitle
);
2059 XSetWindowBackground(blackbox
->getXDisplay(),
2060 frame
.title
, frame
.utitle_pixel
);
2062 XClearWindow(blackbox
->getXDisplay(), frame
.title
);
2068 if (decorations
& Decor_Handle
) {
2069 if (flags
.focused
) {
2071 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2072 frame
.handle
, frame
.fhandle
);
2074 XSetWindowBackground(blackbox
->getXDisplay(),
2075 frame
.handle
, frame
.fhandle_pixel
);
2078 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2079 frame
.left_grip
, frame
.fgrip
);
2080 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2081 frame
.right_grip
, frame
.fgrip
);
2083 XSetWindowBackground(blackbox
->getXDisplay(),
2084 frame
.left_grip
, frame
.fgrip_pixel
);
2085 XSetWindowBackground(blackbox
->getXDisplay(),
2086 frame
.right_grip
, frame
.fgrip_pixel
);
2090 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2091 frame
.handle
, frame
.uhandle
);
2093 XSetWindowBackground(blackbox
->getXDisplay(),
2094 frame
.handle
, frame
.uhandle_pixel
);
2097 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2098 frame
.left_grip
, frame
.ugrip
);
2099 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2100 frame
.right_grip
, frame
.ugrip
);
2102 XSetWindowBackground(blackbox
->getXDisplay(),
2103 frame
.left_grip
, frame
.ugrip_pixel
);
2104 XSetWindowBackground(blackbox
->getXDisplay(),
2105 frame
.right_grip
, frame
.ugrip_pixel
);
2108 XClearWindow(blackbox
->getXDisplay(), frame
.handle
);
2109 XClearWindow(blackbox
->getXDisplay(), frame
.left_grip
);
2110 XClearWindow(blackbox
->getXDisplay(), frame
.right_grip
);
2113 if (decorations
& Decor_Border
) {
2115 XSetWindowBorder(blackbox
->getXDisplay(),
2116 frame
.plate
, frame
.fborder_pixel
);
2118 XSetWindowBorder(blackbox
->getXDisplay(),
2119 frame
.plate
, frame
.uborder_pixel
);
2124 void BlackboxWindow::setFocusFlag(bool focus
) {
2125 // only focus a window if it is visible
2126 if (focus
&& ! flags
.visible
)
2129 flags
.focused
= focus
;
2131 redrawWindowFrame();
2134 blackbox
->setFocusedWindow(this);
2136 if (! flags
.iconic
) {
2137 // iconic windows arent in a workspace menu!
2139 screen
->getCurrentWorkspace()->setFocused(this, isFocused());
2141 screen
->getWorkspace(blackbox_attrib
.workspace
)->
2142 setFocused(this, flags
.focused
);
2147 void BlackboxWindow::installColormap(bool install
) {
2148 int i
= 0, ncmap
= 0;
2149 Colormap
*cmaps
= XListInstalledColormaps(blackbox
->getXDisplay(),
2150 client
.window
, &ncmap
);
2152 XWindowAttributes wattrib
;
2153 if (XGetWindowAttributes(blackbox
->getXDisplay(),
2154 client
.window
, &wattrib
)) {
2156 // install the window's colormap
2157 for (i
= 0; i
< ncmap
; i
++) {
2158 if (*(cmaps
+ i
) == wattrib
.colormap
)
2159 // this window is using an installed color map... do not install
2162 // otherwise, install the window's colormap
2164 XInstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2166 // uninstall the window's colormap
2167 for (i
= 0; i
< ncmap
; i
++) {
2168 if (*(cmaps
+ i
) == wattrib
.colormap
)
2169 // we found the colormap to uninstall
2170 XUninstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2180 void BlackboxWindow::setAllowedActions(void) {
2184 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_shade
);
2185 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_change_desktop
);
2186 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_close
);
2188 if (functions
& Func_Move
)
2189 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_move
);
2190 if (functions
& Func_Resize
)
2191 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_resize
);
2192 if (functions
& Func_Maximize
) {
2193 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_horz
);
2194 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_vert
);
2197 xatom
->setValue(client
.window
, XAtom::net_wm_allowed_actions
, XAtom::atom
,
2202 void BlackboxWindow::setState(unsigned long new_state
) {
2203 current_state
= new_state
;
2205 unsigned long state
[2];
2206 state
[0] = current_state
;
2208 xatom
->setValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
, state
, 2);
2210 xatom
->setValue(client
.window
, XAtom::blackbox_attributes
,
2211 XAtom::blackbox_attributes
, (unsigned long *)&blackbox_attrib
,
2212 PropBlackboxAttributesElements
);
2217 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_modal
);
2219 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_shaded
);
2221 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_hidden
);
2222 if (flags
.skip_taskbar
)
2223 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
);
2224 if (flags
.skip_pager
)
2225 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_pager
);
2226 if (flags
.fullscreen
)
2227 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_fullscreen
);
2228 if (flags
.maximized
== 1 || flags
.maximized
== 2)
2229 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_vert
);
2230 if (flags
.maximized
== 1 || flags
.maximized
== 3)
2231 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_horz
);
2232 xatom
->setValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
2237 bool BlackboxWindow::getState(void) {
2238 bool ret
= xatom
->getValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
,
2240 if (! ret
) current_state
= 0;
2245 void BlackboxWindow::restoreAttributes(void) {
2246 unsigned long num
= PropBlackboxAttributesElements
;
2247 BlackboxAttributes
*net
;
2248 if (! xatom
->getValue(client
.window
, XAtom::blackbox_attributes
,
2249 XAtom::blackbox_attributes
, num
,
2250 (unsigned long **)&net
))
2252 if (num
< PropBlackboxAttributesElements
) {
2257 if (net
->flags
& AttribShaded
&& net
->attrib
& AttribShaded
) {
2258 flags
.shaded
= False
;
2259 unsigned long orig_state
= current_state
;
2263 At this point in the life of a window, current_state should only be set
2264 to IconicState if the window was an *icon*, not if it was shaded.
2266 if (orig_state
!= IconicState
)
2267 current_state
= WithdrawnState
;
2270 if (net
->workspace
!= screen
->getCurrentWorkspaceID() &&
2271 net
->workspace
< screen
->getWorkspaceCount())
2272 screen
->reassociateWindow(this, net
->workspace
, True
);
2274 if ((blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID()) &&
2275 (blackbox_attrib
.workspace
< screen
->getWorkspaceCount())) {
2276 // set to WithdrawnState so it will be mapped on the new workspace
2277 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2278 } else if (current_state
== WithdrawnState
) {
2279 // the window is on this workspace and is Withdrawn, so it is waiting to
2281 current_state
= NormalState
;
2284 if (net
->flags
& AttribOmnipresent
&& net
->attrib
& AttribOmnipresent
&&
2288 // if the window was on another workspace, it was going to be hidden. this
2289 // specifies that the window should be mapped since it is sticky.
2290 if (current_state
== WithdrawnState
) current_state
= NormalState
;
2293 if (net
->flags
& AttribMaxHoriz
|| net
->flags
& AttribMaxVert
) {
2294 int x
= net
->premax_x
, y
= net
->premax_y
;
2295 unsigned int w
= net
->premax_w
, h
= net
->premax_h
;
2296 flags
.maximized
= 0;
2299 if ((net
->flags
& AttribMaxHoriz
) &&
2300 (net
->flags
& AttribMaxVert
))
2301 m
= (net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
2302 else if (net
->flags
& AttribMaxVert
)
2303 m
= (net
->attrib
& AttribMaxVert
) ? 2 : 0;
2304 else if (net
->flags
& AttribMaxHoriz
)
2305 m
= (net
->attrib
& AttribMaxHoriz
) ? 3 : 0;
2309 blackbox_attrib
.premax_x
= x
;
2310 blackbox_attrib
.premax_y
= y
;
2311 blackbox_attrib
.premax_w
= w
;
2312 blackbox_attrib
.premax_h
= h
;
2315 if (net
->flags
& AttribDecoration
) {
2316 switch (net
->decoration
) {
2321 /* since tools only let you toggle this anyways, we'll just make that all
2322 it supports for now.
2333 // with the state set it will then be the map event's job to read the
2334 // window's state and behave accordingly
2341 * Positions the Rect r according the the client window position and
2344 void BlackboxWindow::applyGravity(Rect
&r
) {
2345 // apply horizontal window gravity
2346 switch (client
.win_gravity
) {
2348 case NorthWestGravity
:
2349 case SouthWestGravity
:
2351 r
.setX(client
.rect
.x());
2357 r
.setX(client
.rect
.x() - (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2360 case NorthEastGravity
:
2361 case SouthEastGravity
:
2363 r
.setX(client
.rect
.x() - frame
.margin
.left
- frame
.margin
.right
+ 2);
2368 r
.setX(client
.rect
.x() - frame
.margin
.left
);
2372 // apply vertical window gravity
2373 switch (client
.win_gravity
) {
2375 case NorthWestGravity
:
2376 case NorthEastGravity
:
2378 r
.setY(client
.rect
.y());
2384 r
.setY(client
.rect
.y() - (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2387 case SouthWestGravity
:
2388 case SouthEastGravity
:
2390 r
.setY(client
.rect
.y() - frame
.margin
.top
- frame
.margin
.bottom
+ 2);
2395 r
.setY(client
.rect
.y() - frame
.margin
.top
);
2402 * The reverse of the applyGravity function.
2404 * Positions the Rect r according to the frame window position and
2407 void BlackboxWindow::restoreGravity(Rect
&r
) {
2408 // restore horizontal window gravity
2409 switch (client
.win_gravity
) {
2411 case NorthWestGravity
:
2412 case SouthWestGravity
:
2414 r
.setX(frame
.rect
.x());
2420 r
.setX(frame
.rect
.x() + (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2423 case NorthEastGravity
:
2424 case SouthEastGravity
:
2426 r
.setX(frame
.rect
.x() + frame
.margin
.left
+ frame
.margin
.right
- 2);
2431 r
.setX(frame
.rect
.x() + frame
.margin
.left
);
2435 // restore vertical window gravity
2436 switch (client
.win_gravity
) {
2438 case NorthWestGravity
:
2439 case NorthEastGravity
:
2441 r
.setY(frame
.rect
.y());
2447 r
.setY(frame
.rect
.y() + (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2450 case SouthWestGravity
:
2451 case SouthEastGravity
:
2453 r
.setY(frame
.rect
.y() + frame
.margin
.top
+ frame
.margin
.bottom
- 2);
2458 r
.setY(frame
.rect
.y() + frame
.margin
.top
);
2464 void BlackboxWindow::redrawLabel(void) const {
2465 if (flags
.focused
) {
2467 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2468 frame
.label
, frame
.flabel
);
2470 XSetWindowBackground(blackbox
->getXDisplay(),
2471 frame
.label
, frame
.flabel_pixel
);
2474 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2475 frame
.label
, frame
.ulabel
);
2477 XSetWindowBackground(blackbox
->getXDisplay(),
2478 frame
.label
, frame
.ulabel_pixel
);
2480 XClearWindow(blackbox
->getXDisplay(), frame
.label
);
2482 WindowStyle
*style
= screen
->getWindowStyle();
2484 int pos
= frame
.bevel_w
* 2;
2485 style
->doJustify(client
.title
.c_str(), pos
, frame
.label_w
, frame
.bevel_w
* 4);
2486 style
->font
->drawString(frame
.label
, pos
, 1,
2487 (flags
.focused
? style
->l_text_focus
:
2488 style
->l_text_unfocus
),
2493 void BlackboxWindow::redrawAllButtons(void) const {
2494 if (frame
.iconify_button
) redrawIconifyButton(False
);
2495 if (frame
.maximize_button
) redrawMaximizeButton(flags
.maximized
);
2496 if (frame
.close_button
) redrawCloseButton(False
);
2500 void BlackboxWindow::redrawIconifyButton(bool pressed
) const {
2502 if (flags
.focused
) {
2504 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2505 frame
.iconify_button
, frame
.fbutton
);
2507 XSetWindowBackground(blackbox
->getXDisplay(),
2508 frame
.iconify_button
, frame
.fbutton_pixel
);
2511 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2512 frame
.iconify_button
, frame
.ubutton
);
2514 XSetWindowBackground(blackbox
->getXDisplay(), frame
.iconify_button
,
2515 frame
.ubutton_pixel
);
2519 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2520 frame
.iconify_button
, frame
.pbutton
);
2522 XSetWindowBackground(blackbox
->getXDisplay(),
2523 frame
.iconify_button
, frame
.pbutton_pixel
);
2525 XClearWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
2527 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2528 screen
->getWindowStyle()->b_pic_unfocus
);
2529 XDrawRectangle(blackbox
->getXDisplay(), frame
.iconify_button
, pen
.gc(),
2530 2, (frame
.button_w
- 5), (frame
.button_w
- 5), 2);
2534 void BlackboxWindow::redrawMaximizeButton(bool pressed
) const {
2536 if (flags
.focused
) {
2538 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2539 frame
.maximize_button
, frame
.fbutton
);
2541 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2542 frame
.fbutton_pixel
);
2545 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2546 frame
.maximize_button
, frame
.ubutton
);
2548 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2549 frame
.ubutton_pixel
);
2553 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2554 frame
.maximize_button
, frame
.pbutton
);
2556 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2557 frame
.pbutton_pixel
);
2559 XClearWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
2561 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2562 screen
->getWindowStyle()->b_pic_unfocus
);
2563 XDrawRectangle(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2564 2, 2, (frame
.button_w
- 5), (frame
.button_w
- 5));
2565 XDrawLine(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2566 2, 3, (frame
.button_w
- 3), 3);
2570 void BlackboxWindow::redrawCloseButton(bool pressed
) const {
2572 if (flags
.focused
) {
2574 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2577 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2578 frame
.fbutton_pixel
);
2581 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2584 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2585 frame
.ubutton_pixel
);
2589 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2590 frame
.close_button
, frame
.pbutton
);
2592 XSetWindowBackground(blackbox
->getXDisplay(),
2593 frame
.close_button
, frame
.pbutton_pixel
);
2595 XClearWindow(blackbox
->getXDisplay(), frame
.close_button
);
2597 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2598 screen
->getWindowStyle()->b_pic_unfocus
);
2599 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2600 2, 2, (frame
.button_w
- 3), (frame
.button_w
- 3));
2601 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2602 2, (frame
.button_w
- 3), (frame
.button_w
- 3), 2);
2606 void BlackboxWindow::mapRequestEvent(const XMapRequestEvent
*re
) {
2607 if (re
->window
!= client
.window
)
2611 fprintf(stderr
, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2615 switch (current_state
) {
2620 case WithdrawnState
:
2629 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2631 if (! blackbox
->isStartup()) {
2632 XSync(blackbox
->getXDisplay(), False
); // make sure the frame is mapped
2633 if (screen
->doFocusNew() || (isTransient() && getTransientFor() &&
2634 getTransientFor()->isFocused())) {
2637 if (screen
->getPlacementPolicy() == BScreen::ClickMousePlacement
) {
2641 XQueryPointer(blackbox
->getXDisplay(), screen
->getRootWindow(),
2642 &r
, &c
, &rx
, &ry
, &x
, &y
, &m
);
2652 void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent
*ue
) {
2653 if (ue
->window
!= client
.window
)
2657 fprintf(stderr
, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2661 screen
->unmanageWindow(this, False
);
2665 void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent
*de
) {
2666 if (de
->window
!= client
.window
)
2670 fprintf(stderr
, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2674 screen
->unmanageWindow(this, False
);
2678 void BlackboxWindow::reparentNotifyEvent(const XReparentEvent
*re
) {
2679 if (re
->window
!= client
.window
|| re
->parent
== frame
.plate
)
2683 fprintf(stderr
, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2684 "0x%lx.\n", client
.window
, re
->parent
);
2689 XPutBackEvent(blackbox
->getXDisplay(), &ev
);
2690 screen
->unmanageWindow(this, True
);
2694 void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent
*pe
) {
2695 if (pe
->state
== PropertyDelete
)
2699 fprintf(stderr
, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n",
2705 case XA_WM_CLIENT_MACHINE
:
2709 case XA_WM_TRANSIENT_FOR
: {
2710 // determine if this is a transient window
2713 // adjust the window decorations based on transience
2714 if (isTransient()) {
2715 functions
&= ~Func_Maximize
;
2716 setAllowedActions();
2728 case XA_WM_ICON_NAME
:
2730 if (flags
.iconic
) screen
->propagateWindowName(this);
2733 case XAtom::net_wm_name
:
2737 if (decorations
& Decor_Titlebar
)
2740 screen
->propagateWindowName(this);
2743 case XA_WM_NORMAL_HINTS
: {
2746 if ((client
.normal_hint_flags
& PMinSize
) &&
2747 (client
.normal_hint_flags
& PMaxSize
)) {
2748 // the window now can/can't resize itself, so the buttons need to be
2751 if (client
.max_width
<= client
.min_width
&&
2752 client
.max_height
<= client
.min_height
) {
2753 functions
&= ~(Func_Resize
| Func_Maximize
);
2755 if (! isTransient())
2756 functions
|= Func_Maximize
;
2757 functions
|= Func_Resize
;
2760 setAllowedActions();
2764 Rect old_rect
= frame
.rect
;
2768 if (old_rect
!= frame
.rect
)
2775 if (pe
->atom
== xatom
->getAtom(XAtom::wm_protocols
)) {
2778 if ((decorations
& Decor_Close
) && (! frame
.close_button
)) {
2779 createCloseButton();
2780 if (decorations
& Decor_Titlebar
) {
2781 positionButtons(True
);
2782 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
2784 if (windowmenu
) windowmenu
->reconfigure();
2786 } else if (pe
->atom
== xatom
->getAtom(XAtom::net_wm_strut
)) {
2795 void BlackboxWindow::exposeEvent(const XExposeEvent
*ee
) {
2797 fprintf(stderr
, "BlackboxWindow::exposeEvent() for 0x%lx\n", client
.window
);
2800 if (frame
.label
== ee
->window
&& (decorations
& Decor_Titlebar
))
2802 else if (frame
.close_button
== ee
->window
)
2803 redrawCloseButton(False
);
2804 else if (frame
.maximize_button
== ee
->window
)
2805 redrawMaximizeButton(flags
.maximized
);
2806 else if (frame
.iconify_button
== ee
->window
)
2807 redrawIconifyButton(False
);
2811 void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent
*cr
) {
2812 if (cr
->window
!= client
.window
|| flags
.iconic
)
2815 if (cr
->value_mask
& CWBorderWidth
)
2816 client
.old_bw
= cr
->border_width
;
2818 if (cr
->value_mask
& (CWX
| CWY
| CWWidth
| CWHeight
)) {
2819 Rect req
= frame
.rect
;
2821 if (cr
->value_mask
& (CWX
| CWY
)) {
2822 if (cr
->value_mask
& CWX
)
2823 client
.rect
.setX(cr
->x
);
2824 if (cr
->value_mask
& CWY
)
2825 client
.rect
.setY(cr
->y
);
2830 if (cr
->value_mask
& CWWidth
)
2831 req
.setWidth(cr
->width
+ frame
.margin
.left
+ frame
.margin
.right
);
2833 if (cr
->value_mask
& CWHeight
)
2834 req
.setHeight(cr
->height
+ frame
.margin
.top
+ frame
.margin
.bottom
);
2836 configure(req
.x(), req
.y(), req
.width(), req
.height());
2839 if (cr
->value_mask
& CWStackMode
&& !isDesktop()) {
2840 switch (cr
->detail
) {
2843 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2849 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2856 void BlackboxWindow::buttonPressEvent(const XButtonEvent
*be
) {
2858 fprintf(stderr
, "BlackboxWindow::buttonPressEvent() for 0x%lx\n",
2862 if (frame
.maximize_button
== be
->window
&& be
->button
<= 3) {
2863 redrawMaximizeButton(True
);
2864 } else if (be
->button
== 1 || (be
->button
== 3 && be
->state
== mod_mask
)) {
2865 if (! flags
.focused
)
2868 if (frame
.iconify_button
== be
->window
) {
2869 redrawIconifyButton(True
);
2870 } else if (frame
.close_button
== be
->window
) {
2871 redrawCloseButton(True
);
2872 } else if (frame
.plate
== be
->window
) {
2873 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2875 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2877 XAllowEvents(blackbox
->getXDisplay(), ReplayPointer
, be
->time
);
2879 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
2880 if (((be
->time
- lastButtonPressTime
) <=
2881 blackbox
->getDoubleClickInterval()) ||
2882 (be
->state
== ControlMask
)) {
2883 lastButtonPressTime
= 0;
2886 lastButtonPressTime
= be
->time
;
2890 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
2892 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2894 } else if (be
->button
== 2 && (be
->window
!= frame
.iconify_button
) &&
2895 (be
->window
!= frame
.close_button
)) {
2896 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
2897 } else if (windowmenu
&& be
->button
== 3 &&
2898 (frame
.title
== be
->window
|| frame
.label
== be
->window
||
2899 frame
.handle
== be
->window
|| frame
.window
== be
->window
)) {
2900 if (windowmenu
->isVisible()) {
2903 int mx
= be
->x_root
- windowmenu
->getWidth() / 2,
2904 my
= be
->y_root
- windowmenu
->getHeight() / 2;
2906 // snap the window menu into a corner/side if necessary
2907 int left_edge
, right_edge
, top_edge
, bottom_edge
;
2910 the " + (frame.border_w * 2) - 1" bits are to get the proper width
2911 and height of the menu, as the sizes returned by it do not include
2914 left_edge
= frame
.rect
.x();
2915 right_edge
= frame
.rect
.right() -
2916 (windowmenu
->getWidth() + (frame
.border_w
* 2) - 1);
2917 top_edge
= client
.rect
.top() - (frame
.border_w
+ frame
.mwm_border_w
);
2918 bottom_edge
= client
.rect
.bottom() -
2919 (windowmenu
->getHeight() + (frame
.border_w
* 2) - 1) +
2920 (frame
.border_w
+ frame
.mwm_border_w
);
2924 if (mx
> right_edge
)
2928 if (my
> bottom_edge
)
2931 windowmenu
->move(mx
, my
);
2933 XRaiseWindow(blackbox
->getXDisplay(), windowmenu
->getWindowID());
2934 XRaiseWindow(blackbox
->getXDisplay(),
2935 windowmenu
->getSendToMenu()->getWindowID());
2938 } else if (be
->button
== 4) {
2939 if ((be
->window
== frame
.label
||
2940 be
->window
== frame
.title
||
2941 be
->window
== frame
.maximize_button
||
2942 be
->window
== frame
.iconify_button
||
2943 be
->window
== frame
.close_button
) &&
2947 } else if (be
->button
== 5) {
2948 if ((be
->window
== frame
.label
||
2949 be
->window
== frame
.title
||
2950 be
->window
== frame
.maximize_button
||
2951 be
->window
== frame
.iconify_button
||
2952 be
->window
== frame
.close_button
) &&
2959 void BlackboxWindow::buttonReleaseEvent(const XButtonEvent
*re
) {
2961 fprintf(stderr
, "BlackboxWindow::buttonReleaseEvent() for 0x%lx\n",
2965 if (re
->window
== frame
.maximize_button
&&
2966 re
->button
>= 1 && re
->button
<= 3) {
2967 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2968 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2969 maximize(re
->button
);
2971 redrawMaximizeButton(flags
.maximized
);
2973 } else if (re
->window
== frame
.iconify_button
&& re
->button
== 1) {
2974 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2975 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
2978 redrawIconifyButton(False
);
2980 } else if (re
->window
== frame
.close_button
& re
->button
== 1) {
2981 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
2982 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
)))
2984 redrawCloseButton(False
);
2985 } else if (flags
.moving
) {
2987 } else if (flags
.resizing
) {
2989 } else if (re
->window
== frame
.window
) {
2990 if (re
->button
== 2 && re
->state
== mod_mask
)
2991 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
2997 void BlackboxWindow::beginMove(int x_root
, int y_root
) {
2998 assert(! (flags
.resizing
|| flags
.moving
));
3001 Only one window can be moved/resized at a time. If another window is already
3002 being moved or resized, then stop it before whating to work with this one.
3004 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3005 if (changing
&& changing
!= this) {
3006 if (changing
->flags
.moving
)
3007 changing
->endMove();
3008 else // if (changing->flags.resizing)
3009 changing
->endResize();
3012 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3013 PointerMotionMask
| ButtonReleaseMask
,
3014 GrabModeAsync
, GrabModeAsync
,
3015 None
, blackbox
->getMoveCursor(), CurrentTime
);
3017 if (windowmenu
&& windowmenu
->isVisible())
3020 flags
.moving
= True
;
3021 blackbox
->setChangingWindow(this);
3023 if (! screen
->doOpaqueMove()) {
3024 XGrabServer(blackbox
->getXDisplay());
3026 frame
.changing
= frame
.rect
;
3027 screen
->showPosition(frame
.changing
.x(), frame
.changing
.y());
3029 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3033 frame
.changing
.width() - 1,
3034 frame
.changing
.height() - 1);
3037 frame
.grab_x
= x_root
- frame
.rect
.x() - frame
.border_w
;
3038 frame
.grab_y
= y_root
- frame
.rect
.y() - frame
.border_w
;
3042 void BlackboxWindow::doMove(int x_root
, int y_root
) {
3043 assert(flags
.moving
);
3044 assert(blackbox
->getChangingWindow() == this);
3046 int dx
= x_root
- frame
.grab_x
, dy
= y_root
- frame
.grab_y
;
3047 dx
-= frame
.border_w
;
3048 dy
-= frame
.border_w
;
3050 if (screen
->doWorkspaceWarping())
3051 if (doWorkspaceWarping(x_root
, y_root
, dx
, dy
))
3054 doWindowSnapping(dx
, dy
);
3056 if (screen
->doOpaqueMove()) {
3057 configure(dx
, dy
, frame
.rect
.width(), frame
.rect
.height());
3059 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3063 frame
.changing
.width() - 1,
3064 frame
.changing
.height() - 1);
3066 frame
.changing
.setPos(dx
, dy
);
3068 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3072 frame
.changing
.width() - 1,
3073 frame
.changing
.height() - 1);
3076 screen
->showPosition(dx
, dy
);
3080 bool BlackboxWindow::doWorkspaceWarping(int x_root
, int y_root
,
3082 // workspace warping
3084 unsigned int dest
= screen
->getCurrentWorkspaceID();
3088 if (dest
> 0) dest
--;
3089 else dest
= screen
->getNumberOfWorkspaces() - 1;
3091 } else if (x_root
>= screen
->getRect().right()) {
3094 if (dest
< screen
->getNumberOfWorkspaces() - 1) dest
++;
3101 bool focus
= flags
.focused
; // had focus while moving?
3103 screen
->reassociateWindow(this, dest
, False
);
3104 screen
->changeWorkspaceID(dest
);
3109 We grab the X server here because we are moving the window and then the
3110 mouse cursor. When one moves, it could end up putting the mouse cursor
3111 over another window for a moment. This can cause the warp to iniate a
3112 move on another window.
3114 XGrabServer(blackbox
->getXDisplay());
3117 dest_x
= screen
->getRect().right() - 1;
3118 configure(dx
+ (screen
->getRect().width() - 1), dy
,
3119 frame
.rect
.width(), frame
.rect
.height());
3122 configure(dx
- (screen
->getRect().width() - 1), dy
,
3123 frame
.rect
.width(), frame
.rect
.height());
3125 XWarpPointer(blackbox
->getXDisplay(), None
,
3126 screen
->getRootWindow(), 0, 0, 0, 0,
3128 XUngrabServer(blackbox
->getXDisplay());
3130 beginMove(dest_x
, y_root
);
3135 void BlackboxWindow::doWindowSnapping(int &dx
, int &dy
) {
3136 // how much resistance to edges to provide
3137 const int resistance_size
= screen
->getResistanceSize();
3139 // how far away to snap
3140 const int snap_distance
= screen
->getSnapThreshold();
3142 // how to snap windows
3143 const int snap_to_windows
= screen
->getWindowToWindowSnap();
3144 const int snap_to_edges
= screen
->getWindowToEdgeSnap();
3145 // the amount of space away from the edge to provide resistance/snap
3146 const int snap_offset
= screen
->getSnapOffset();
3148 // find the geomeetery where the moving window currently is
3149 const Rect
&moving
= screen
->doOpaqueMove() ? frame
.rect
: frame
.changing
;
3152 const int wleft
= dx
,
3153 wright
= dx
+ frame
.rect
.width() - 1,
3155 wbottom
= dy
+ frame
.rect
.height() - 1;
3157 if (snap_to_windows
) {
3160 Workspace
*w
= screen
->getWorkspace(getWorkspaceNumber());
3163 // add windows on the workspace to the rect list
3164 const BlackboxWindowList
& stack_list
= w
->getStackingList();
3165 BlackboxWindowList::const_iterator st_it
, st_end
= stack_list
.end();
3166 for (st_it
= stack_list
.begin(); st_it
!= st_end
; ++st_it
)
3167 if (*st_it
!= this) // don't snap to ourself
3168 rectlist
.push_back( (*st_it
)->frameRect() );
3170 // add the toolbar and the slit to the rect list.
3171 // (only if they are not hidden)
3172 Toolbar
*tbar
= screen
->getToolbar();
3173 Slit
*slit
= screen
->getSlit();
3174 Rect tbar_rect
, slit_rect
;
3175 unsigned int bwidth
= screen
->getBorderWidth() * 2;
3177 if (! (screen
->doHideToolbar() || tbar
->isHidden())) {
3178 tbar_rect
.setRect(tbar
->getX(), tbar
->getY(), tbar
->getWidth() + bwidth
,
3179 tbar
->getHeight() + bwidth
);
3180 rectlist
.push_back(tbar_rect
);
3183 if (! slit
->isHidden()) {
3184 slit_rect
.setRect(slit
->getX(), slit
->getY(), slit
->getWidth() + bwidth
,
3185 slit
->getHeight() + bwidth
);
3186 rectlist
.push_back(slit_rect
);
3189 RectList::const_iterator it
, end
= rectlist
.end();
3190 for (it
= rectlist
.begin(); it
!= end
; ++it
) {
3191 bool snapped
= False
;
3192 const Rect
&winrect
= *it
;
3194 offsetrect
.setCoords(winrect
.left() - snap_offset
,
3195 winrect
.top() - snap_offset
,
3196 winrect
.right() + snap_offset
,
3197 winrect
.bottom() + snap_offset
);
3199 if (snap_to_windows
== BScreen::WindowResistance
)
3200 // if the window is already over top of this snap target, then
3201 // resistance is futile, so just ignore it
3202 if (winrect
.intersects(moving
))
3205 int dleft
, dright
, dtop
, dbottom
;
3207 // if the windows are in the same plane vertically
3208 if (wtop
>= (signed)(winrect
.y() - frame
.rect
.height() + 1) &&
3209 wtop
< (signed)(winrect
.y() + winrect
.height() - 1)) {
3211 if (snap_to_windows
== BScreen::WindowResistance
) {
3212 dleft
= wright
- offsetrect
.left();
3213 dright
= offsetrect
.right() - wleft
;
3215 // snap left of other window?
3216 if (dleft
>= 0 && dleft
< resistance_size
&&
3217 dleft
< (wright
- wleft
)) {
3218 dx
= offsetrect
.left() - frame
.rect
.width();
3221 // snap right of other window?
3222 else if (dright
>= 0 && dright
< resistance_size
&&
3223 dright
< (wright
- wleft
)) {
3224 dx
= offsetrect
.right() + 1;
3227 } else { // BScreen::WindowSnap
3228 dleft
= abs(wright
- offsetrect
.left());
3229 dright
= abs(wleft
- offsetrect
.right());
3231 // snap left of other window?
3232 if (dleft
< snap_distance
&& dleft
<= dright
) {
3233 dx
= offsetrect
.left() - frame
.rect
.width();
3236 // snap right of other window?
3237 else if (dright
< snap_distance
) {
3238 dx
= offsetrect
.right() + 1;
3244 if (screen
->getWindowCornerSnap()) {
3245 // try corner-snap to its other sides
3246 if (snap_to_windows
== BScreen::WindowResistance
) {
3247 dtop
= winrect
.top() - wtop
;
3248 dbottom
= wbottom
- winrect
.bottom();
3249 if (dtop
> 0 && dtop
< resistance_size
) {
3250 // if we're already past the top edge, then don't provide
3252 if (moving
.top() >= winrect
.top())
3254 } else if (dbottom
> 0 && dbottom
< resistance_size
) {
3255 // if we're already past the bottom edge, then don't provide
3257 if (moving
.bottom() <= winrect
.bottom())
3258 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
3260 } else { // BScreen::WindowSnap
3261 dtop
= abs(wtop
- winrect
.top());
3262 dbottom
= abs(wbottom
- winrect
.bottom());
3263 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3265 else if (dbottom
< snap_distance
)
3266 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
3274 // if the windows are on the same plane horizontally
3275 if (wleft
>= (signed)(winrect
.x() - frame
.rect
.width() + 1) &&
3276 wleft
< (signed)(winrect
.x() + winrect
.width() - 1)) {
3278 if (snap_to_windows
== BScreen::WindowResistance
) {
3279 dtop
= wbottom
- offsetrect
.top();
3280 dbottom
= offsetrect
.bottom() - wtop
;
3282 // snap top of other window?
3283 if (dtop
>= 0 && dtop
< resistance_size
&& dtop
< (wbottom
- wtop
)) {
3284 dy
= offsetrect
.top() - frame
.rect
.height();
3287 // snap bottom of other window?
3288 else if (dbottom
>= 0 && dbottom
< resistance_size
&&
3289 dbottom
< (wbottom
- wtop
)) {
3290 dy
= offsetrect
.bottom() + 1;
3293 } else { // BScreen::WindowSnap
3294 dtop
= abs(wbottom
- offsetrect
.top());
3295 dbottom
= abs(wtop
- offsetrect
.bottom());
3297 // snap top of other window?
3298 if (dtop
< snap_distance
&& dtop
<= dbottom
) {
3299 dy
= offsetrect
.top() - frame
.rect
.height();
3302 // snap bottom of other window?
3303 else if (dbottom
< snap_distance
) {
3304 dy
= offsetrect
.bottom() + 1;
3311 if (screen
->getWindowCornerSnap()) {
3312 // try corner-snap to its other sides
3313 if (snap_to_windows
== BScreen::WindowResistance
) {
3314 dleft
= winrect
.left() - wleft
;
3315 dright
= wright
- winrect
.right();
3316 if (dleft
> 0 && dleft
< resistance_size
) {
3317 // if we're already past the left edge, then don't provide
3319 if (moving
.left() >= winrect
.left())
3320 dx
= winrect
.left();
3321 } else if (dright
> 0 && dright
< resistance_size
) {
3322 // if we're already past the right edge, then don't provide
3324 if (moving
.right() <= winrect
.right())
3325 dx
= winrect
.right() - frame
.rect
.width() + 1;
3327 } else { // BScreen::WindowSnap
3328 dleft
= abs(wleft
- winrect
.left());
3329 dright
= abs(wright
- winrect
.right());
3330 if (dleft
< snap_distance
&& dleft
<= dright
)
3331 dx
= winrect
.left();
3332 else if (dright
< snap_distance
)
3333 dx
= winrect
.right() - frame
.rect
.width() + 1;
3343 if (snap_to_edges
) {
3346 // snap to the screen edges (and screen boundaries for xinerama)
3348 if (screen
->isXineramaActive() && blackbox
->doXineramaSnapping()) {
3349 rectlist
.insert(rectlist
.begin(),
3350 screen
->getXineramaAreas().begin(),
3351 screen
->getXineramaAreas().end());
3354 rectlist
.push_back(screen
->getRect());
3356 RectList::const_iterator it
, end
= rectlist
.end();
3357 for (it
= rectlist
.begin(); it
!= end
; ++it
) {
3358 const Rect
&srect
= *it
;
3360 offsetrect
.setCoords(srect
.left() + snap_offset
,
3361 srect
.top() + snap_offset
,
3362 srect
.right() - snap_offset
,
3363 srect
.bottom() - snap_offset
);
3365 if (snap_to_edges
== BScreen::WindowResistance
) {
3366 // if we're not in the rectangle then don't snap to it.
3367 if (! srect
.contains(moving
))
3369 } else { // BScreen::WindowSnap
3370 // if we're not in the rectangle then don't snap to it.
3371 if (! srect
.intersects(Rect(wleft
, wtop
, frame
.rect
.width(),
3372 frame
.rect
.height())))
3376 if (snap_to_edges
== BScreen::WindowResistance
) {
3377 int dleft
= offsetrect
.left() - wleft
,
3378 dright
= wright
- offsetrect
.right(),
3379 dtop
= offsetrect
.top() - wtop
,
3380 dbottom
= wbottom
- offsetrect
.bottom();
3383 if (dleft
> 0 && dleft
< resistance_size
)
3384 dx
= offsetrect
.left();
3386 else if (dright
> 0 && dright
< resistance_size
)
3387 dx
= offsetrect
.right() - frame
.rect
.width() + 1;
3390 if (dtop
> 0 && dtop
< resistance_size
)
3391 dy
= offsetrect
.top();
3393 else if (dbottom
> 0 && dbottom
< resistance_size
)
3394 dy
= offsetrect
.bottom() - frame
.rect
.height() + 1;
3395 } else { // BScreen::WindowSnap
3396 int dleft
= abs(wleft
- offsetrect
.left()),
3397 dright
= abs(wright
- offsetrect
.right()),
3398 dtop
= abs(wtop
- offsetrect
.top()),
3399 dbottom
= abs(wbottom
- offsetrect
.bottom());
3402 if (dleft
< snap_distance
&& dleft
<= dright
)
3403 dx
= offsetrect
.left();
3405 else if (dright
< snap_distance
)
3406 dx
= offsetrect
.right() - frame
.rect
.width() + 1;
3409 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3410 dy
= offsetrect
.top();
3412 else if (dbottom
< snap_distance
)
3413 dy
= offsetrect
.bottom() - frame
.rect
.height() + 1;
3420 void BlackboxWindow::endMove(void) {
3421 assert(flags
.moving
);
3422 assert(blackbox
->getChangingWindow() == this);
3424 flags
.moving
= False
;
3425 blackbox
->setChangingWindow(0);
3427 if (! screen
->doOpaqueMove()) {
3428 /* when drawing the rubber band, we need to make sure we only draw inside
3429 * the frame... frame.changing_* contain the new coords for the window,
3430 * so we need to subtract 1 from changing_w/changing_h every where we
3431 * draw the rubber band (for both moving and resizing)
3433 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3434 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3435 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3436 XUngrabServer(blackbox
->getXDisplay());
3438 configure(frame
.changing
.x(), frame
.changing
.y(),
3439 frame
.changing
.width(), frame
.changing
.height());
3441 configure(frame
.rect
.x(), frame
.rect
.y(),
3442 frame
.rect
.width(), frame
.rect
.height());
3444 screen
->hideGeometry();
3446 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3448 // if there are any left over motions from the move, drop them now
3449 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3451 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3456 void BlackboxWindow::beginResize(int x_root
, int y_root
, Corner dir
) {
3457 assert(! (flags
.resizing
|| flags
.moving
));
3460 Only one window can be moved/resized at a time. If another window is already
3461 being moved or resized, then stop it before whating to work with this one.
3463 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3464 if (changing
&& changing
!= this) {
3465 if (changing
->flags
.moving
)
3466 changing
->endMove();
3467 else // if (changing->flags.resizing)
3468 changing
->endResize();
3476 switch (resize_dir
) {
3479 cursor
= blackbox
->getLowerLeftAngleCursor();
3484 cursor
= blackbox
->getLowerRightAngleCursor();
3488 anchor
= BottomRight
;
3489 cursor
= blackbox
->getUpperLeftAngleCursor();
3493 anchor
= BottomLeft
;
3494 cursor
= blackbox
->getUpperRightAngleCursor();
3498 assert(false); // unhandled Corner
3499 return; // unreachable, for the compiler
3502 XGrabServer(blackbox
->getXDisplay());
3503 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3504 PointerMotionMask
| ButtonReleaseMask
,
3505 GrabModeAsync
, GrabModeAsync
, None
, cursor
, CurrentTime
);
3507 flags
.resizing
= True
;
3508 blackbox
->setChangingWindow(this);
3510 unsigned int gw
, gh
;
3511 frame
.changing
= frame
.rect
;
3513 constrain(anchor
, &gw
, &gh
);
3515 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3516 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3517 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3519 screen
->showGeometry(gw
, gh
);
3521 frame
.grab_x
= x_root
;
3522 frame
.grab_y
= y_root
;
3526 void BlackboxWindow::doResize(int x_root
, int y_root
) {
3527 assert(flags
.resizing
);
3528 assert(blackbox
->getChangingWindow() == this);
3530 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3531 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3532 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3534 unsigned int gw
, gh
;
3537 switch (resize_dir
) {
3540 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3541 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3545 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3546 frame
.rect
.height() + (y_root
- frame
.grab_y
));
3549 anchor
= BottomRight
;
3550 frame
.changing
.setSize(frame
.rect
.width() - (x_root
- frame
.grab_x
),
3551 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3554 anchor
= BottomLeft
;
3555 frame
.changing
.setSize(frame
.rect
.width() + (x_root
- frame
.grab_x
),
3556 frame
.rect
.height() - (y_root
- frame
.grab_y
));
3560 assert(false); // unhandled Corner
3561 return; // unreachable, for the compiler
3564 constrain(anchor
, &gw
, &gh
);
3566 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3567 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3568 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3570 screen
->showGeometry(gw
, gh
);
3574 void BlackboxWindow::endResize(void) {
3575 assert(flags
.resizing
);
3576 assert(blackbox
->getChangingWindow() == this);
3578 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3579 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3580 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3581 XUngrabServer(blackbox
->getXDisplay());
3583 // unset maximized state after resized when fully maximized
3584 if (flags
.maximized
== 1)
3587 flags
.resizing
= False
;
3588 blackbox
->setChangingWindow(0);
3590 configure(frame
.changing
.x(), frame
.changing
.y(),
3591 frame
.changing
.width(), frame
.changing
.height());
3592 screen
->hideGeometry();
3594 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3596 // if there are any left over motions from the resize, drop them now
3597 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3599 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3604 void BlackboxWindow::motionNotifyEvent(const XMotionEvent
*me
) {
3606 fprintf(stderr
, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n",
3611 doMove(me
->x_root
, me
->y_root
);
3612 } else if (flags
.resizing
) {
3613 doResize(me
->x_root
, me
->y_root
);
3615 if (!flags
.resizing
&& me
->state
& Button1Mask
&& (functions
& Func_Move
) &&
3616 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3617 frame
.handle
== me
->window
|| frame
.window
== me
->window
)) {
3618 beginMove(me
->x_root
, me
->y_root
);
3619 } else if ((functions
& Func_Resize
) &&
3620 (me
->state
& Button1Mask
&& (me
->window
== frame
.right_grip
||
3621 me
->window
== frame
.left_grip
)) ||
3622 (me
->state
& Button3Mask
&& me
->state
& mod_mask
&&
3623 me
->window
== frame
.window
)) {
3624 unsigned int zones
= screen
->getResizeZones();
3627 if (me
->window
== frame
.left_grip
) {
3628 corner
= BottomLeft
;
3629 } else if (me
->window
== frame
.right_grip
|| zones
== 1) {
3630 corner
= BottomRight
;
3633 bool left
= (me
->x_root
- frame
.rect
.x() <=
3634 static_cast<signed>(frame
.rect
.width() / 2));
3637 else // (zones == 4)
3638 top
= (me
->y_root
- frame
.rect
.y() <=
3639 static_cast<signed>(frame
.rect
.height() / 2));
3640 corner
= (top
? (left
? TopLeft
: TopRight
) :
3641 (left
? BottomLeft
: BottomRight
));
3644 beginResize(me
->x_root
, me
->y_root
, corner
);
3650 void BlackboxWindow::enterNotifyEvent(const XCrossingEvent
* ce
) {
3651 if (! (screen
->isSloppyFocus() && isVisible() && isNormal()))
3655 bool leave
= False
, inferior
= False
;
3657 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), ce
->window
,
3659 if (e
.type
== LeaveNotify
&& e
.xcrossing
.mode
== NotifyNormal
) {
3661 inferior
= (e
.xcrossing
.detail
== NotifyInferior
);
3665 if ((! leave
|| inferior
) && ! isFocused()) {
3666 bool success
= setInputFocus();
3667 if (success
) // if focus succeeded install the colormap
3668 installColormap(True
); // XXX: shouldnt we honour no install?
3671 if (screen
->doAutoRaise())
3676 void BlackboxWindow::leaveNotifyEvent(const XCrossingEvent
*) {
3677 if (! (screen
->isSloppyFocus() && screen
->doAutoRaise() && isNormal()))
3680 installColormap(False
);
3682 if (timer
->isTiming())
3688 void BlackboxWindow::shapeEvent(XShapeEvent
*) {
3689 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
3696 bool BlackboxWindow::validateClient(void) const {
3697 XSync(blackbox
->getXDisplay(), False
);
3700 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3701 DestroyNotify
, &e
) ||
3702 XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3704 XPutBackEvent(blackbox
->getXDisplay(), &e
);
3713 void BlackboxWindow::restore(bool remap
) {
3714 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeDelete
);
3715 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
3716 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, NoEventMask
);
3718 // do not leave a shaded window as an icon unless it was an icon
3719 if (flags
.shaded
&& ! flags
.iconic
)
3720 setState(NormalState
);
3722 restoreGravity(client
.rect
);
3724 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
3725 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
3727 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, client
.old_bw
);
3730 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3731 ReparentNotify
, &ev
)) {
3734 // according to the ICCCM - if the client doesn't reparent to
3735 // root, then we have to do it for them
3736 XReparentWindow(blackbox
->getXDisplay(), client
.window
,
3737 screen
->getRootWindow(),
3738 client
.rect
.x(), client
.rect
.y());
3741 if (remap
) XMapWindow(blackbox
->getXDisplay(), client
.window
);
3745 // timer for autoraise
3746 void BlackboxWindow::timeout(void) {
3747 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3751 void BlackboxWindow::changeBlackboxHints(const BlackboxHints
*net
) {
3752 if ((net
->flags
& AttribShaded
) &&
3753 ((blackbox_attrib
.attrib
& AttribShaded
) !=
3754 (net
->attrib
& AttribShaded
)))
3757 if (flags
.visible
&& // watch out for requests when we can not be seen
3758 (net
->flags
& (AttribMaxVert
| AttribMaxHoriz
)) &&
3759 ((blackbox_attrib
.attrib
& (AttribMaxVert
| AttribMaxHoriz
)) !=
3760 (net
->attrib
& (AttribMaxVert
| AttribMaxHoriz
)))) {
3761 if (flags
.maximized
) {
3766 if ((net
->flags
& AttribMaxHoriz
) && (net
->flags
& AttribMaxVert
))
3767 button
= ((net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0);
3768 else if (net
->flags
& AttribMaxVert
)
3769 button
= ((net
->attrib
& AttribMaxVert
) ? 2 : 0);
3770 else if (net
->flags
& AttribMaxHoriz
)
3771 button
= ((net
->attrib
& AttribMaxHoriz
) ? 3 : 0);
3777 if ((net
->flags
& AttribOmnipresent
) &&
3778 ((blackbox_attrib
.attrib
& AttribOmnipresent
) !=
3779 (net
->attrib
& AttribOmnipresent
)))
3782 if ((net
->flags
& AttribWorkspace
) &&
3783 (blackbox_attrib
.workspace
!= net
->workspace
)) {
3784 screen
->reassociateWindow(this, net
->workspace
, True
);
3786 if (screen
->getCurrentWorkspaceID() != net
->workspace
) {
3790 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3794 if (net
->flags
& AttribDecoration
) {
3795 switch (net
->decoration
) {
3812 * Set the sizes of all components of the window frame
3813 * (the window decorations).
3814 * These values are based upon the current style settings and the client
3815 * window's dimensions.
3817 void BlackboxWindow::upsize(void) {
3818 frame
.bevel_w
= screen
->getBevelWidth();
3820 if (decorations
& Decor_Border
) {
3821 frame
.border_w
= screen
->getBorderWidth();
3822 if (! isTransient())
3823 frame
.mwm_border_w
= screen
->getFrameWidth();
3825 frame
.mwm_border_w
= 0;
3827 frame
.mwm_border_w
= frame
.border_w
= 0;
3830 if (decorations
& Decor_Titlebar
) {
3831 // the height of the titlebar is based upon the height of the font being
3832 // used to display the window's title
3833 WindowStyle
*style
= screen
->getWindowStyle();
3834 frame
.title_h
= style
->font
->height() + (frame
.bevel_w
* 2) + 2;
3836 frame
.label_h
= frame
.title_h
- (frame
.bevel_w
* 2);
3837 frame
.button_w
= (frame
.label_h
- 2);
3839 // set the top frame margin
3840 frame
.margin
.top
= frame
.border_w
+ frame
.title_h
+
3841 frame
.border_w
+ frame
.mwm_border_w
;
3847 // set the top frame margin
3848 frame
.margin
.top
= frame
.border_w
+ frame
.mwm_border_w
;
3851 // set the left/right frame margin
3852 frame
.margin
.left
= frame
.margin
.right
= frame
.border_w
+ frame
.mwm_border_w
;
3854 if (decorations
& Decor_Handle
) {
3855 frame
.grip_w
= frame
.button_w
* 2;
3856 frame
.handle_h
= screen
->getHandleWidth();
3858 // set the bottom frame margin
3859 frame
.margin
.bottom
= frame
.border_w
+ frame
.handle_h
+
3860 frame
.border_w
+ frame
.mwm_border_w
;
3865 // set the bottom frame margin
3866 frame
.margin
.bottom
= frame
.border_w
+ frame
.mwm_border_w
;
3870 We first get the normal dimensions and use this to define the inside_w/h
3871 then we modify the height if shading is in effect.
3872 If the shade state is not considered then frame.rect gets reset to the
3873 normal window size on a reconfigure() call resulting in improper
3874 dimensions appearing in move/resize and other events.
3877 height
= client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
,
3878 width
= client
.rect
.width() + frame
.margin
.left
+ frame
.margin
.right
;
3880 frame
.inside_w
= width
- (frame
.border_w
* 2);
3881 frame
.inside_h
= height
- (frame
.border_w
* 2);
3884 height
= frame
.title_h
+ (frame
.border_w
* 2);
3885 frame
.rect
.setSize(width
, height
);
3890 * Calculate the size of the client window and constrain it to the
3891 * size specified by the size hints of the client window.
3893 * The logical width and height are placed into pw and ph, if they
3894 * are non-zero. Logical size refers to the users perception of
3895 * the window size (for example an xterm resizes in cells, not in pixels).
3896 * pw and ph are then used to display the geometry during window moves, resize,
3899 * The physical geometry is placed into frame.changing_{x,y,width,height}.
3900 * Physical geometry refers to the geometry of the window in pixels.
3902 void BlackboxWindow::constrain(Corner anchor
,
3903 unsigned int *pw
, unsigned int *ph
) {
3904 // frame.changing represents the requested frame size, we need to
3905 // strip the frame margin off and constrain the client size
3906 frame
.changing
.setCoords(frame
.changing
.left() + frame
.margin
.left
,
3907 frame
.changing
.top() + frame
.margin
.top
,
3908 frame
.changing
.right() - frame
.margin
.right
,
3909 frame
.changing
.bottom() - frame
.margin
.bottom
);
3911 unsigned int dw
= frame
.changing
.width(), dh
= frame
.changing
.height(),
3912 base_width
= (client
.base_width
) ? client
.base_width
: client
.min_width
,
3913 base_height
= (client
.base_height
) ? client
.base_height
:
3917 if (dw
< client
.min_width
) dw
= client
.min_width
;
3918 if (dh
< client
.min_height
) dh
= client
.min_height
;
3919 if (dw
> client
.max_width
) dw
= client
.max_width
;
3920 if (dh
> client
.max_height
) dh
= client
.max_height
;
3922 assert(dw
>= base_width
&& dh
>= base_height
);
3924 if (client
.width_inc
> 1) {
3926 dw
/= client
.width_inc
;
3928 if (client
.height_inc
> 1) {
3930 dh
/= client
.height_inc
;
3939 if (client
.width_inc
> 1) {
3940 dw
*= client
.width_inc
;
3943 if (client
.height_inc
> 1) {
3944 dh
*= client
.height_inc
;
3948 frame
.changing
.setSize(dw
, dh
);
3950 // add the frame margin back onto frame.changing
3951 frame
.changing
.setCoords(frame
.changing
.left() - frame
.margin
.left
,
3952 frame
.changing
.top() - frame
.margin
.top
,
3953 frame
.changing
.right() + frame
.margin
.right
,
3954 frame
.changing
.bottom() + frame
.margin
.bottom
);
3956 // move frame.changing to the specified anchor
3964 dx
= frame
.rect
.right() - frame
.changing
.right();
3968 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3972 dx
= frame
.rect
.right() - frame
.changing
.right();
3973 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
3977 assert(false); // unhandled corner
3979 frame
.changing
.setPos(frame
.changing
.x() + dx
, frame
.changing
.y() + dy
);
3983 void WindowStyle::doJustify(const std::string
&text
, int &start_pos
,
3984 unsigned int max_length
,
3985 unsigned int modifier
) const {
3986 size_t text_len
= text
.size();
3987 unsigned int length
;
3990 length
= font
->measureString(string(text
, 0, text_len
)) + modifier
;
3991 } while (length
> max_length
&& text_len
-- > 0);
3995 start_pos
+= max_length
- length
;
3999 start_pos
+= (max_length
- length
) / 2;
4009 BWindowGroup::BWindowGroup(Blackbox
*b
, Window _group
)
4010 : blackbox(b
), group(_group
) {
4011 XWindowAttributes wattrib
;
4012 if (! XGetWindowAttributes(blackbox
->getXDisplay(), group
, &wattrib
)) {
4013 // group window doesn't seem to exist anymore
4018 XSelectInput(blackbox
->getXDisplay(), group
,
4019 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
4021 blackbox
->saveGroupSearch(group
, this);
4025 BWindowGroup::~BWindowGroup(void) {
4026 blackbox
->removeGroupSearch(group
);
4031 BWindowGroup::find(BScreen
*screen
, bool allow_transients
) const {
4032 BlackboxWindow
*ret
= blackbox
->getFocusedWindow();
4034 // does the focus window match (or any transient_fors)?
4035 for (; ret
; ret
= ret
->getTransientFor()) {
4036 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
&&
4037 (! ret
->isTransient() || allow_transients
))
4041 if (ret
) return ret
;
4043 // the focus window didn't match, look in the group's window list
4044 BlackboxWindowList::const_iterator it
, end
= windowList
.end();
4045 for (it
= windowList
.begin(); it
!= end
; ++it
) {
4047 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
&&
4048 (! ret
->isTransient() || allow_transients
))