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
=
132 frame
.stick_button
= None
;
133 frame
.right_grip
= frame
.left_grip
= None
;
135 frame
.ulabel_pixel
= frame
.flabel_pixel
= frame
.utitle_pixel
=
136 frame
.ftitle_pixel
= frame
.uhandle_pixel
= frame
.fhandle_pixel
=
137 frame
.ubutton_pixel
= frame
.fbutton_pixel
= frame
.pbutton_pixel
=
138 frame
.uborder_pixel
= frame
.fborder_pixel
= frame
.ugrip_pixel
=
139 frame
.fgrip_pixel
= 0;
140 frame
.utitle
= frame
.ftitle
= frame
.uhandle
= frame
.fhandle
= None
;
141 frame
.ulabel
= frame
.flabel
= frame
.ubutton
= frame
.fbutton
= None
;
142 frame
.pbutton
= frame
.ugrip
= frame
.fgrip
= None
;
144 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
145 mwm_decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
146 Decor_Iconify
| Decor_Maximize
;
148 client
.normal_hint_flags
= 0;
149 client
.window_group
= None
;
150 client
.transient_for
= 0;
152 current_state
= NormalState
;
157 set the initial size and location of client window (relative to the
158 _root window_). This position is the reference point used with the
159 window's gravity to find the window's initial position.
161 client
.rect
.setRect(wattrib
.x
, wattrib
.y
, wattrib
.width
, wattrib
.height
);
162 client
.old_bw
= wattrib
.border_width
;
164 lastButtonPressTime
= 0;
166 timer
= new BTimer(blackbox
, this);
167 timer
->setTimeout(blackbox
->getAutoRaiseDelay());
169 // get size, aspect, minimum/maximum size and other hints set by the
172 if (! getBlackboxHints())
179 frame
.window
= createToplevelWindow();
181 blackbox
->saveWindowSearch(frame
.window
, this);
183 frame
.plate
= createChildWindow(frame
.window
, ExposureMask
);
184 blackbox
->saveWindowSearch(frame
.plate
, this);
186 // determine if this is a transient window
189 // determine the window's type, so we can decide its decorations and
190 // functionality, or if we should not manage it at all
191 if (getWindowType()) {
192 // adjust the window decorations/behavior based on the window type
193 switch (window_type
) {
197 blackbox_attrib
.workspace
= 0; // we do need to belong to a workspace
198 flags
.stuck
= True
; // we show up on all workspaces
200 // none of these windows are manipulated by the window manager
206 // these windows get less functionality
207 functions
&= ~(Func_Maximize
| Func_Resize
| Func_Iconify
);
211 // dialogs cannot be maximized
212 functions
&= ~Func_Maximize
;
216 // normal windows retain all of the possible decorations and
224 // further adjeust the window's decorations/behavior based on window sizes
225 if ((client
.normal_hint_flags
& PMinSize
) &&
226 (client
.normal_hint_flags
& PMaxSize
) &&
227 client
.max_width
<= client
.min_width
&&
228 client
.max_height
<= client
.min_height
) {
229 functions
&= ~(Func_Resize
| Func_Maximize
);
236 if (decorations
& Decor_Titlebar
)
239 if (decorations
& Decor_Handle
)
242 // apply the size and gravity hint to the frame
246 bool place_window
= True
;
247 if (blackbox
->isStartup() || isTransient() ||
248 client
.normal_hint_flags
& (PPosition
|USPosition
)) {
249 applyGravity(frame
.rect
);
251 if (blackbox
->isStartup() || client
.rect
.intersects(screen
->getRect()))
252 place_window
= False
;
255 // add the window's strut. note this is done *after* placing the window.
256 screen
->addStrut(&client
.strut
);
260 the server needs to be grabbed here to prevent client's from sending
261 events while we are in the process of configuring their window.
262 We hold the grab until after we are done moving the window around.
265 XGrabServer(blackbox
->getXDisplay());
267 associateClientWindow();
269 blackbox
->saveWindowSearch(client
.window
, this);
271 if (blackbox_attrib
.workspace
>= screen
->getWorkspaceCount())
272 screen
->getCurrentWorkspace()->addWindow(this, place_window
);
274 screen
->getWorkspace(blackbox_attrib
.workspace
)->
275 addWindow(this, place_window
);
277 if (! place_window
) {
278 // don't need to call configure if we are letting the workspace
280 configure(frame
.rect
.x(), frame
.rect
.y(),
281 frame
.rect
.width(), frame
.rect
.height());
287 XUngrabServer(blackbox
->getXDisplay());
290 if (blackbox
->hasShapeExtensions() && flags
.shaped
)
294 // now that we know where to put the window and what it should look like
295 // we apply the decorations
300 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
302 // this ensures the title, buttons, and other decor are properly displayed
305 // preserve the window's initial state on first map, and its current state
307 unsigned long initial_state
= current_state
;
309 current_state
= initial_state
;
311 // get sticky state from our parent window if we've got one
312 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
313 client
.transient_for
->isStuck() != flags
.stuck
)
317 flags
.shaded
= False
;
318 initial_state
= current_state
;
322 At this point in the life of a window, current_state should only be set
323 to IconicState if the window was an *icon*, not if it was shaded.
325 if (initial_state
!= IconicState
)
326 current_state
= NormalState
;
334 if (flags
.maximized
&& (functions
& Func_Maximize
))
337 // create this last so it only needs to be configured once
338 windowmenu
= new Windowmenu(this);
342 BlackboxWindow::~BlackboxWindow(void) {
344 fprintf(stderr
, "BlackboxWindow::~BlackboxWindow: destroying 0x%lx\n",
348 if (! timer
) // window not managed...
354 screen
->removeStrut(&client
.strut
);
355 screen
->updateAvailableArea();
357 // We don't need to worry about resizing because resizing always grabs the X
358 // server. This should only ever happen if using opaque moving.
366 if (client
.window_group
) {
367 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
368 if (group
) group
->removeWindow(this);
371 // remove ourselves from our transient_for
373 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul)
374 client
.transient_for
->client
.transientList
.remove(this);
375 client
.transient_for
= (BlackboxWindow
*) 0;
378 if (client
.transientList
.size() > 0) {
379 // reset transient_for for all transients
380 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
381 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
382 (*it
)->client
.transient_for
= (BlackboxWindow
*) 0;
392 blackbox
->removeWindowSearch(frame
.plate
);
393 XDestroyWindow(blackbox
->getXDisplay(), frame
.plate
);
397 blackbox
->removeWindowSearch(frame
.window
);
398 XDestroyWindow(blackbox
->getXDisplay(), frame
.window
);
401 blackbox
->removeWindowSearch(client
.window
);
405 void BlackboxWindow::enableDecor(bool enable
) {
406 blackbox_attrib
.flags
|= AttribDecoration
;
407 blackbox_attrib
.decoration
= enable
? DecorNormal
: DecorNone
;
410 // we can not be shaded if we lack a titlebar
411 if (! (decorations
& Decor_Titlebar
) && flags
.shaded
)
414 if (flags
.visible
&& frame
.window
) {
415 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
416 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
420 setState(current_state
);
424 void BlackboxWindow::setupDecor() {
425 if (blackbox_attrib
.decoration
!= DecorNone
) {
426 // start with everything on
427 decorations
= Decor_Close
|
428 (mwm_decorations
& Decor_Titlebar
? Decor_Titlebar
: 0) |
429 (mwm_decorations
& Decor_Border
? Decor_Border
: 0) |
430 (mwm_decorations
& Decor_Handle
? Decor_Handle
: 0) |
431 (mwm_decorations
& Decor_Iconify
? Decor_Iconify
: 0) |
432 (mwm_decorations
& Decor_Maximize
? Decor_Maximize
: 0);
434 if (! (functions
& Func_Close
)) decorations
&= ~Decor_Close
;
435 if (! (functions
& Func_Maximize
)) decorations
&= ~Decor_Maximize
;
436 if (! (functions
& Func_Iconify
)) decorations
&= ~Decor_Iconify
;
437 if (! (functions
& Func_Resize
)) decorations
&= ~Decor_Handle
;
439 switch (window_type
) {
444 // none of these windows are decorated by the window manager at all
450 decorations
&= ~(Decor_Border
);
454 decorations
&= ~Decor_Handle
;
466 * Creates a new top level window, with a given location, size, and border
468 * Returns: the newly created window
470 Window
BlackboxWindow::createToplevelWindow(void) {
471 XSetWindowAttributes attrib_create
;
472 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
| CWColormap
|
473 CWOverrideRedirect
| CWEventMask
;
475 attrib_create
.background_pixmap
= None
;
476 attrib_create
.colormap
= screen
->getColormap();
477 attrib_create
.override_redirect
= True
;
478 attrib_create
.event_mask
= EnterWindowMask
| LeaveWindowMask
;
480 return XCreateWindow(blackbox
->getXDisplay(), screen
->getRootWindow(),
481 0, 0, 1, 1, frame
.border_w
, screen
->getDepth(),
482 InputOutput
, screen
->getVisual(), create_mask
,
488 * Creates a child window, and optionally associates a given cursor with
491 Window
BlackboxWindow::createChildWindow(Window parent
,
492 unsigned long event_mask
,
494 XSetWindowAttributes attrib_create
;
495 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
|
498 attrib_create
.background_pixmap
= None
;
499 attrib_create
.event_mask
= event_mask
;
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
.color().pixel();
595 frame
.uborder_pixel
= screen
->getWindowStyle()->f_unfocus
.color().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 ButtonPressMask
| ButtonReleaseMask
|
652 ButtonMotionMask
| ExposureMask
);
653 blackbox
->saveWindowSearch(frame
.handle
, this);
656 createChildWindow(frame
.handle
,
657 ButtonPressMask
| ButtonReleaseMask
|
658 ButtonMotionMask
| ExposureMask
,
659 blackbox
->getLowerLeftAngleCursor());
660 blackbox
->saveWindowSearch(frame
.left_grip
, this);
663 createChildWindow(frame
.handle
,
664 ButtonPressMask
| ButtonReleaseMask
|
665 ButtonMotionMask
| ExposureMask
,
666 blackbox
->getLowerRightAngleCursor());
667 blackbox
->saveWindowSearch(frame
.right_grip
, this);
671 void BlackboxWindow::destroyHandle(void) {
673 screen
->getImageControl()->removeImage(frame
.fhandle
);
676 screen
->getImageControl()->removeImage(frame
.uhandle
);
679 screen
->getImageControl()->removeImage(frame
.fgrip
);
682 screen
->getImageControl()->removeImage(frame
.ugrip
);
684 blackbox
->removeWindowSearch(frame
.left_grip
);
685 blackbox
->removeWindowSearch(frame
.right_grip
);
687 XDestroyWindow(blackbox
->getXDisplay(), frame
.left_grip
);
688 XDestroyWindow(blackbox
->getXDisplay(), frame
.right_grip
);
689 frame
.left_grip
= frame
.right_grip
= None
;
691 blackbox
->removeWindowSearch(frame
.handle
);
692 XDestroyWindow(blackbox
->getXDisplay(), frame
.handle
);
697 void BlackboxWindow::createTitlebar(void) {
698 frame
.title
= createChildWindow(frame
.window
,
699 ButtonPressMask
| ButtonReleaseMask
|
700 ButtonMotionMask
| ExposureMask
);
701 frame
.label
= createChildWindow(frame
.title
,
702 ButtonPressMask
| ButtonReleaseMask
|
703 ButtonMotionMask
| ExposureMask
);
704 blackbox
->saveWindowSearch(frame
.title
, this);
705 blackbox
->saveWindowSearch(frame
.label
, this);
707 if (decorations
& Decor_Iconify
) createIconifyButton();
708 if (decorations
& Decor_Maximize
) createMaximizeButton();
709 if (decorations
& Decor_Close
) createCloseButton();
713 void BlackboxWindow::destroyTitlebar(void) {
714 if (frame
.close_button
)
715 destroyCloseButton();
717 if (frame
.iconify_button
)
718 destroyIconifyButton();
720 if (frame
.maximize_button
)
721 destroyMaximizeButton();
723 if (frame
.stick_button
)
724 destroyStickyButton();
727 screen
->getImageControl()->removeImage(frame
.ftitle
);
730 screen
->getImageControl()->removeImage(frame
.utitle
);
733 screen
->getImageControl()->removeImage(frame
.flabel
);
736 screen
->getImageControl()->removeImage(frame
.ulabel
);
739 screen
->getImageControl()->removeImage(frame
.fbutton
);
742 screen
->getImageControl()->removeImage(frame
.ubutton
);
745 screen
->getImageControl()->removeImage(frame
.pbutton
);
747 blackbox
->removeWindowSearch(frame
.title
);
748 blackbox
->removeWindowSearch(frame
.label
);
750 XDestroyWindow(blackbox
->getXDisplay(), frame
.label
);
751 XDestroyWindow(blackbox
->getXDisplay(), frame
.title
);
752 frame
.title
= frame
.label
= None
;
756 void BlackboxWindow::createCloseButton(void) {
757 if (frame
.title
!= None
) {
758 frame
.close_button
= createChildWindow(frame
.title
,
761 ButtonMotionMask
| ExposureMask
);
762 blackbox
->saveWindowSearch(frame
.close_button
, this);
767 void BlackboxWindow::destroyCloseButton(void) {
768 blackbox
->removeWindowSearch(frame
.close_button
);
769 XDestroyWindow(blackbox
->getXDisplay(), frame
.close_button
);
770 frame
.close_button
= None
;
774 void BlackboxWindow::createIconifyButton(void) {
775 if (frame
.title
!= None
) {
776 frame
.iconify_button
= createChildWindow(frame
.title
,
779 ButtonMotionMask
| ExposureMask
);
780 blackbox
->saveWindowSearch(frame
.iconify_button
, this);
785 void BlackboxWindow::destroyIconifyButton(void) {
786 blackbox
->removeWindowSearch(frame
.iconify_button
);
787 XDestroyWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
788 frame
.iconify_button
= None
;
792 void BlackboxWindow::createMaximizeButton(void) {
793 if (frame
.title
!= None
) {
794 frame
.maximize_button
= createChildWindow(frame
.title
,
797 ButtonMotionMask
| ExposureMask
);
798 blackbox
->saveWindowSearch(frame
.maximize_button
, this);
803 void BlackboxWindow::destroyMaximizeButton(void) {
804 blackbox
->removeWindowSearch(frame
.maximize_button
);
805 XDestroyWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
806 frame
.maximize_button
= None
;
809 void BlackboxWindow::createStickyButton(void) {
810 if (frame
.title
!= None
) {
811 frame
.stick_button
= createChildWindow(frame
.title
,
814 ButtonMotionMask
| ExposureMask
);
815 blackbox
->saveWindowSearch(frame
.stick_button
, this);
819 void BlackboxWindow::destroyStickyButton(void) {
820 blackbox
->removeWindowSearch(frame
.stick_button
);
821 XDestroyWindow(blackbox
->getXDisplay(), frame
.stick_button
);
822 frame
.stick_button
= None
;
825 void BlackboxWindow::positionButtons(bool redecorate_label
) {
826 string layout
= blackbox
->getTitlebarLayout();
829 bool hasclose
, hasiconify
, hasmaximize
, haslabel
, hasstick
;
830 hasclose
= hasiconify
= hasmaximize
= haslabel
= hasstick
= false;
832 string::const_iterator it
, end
;
833 for (it
= layout
.begin(), end
= layout
.end(); it
!= end
; ++it
) {
836 if (! hasclose
&& (decorations
& Decor_Close
)) {
842 if (! hasiconify
&& (decorations
& Decor_Iconify
)) {
854 if (! hasmaximize
&& (decorations
& Decor_Maximize
)) {
868 if (! hasclose
&& frame
.close_button
)
869 destroyCloseButton();
870 if (! hasiconify
&& frame
.iconify_button
)
871 destroyIconifyButton();
872 if (! hasmaximize
&& frame
.maximize_button
)
873 destroyMaximizeButton();
874 if (! hasstick
&& frame
.stick_button
)
875 destroyStickyButton();
877 parsed
+= 'L'; // require that the label be in the layout
879 const unsigned int bsep
= frame
.bevel_w
+ 1; // separation between elements
880 const unsigned int by
= frame
.bevel_w
+ 1;
881 const unsigned int ty
= frame
.bevel_w
;
883 frame
.label_w
= frame
.inside_w
- bsep
* 2 -
884 (frame
.button_w
+ bsep
) * (parsed
.size() - 1);
886 unsigned int x
= bsep
;
887 for (it
= parsed
.begin(), end
= parsed
.end(); it
!= end
; ++it
) {
890 if (! frame
.close_button
) createCloseButton();
891 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.close_button
, x
, by
,
892 frame
.button_w
, frame
.button_w
);
893 x
+= frame
.button_w
+ bsep
;
896 if (! frame
.iconify_button
) createIconifyButton();
897 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.iconify_button
, x
, by
,
898 frame
.button_w
, frame
.button_w
);
899 x
+= frame
.button_w
+ bsep
;
902 if (! frame
.stick_button
) createStickyButton();
903 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.stick_button
, x
, by
,
904 frame
.button_w
, frame
.button_w
);
905 x
+= frame
.button_w
+ bsep
;
908 if (! frame
.maximize_button
) createMaximizeButton();
909 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.maximize_button
, x
, by
,
910 frame
.button_w
, frame
.button_w
);
911 x
+= frame
.button_w
+ bsep
;
914 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.label
, x
, ty
,
915 frame
.label_w
, frame
.label_h
);
916 x
+= frame
.label_w
+ bsep
;
921 if (redecorate_label
) decorateLabel();
927 void BlackboxWindow::reconfigure(void) {
928 restoreGravity(client
.rect
);
930 applyGravity(frame
.rect
);
939 windowmenu
->move(windowmenu
->getX(), frame
.rect
.y() + frame
.title_h
);
940 windowmenu
->reconfigure();
945 void BlackboxWindow::grabButtons(void) {
946 mod_mask
= blackbox
->getMouseModMask();
948 if (! screen
->isSloppyFocus() || screen
->doClickRaise())
949 // grab button 1 for changing focus/raising
950 blackbox
->grabButton(Button1
, 0, frame
.plate
, True
, ButtonPressMask
,
951 GrabModeSync
, GrabModeSync
, frame
.plate
, None
,
952 screen
->allowScrollLock());
954 if (functions
& Func_Move
)
955 blackbox
->grabButton(Button1
, mod_mask
, frame
.window
, True
,
956 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
957 GrabModeAsync
, frame
.window
, None
,
958 screen
->allowScrollLock());
959 if (functions
& Func_Resize
)
960 blackbox
->grabButton(Button3
, mod_mask
, frame
.window
, True
,
961 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
962 GrabModeAsync
, frame
.window
, None
,
963 screen
->allowScrollLock());
964 // alt+middle lowers the window
965 blackbox
->grabButton(Button2
, mod_mask
, frame
.window
, True
,
966 ButtonReleaseMask
, GrabModeAsync
, GrabModeAsync
,
967 frame
.window
, None
, screen
->allowScrollLock());
971 void BlackboxWindow::ungrabButtons(void) {
972 blackbox
->ungrabButton(Button1
, 0, frame
.plate
);
973 blackbox
->ungrabButton(Button1
, mod_mask
, frame
.window
);
974 blackbox
->ungrabButton(Button2
, mod_mask
, frame
.window
);
975 blackbox
->ungrabButton(Button3
, mod_mask
, frame
.window
);
979 void BlackboxWindow::positionWindows(void) {
980 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.window
,
981 frame
.rect
.x(), frame
.rect
.y(), frame
.inside_w
,
982 (flags
.shaded
) ? frame
.title_h
: frame
.inside_h
);
983 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.window
,
985 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.plate
,
987 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.plate
,
988 frame
.margin
.left
- frame
.mwm_border_w
- frame
.border_w
,
989 frame
.margin
.top
- frame
.mwm_border_w
- frame
.border_w
,
990 client
.rect
.width(), client
.rect
.height());
991 XMoveResizeWindow(blackbox
->getXDisplay(), client
.window
,
992 0, 0, client
.rect
.width(), client
.rect
.height());
993 // ensure client.rect contains the real location
994 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
995 frame
.rect
.top() + frame
.margin
.top
);
997 if (decorations
& Decor_Titlebar
) {
998 if (frame
.title
== None
) createTitlebar();
1000 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.title
,
1002 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.title
, -frame
.border_w
,
1003 -frame
.border_w
, frame
.inside_w
, frame
.title_h
);
1006 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
1007 XMapWindow(blackbox
->getXDisplay(), frame
.title
);
1008 } else if (frame
.title
) {
1011 if (decorations
& Decor_Handle
) {
1012 if (frame
.handle
== None
) createHandle();
1013 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.handle
,
1015 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.left_grip
,
1017 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.right_grip
,
1020 // use client.rect here so the value is correct even if shaded
1021 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.handle
,
1023 client
.rect
.height() + frame
.margin
.top
+
1024 frame
.mwm_border_w
- frame
.border_w
,
1025 frame
.inside_w
, frame
.handle_h
);
1026 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.left_grip
,
1027 -frame
.border_w
, -frame
.border_w
,
1028 frame
.grip_w
, frame
.handle_h
);
1029 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.right_grip
,
1030 frame
.inside_w
- frame
.grip_w
- frame
.border_w
,
1031 -frame
.border_w
, frame
.grip_w
, frame
.handle_h
);
1033 XMapSubwindows(blackbox
->getXDisplay(), frame
.handle
);
1034 XMapWindow(blackbox
->getXDisplay(), frame
.handle
);
1035 } else if (frame
.handle
) {
1038 XSync(blackbox
->getXDisplay(), False
);
1042 void BlackboxWindow::updateStrut(void) {
1043 unsigned long num
= 4;
1044 unsigned long *data
;
1045 if (! xatom
->getValue(client
.window
, XAtom::net_wm_strut
, XAtom::cardinal
,
1050 client
.strut
.left
= data
[0];
1051 client
.strut
.right
= data
[1];
1052 client
.strut
.top
= data
[2];
1053 client
.strut
.bottom
= data
[3];
1055 screen
->updateAvailableArea();
1062 bool BlackboxWindow::getWindowType(void) {
1063 window_type
= (WindowType
) -1;
1066 unsigned long num
= (unsigned) -1;
1067 if (xatom
->getValue(client
.window
, XAtom::net_wm_window_type
, XAtom::atom
,
1069 for (unsigned long i
= 0; i
< num
; ++i
) {
1070 if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_desktop
))
1071 window_type
= Type_Desktop
;
1072 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_dock
))
1073 window_type
= Type_Dock
;
1074 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_toolbar
))
1075 window_type
= Type_Toolbar
;
1076 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_menu
))
1077 window_type
= Type_Menu
;
1078 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_utility
))
1079 window_type
= Type_Utility
;
1080 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_splash
))
1081 window_type
= Type_Splash
;
1082 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_dialog
))
1083 window_type
= Type_Dialog
;
1084 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_normal
))
1085 window_type
= Type_Normal
;
1087 xatom
->getAtom(XAtom::kde_net_wm_window_type_override
))
1088 mwm_decorations
= 0; // prevent this window from getting any decor
1093 if (window_type
== (WindowType
) -1) {
1095 * the window type hint was not set, which means we either classify ourself
1096 * as a normal window or a dialog, depending on if we are a transient.
1099 window_type
= Type_Dialog
;
1101 window_type
= Type_Normal
;
1110 void BlackboxWindow::getWMName(void) {
1111 if (xatom
->getValue(client
.window
, XAtom::net_wm_name
,
1112 XAtom::utf8
, client
.title
) &&
1113 !client
.title
.empty()) {
1114 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
1117 //fall through to using WM_NAME
1118 if (xatom
->getValue(client
.window
, XAtom::wm_name
, XAtom::ansi
, client
.title
)
1119 && !client
.title
.empty()) {
1120 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
1123 // fall back to an internal default
1124 client
.title
= i18n(WindowSet
, WindowUnnamed
, "Unnamed");
1125 xatom
->setValue(client
.window
, XAtom::net_wm_visible_name
, XAtom::utf8
,
1128 #define DEBUG_WITH_ID 1
1129 #ifdef DEBUG_WITH_ID
1130 // the 16 is the 8 chars of the debug text plus the number
1131 char *tmp
= new char[client
.title
.length() + 16];
1132 sprintf(tmp
, "%s; id: 0x%lx", client
.title
.c_str(), client
.window
);
1139 void BlackboxWindow::getWMIconName(void) {
1140 if (xatom
->getValue(client
.window
, XAtom::net_wm_icon_name
,
1141 XAtom::utf8
, client
.icon_title
) &&
1142 !client
.icon_title
.empty()) {
1143 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1146 //fall through to using WM_ICON_NAME
1147 if (xatom
->getValue(client
.window
, XAtom::wm_icon_name
, XAtom::ansi
,
1148 client
.icon_title
) &&
1149 !client
.icon_title
.empty()) {
1150 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1153 // fall back to using the main name
1154 client
.icon_title
= client
.title
;
1155 xatom
->setValue(client
.window
, XAtom::net_wm_visible_icon_name
, XAtom::utf8
,
1161 * Retrieve which WM Protocols are supported by the client window.
1162 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
1163 * window's decorations and allow the close behavior.
1164 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
1167 void BlackboxWindow::getWMProtocols(void) {
1171 if (XGetWMProtocols(blackbox
->getXDisplay(), client
.window
,
1172 &proto
, &num_return
)) {
1173 for (int i
= 0; i
< num_return
; ++i
) {
1174 if (proto
[i
] == xatom
->getAtom(XAtom::wm_delete_window
)) {
1175 decorations
|= Decor_Close
;
1176 functions
|= Func_Close
;
1177 } else if (proto
[i
] == xatom
->getAtom(XAtom::wm_take_focus
))
1178 flags
.send_focus_message
= True
;
1179 else if (proto
[i
] == xatom
->getAtom(XAtom::blackbox_structure_messages
))
1180 screen
->addNetizen(new Netizen(screen
, client
.window
));
1189 * Gets the value of the WM_HINTS property.
1190 * If the property is not set, then use a set of default values.
1192 void BlackboxWindow::getWMHints(void) {
1193 focus_mode
= F_Passive
;
1195 // remove from current window group
1196 if (client
.window_group
) {
1197 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1198 if (group
) group
->removeWindow(this);
1200 client
.window_group
= None
;
1202 XWMHints
*wmhint
= XGetWMHints(blackbox
->getXDisplay(), client
.window
);
1207 if (wmhint
->flags
& InputHint
) {
1208 if (wmhint
->input
== True
) {
1209 if (flags
.send_focus_message
)
1210 focus_mode
= F_LocallyActive
;
1212 if (flags
.send_focus_message
)
1213 focus_mode
= F_GloballyActive
;
1215 focus_mode
= F_NoInput
;
1219 if (wmhint
->flags
& StateHint
)
1220 current_state
= wmhint
->initial_state
;
1222 if (wmhint
->flags
& WindowGroupHint
) {
1223 client
.window_group
= wmhint
->window_group
;
1225 // add window to the appropriate group
1226 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1227 if (! group
) { // no group found, create it!
1228 new BWindowGroup(blackbox
, client
.window_group
);
1229 group
= blackbox
->searchGroup(client
.window_group
);
1232 group
->addWindow(this);
1240 * Gets the value of the WM_NORMAL_HINTS property.
1241 * If the property is not set, then use a set of default values.
1243 void BlackboxWindow::getWMNormalHints(void) {
1245 XSizeHints sizehint
;
1247 client
.min_width
= client
.min_height
=
1248 client
.width_inc
= client
.height_inc
= 1;
1249 client
.base_width
= client
.base_height
= 0;
1250 client
.win_gravity
= NorthWestGravity
;
1252 client
.min_aspect_x
= client
.min_aspect_y
=
1253 client
.max_aspect_x
= client
.max_aspect_y
= 1;
1256 // don't limit the size of a window, the default max width is the biggest
1258 client
.max_width
= (unsigned) -1;
1259 client
.max_height
= (unsigned) -1;
1262 if (! XGetWMNormalHints(blackbox
->getXDisplay(), client
.window
,
1263 &sizehint
, &icccm_mask
))
1266 client
.normal_hint_flags
= sizehint
.flags
;
1268 if (sizehint
.flags
& PMinSize
) {
1269 if (sizehint
.min_width
>= 0)
1270 client
.min_width
= sizehint
.min_width
;
1271 if (sizehint
.min_height
>= 0)
1272 client
.min_height
= sizehint
.min_height
;
1275 if (sizehint
.flags
& PMaxSize
) {
1276 if (sizehint
.max_width
> static_cast<signed>(client
.min_width
))
1277 client
.max_width
= sizehint
.max_width
;
1279 client
.max_width
= client
.min_width
;
1281 if (sizehint
.max_height
> static_cast<signed>(client
.min_height
))
1282 client
.max_height
= sizehint
.max_height
;
1284 client
.max_height
= client
.min_height
;
1287 if (sizehint
.flags
& PResizeInc
) {
1288 client
.width_inc
= sizehint
.width_inc
;
1289 client
.height_inc
= sizehint
.height_inc
;
1292 #if 0 // we do not support this at the moment
1293 if (sizehint
.flags
& PAspect
) {
1294 client
.min_aspect_x
= sizehint
.min_aspect
.x
;
1295 client
.min_aspect_y
= sizehint
.min_aspect
.y
;
1296 client
.max_aspect_x
= sizehint
.max_aspect
.x
;
1297 client
.max_aspect_y
= sizehint
.max_aspect
.y
;
1301 if (sizehint
.flags
& PBaseSize
) {
1302 client
.base_width
= sizehint
.base_width
;
1303 client
.base_height
= sizehint
.base_height
;
1306 if (sizehint
.flags
& PWinGravity
)
1307 client
.win_gravity
= sizehint
.win_gravity
;
1312 * Gets the NETWM hints for the class' contained window.
1314 void BlackboxWindow::getNetWMHints(void) {
1315 unsigned long workspace
;
1317 if (xatom
->getValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1319 if (workspace
== 0xffffffff)
1322 blackbox_attrib
.workspace
= workspace
;
1325 unsigned long *state
;
1326 unsigned long num
= (unsigned) -1;
1327 if (xatom
->getValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
1331 for (unsigned long i
= 0; i
< num
; ++i
) {
1332 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
))
1334 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_shaded
))
1335 flags
.shaded
= True
;
1336 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
))
1337 flags
.skip_taskbar
= True
;
1338 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_pager
))
1339 flags
.skip_pager
= True
;
1340 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_fullscreen
))
1341 flags
.fullscreen
= True
;
1342 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_hidden
))
1343 setState(IconicState
);
1344 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_vert
))
1346 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_horz
))
1350 flags
.maximized
= 1;
1352 flags
.maximized
= 2;
1354 flags
.maximized
= 3;
1362 * Gets the MWM hints for the class' contained window.
1363 * This is used while initializing the window to its first state, and not
1365 * Returns: true if the MWM hints are successfully retreived and applied;
1366 * false if they are not.
1368 void BlackboxWindow::getMWMHints(void) {
1372 num
= PropMwmHintsElements
;
1373 if (! xatom
->getValue(client
.window
, XAtom::motif_wm_hints
,
1374 XAtom::motif_wm_hints
, num
,
1375 (unsigned long **)&mwm_hint
))
1377 if (num
< PropMwmHintsElements
) {
1382 if (mwm_hint
->flags
& MwmHintsDecorations
) {
1383 if (mwm_hint
->decorations
& MwmDecorAll
) {
1384 mwm_decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
1385 Decor_Iconify
| Decor_Maximize
;
1387 mwm_decorations
= 0;
1389 if (mwm_hint
->decorations
& MwmDecorBorder
)
1390 mwm_decorations
|= Decor_Border
;
1391 if (mwm_hint
->decorations
& MwmDecorHandle
)
1392 mwm_decorations
|= Decor_Handle
;
1393 if (mwm_hint
->decorations
& MwmDecorTitle
)
1394 mwm_decorations
|= Decor_Titlebar
;
1395 if (mwm_hint
->decorations
& MwmDecorIconify
)
1396 mwm_decorations
|= Decor_Iconify
;
1397 if (mwm_hint
->decorations
& MwmDecorMaximize
)
1398 mwm_decorations
|= Decor_Maximize
;
1402 if (mwm_hint
->flags
& MwmHintsFunctions
) {
1403 if (mwm_hint
->functions
& MwmFuncAll
) {
1404 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
|
1409 if (mwm_hint
->functions
& MwmFuncResize
)
1410 functions
|= Func_Resize
;
1411 if (mwm_hint
->functions
& MwmFuncMove
)
1412 functions
|= Func_Move
;
1413 if (mwm_hint
->functions
& MwmFuncIconify
)
1414 functions
|= Func_Iconify
;
1415 if (mwm_hint
->functions
& MwmFuncMaximize
)
1416 functions
|= Func_Maximize
;
1417 if (mwm_hint
->functions
& MwmFuncClose
)
1418 functions
|= Func_Close
;
1426 * Gets the blackbox hints from the class' contained window.
1427 * This is used while initializing the window to its first state, and not
1429 * Returns: true if the hints are successfully retreived and applied; false if
1432 bool BlackboxWindow::getBlackboxHints(void) {
1434 BlackboxHints
*blackbox_hint
;
1436 num
= PropBlackboxHintsElements
;
1437 if (! xatom
->getValue(client
.window
, XAtom::blackbox_hints
,
1438 XAtom::blackbox_hints
, num
,
1439 (unsigned long **)&blackbox_hint
))
1441 if (num
< PropBlackboxHintsElements
) {
1442 delete [] blackbox_hint
;
1446 if (blackbox_hint
->flags
& AttribShaded
)
1447 flags
.shaded
= (blackbox_hint
->attrib
& AttribShaded
);
1449 if ((blackbox_hint
->flags
& AttribMaxHoriz
) &&
1450 (blackbox_hint
->flags
& AttribMaxVert
))
1451 flags
.maximized
= (blackbox_hint
->attrib
&
1452 (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1453 else if (blackbox_hint
->flags
& AttribMaxVert
)
1454 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxVert
) ? 2 : 0;
1455 else if (blackbox_hint
->flags
& AttribMaxHoriz
)
1456 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1458 if (blackbox_hint
->flags
& AttribOmnipresent
)
1459 flags
.stuck
= (blackbox_hint
->attrib
& AttribOmnipresent
);
1461 if (blackbox_hint
->flags
& AttribWorkspace
)
1462 blackbox_attrib
.workspace
= blackbox_hint
->workspace
;
1464 // if (blackbox_hint->flags & AttribStack)
1465 // don't yet have always on top/bottom for blackbox yet... working
1468 if (blackbox_hint
->flags
& AttribDecoration
) {
1469 switch (blackbox_hint
->decoration
) {
1471 blackbox_attrib
.decoration
= DecorNone
;
1478 // blackbox_attrib.decoration defaults to DecorNormal
1483 delete [] blackbox_hint
;
1489 void BlackboxWindow::getTransientInfo(void) {
1490 if (client
.transient_for
&&
1491 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1492 // reset transient_for in preparation of looking for a new owner
1493 client
.transient_for
->client
.transientList
.remove(this);
1496 // we have no transient_for until we find a new one
1497 client
.transient_for
= (BlackboxWindow
*) 0;
1500 if (! XGetTransientForHint(blackbox
->getXDisplay(), client
.window
,
1502 // transient_for hint not set
1506 if (trans_for
== client
.window
) {
1507 // wierd client... treat this window as a normal window
1511 if (trans_for
== None
|| trans_for
== screen
->getRootWindow()) {
1512 // this is an undocumented interpretation of the ICCCM. a transient
1513 // associated with None/Root/itself is assumed to be a modal root
1514 // transient. we don't support the concept of a global transient,
1515 // so we just associate this transient with nothing, and perhaps
1516 // we will add support later for global modality.
1517 client
.transient_for
= (BlackboxWindow
*) ~0ul;
1522 client
.transient_for
= blackbox
->searchWindow(trans_for
);
1523 if (! client
.transient_for
&&
1524 client
.window_group
&& trans_for
== client
.window_group
) {
1525 // no direct transient_for, perhaps this is a group transient?
1526 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1527 if (group
) client
.transient_for
= group
->find(screen
);
1530 if (! client
.transient_for
|| client
.transient_for
== this) {
1531 // no transient_for found, or we have a wierd client that wants to be
1532 // a transient for itself, so we treat this window as a normal window
1533 client
.transient_for
= (BlackboxWindow
*) 0;
1537 // Check for a circular transient state: this can lock up Blackbox
1538 // when it tries to find the non-transient window for a transient.
1539 BlackboxWindow
*w
= this;
1540 while(w
->client
.transient_for
&&
1541 w
->client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1542 if(w
->client
.transient_for
== this) {
1543 client
.transient_for
= (BlackboxWindow
*) 0;
1546 w
= w
->client
.transient_for
;
1549 if (client
.transient_for
&&
1550 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1551 // register ourselves with our new transient_for
1552 client
.transient_for
->client
.transientList
.push_back(this);
1553 flags
.stuck
= client
.transient_for
->flags
.stuck
;
1558 BlackboxWindow
*BlackboxWindow::getTransientFor(void) const {
1559 if (client
.transient_for
&&
1560 client
.transient_for
!= (BlackboxWindow
*) ~0ul)
1561 return client
.transient_for
;
1567 * This function is responsible for updating both the client and the frame
1569 * According to the ICCCM a client message is not sent for a resize, only a
1572 void BlackboxWindow::configure(int dx
, int dy
,
1573 unsigned int dw
, unsigned int dh
) {
1574 bool send_event
= ((frame
.rect
.x() != dx
|| frame
.rect
.y() != dy
) &&
1577 if (dw
!= frame
.rect
.width() || dh
!= frame
.rect
.height()) {
1578 frame
.rect
.setRect(dx
, dy
, dw
, dh
);
1579 frame
.inside_w
= frame
.rect
.width() - (frame
.border_w
* 2);
1580 frame
.inside_h
= frame
.rect
.height() - (frame
.border_w
* 2);
1582 if (frame
.rect
.right() <= 0 || frame
.rect
.bottom() <= 0)
1583 frame
.rect
.setPos(0, 0);
1585 client
.rect
.setCoords(frame
.rect
.left() + frame
.margin
.left
,
1586 frame
.rect
.top() + frame
.margin
.top
,
1587 frame
.rect
.right() - frame
.margin
.right
,
1588 frame
.rect
.bottom() - frame
.margin
.bottom
);
1591 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
1598 redrawWindowFrame();
1600 frame
.rect
.setPos(dx
, dy
);
1602 XMoveWindow(blackbox
->getXDisplay(), frame
.window
,
1603 frame
.rect
.x(), frame
.rect
.y());
1605 we may have been called just after an opaque window move, so even though
1606 the old coords match the new ones no ConfigureNotify has been sent yet.
1607 There are likely other times when this will be relevant as well.
1609 if (! flags
.moving
) send_event
= True
;
1613 // if moving, the update and event will occur when the move finishes
1614 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1615 frame
.rect
.top() + frame
.margin
.top
);
1618 event
.type
= ConfigureNotify
;
1620 event
.xconfigure
.display
= blackbox
->getXDisplay();
1621 event
.xconfigure
.event
= client
.window
;
1622 event
.xconfigure
.window
= client
.window
;
1623 event
.xconfigure
.x
= client
.rect
.x();
1624 event
.xconfigure
.y
= client
.rect
.y();
1625 event
.xconfigure
.width
= client
.rect
.width();
1626 event
.xconfigure
.height
= client
.rect
.height();
1627 event
.xconfigure
.border_width
= client
.old_bw
;
1628 event
.xconfigure
.above
= frame
.window
;
1629 event
.xconfigure
.override_redirect
= False
;
1631 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1632 StructureNotifyMask
, &event
);
1633 screen
->updateNetizenConfigNotify(&event
);
1634 XFlush(blackbox
->getXDisplay());
1640 void BlackboxWindow::configureShape(void) {
1641 XShapeCombineShape(blackbox
->getXDisplay(), frame
.window
, ShapeBounding
,
1642 frame
.margin
.left
- frame
.border_w
,
1643 frame
.margin
.top
- frame
.border_w
,
1644 client
.window
, ShapeBounding
, ShapeSet
);
1647 XRectangle xrect
[2];
1649 if (decorations
& Decor_Titlebar
) {
1650 xrect
[0].x
= xrect
[0].y
= -frame
.border_w
;
1651 xrect
[0].width
= frame
.rect
.width();
1652 xrect
[0].height
= frame
.title_h
+ (frame
.border_w
* 2);
1656 if (decorations
& Decor_Handle
) {
1657 xrect
[1].x
= -frame
.border_w
;
1658 xrect
[1].y
= frame
.rect
.height() - frame
.margin
.bottom
+
1659 frame
.mwm_border_w
- frame
.border_w
;
1660 xrect
[1].width
= frame
.rect
.width();
1661 xrect
[1].height
= frame
.handle_h
+ (frame
.border_w
* 2);
1665 XShapeCombineRectangles(blackbox
->getXDisplay(), frame
.window
,
1666 ShapeBounding
, 0, 0, xrect
, num
,
1667 ShapeUnion
, Unsorted
);
1671 void BlackboxWindow::clearShape(void) {
1672 XShapeCombineMask(blackbox
->getXDisplay(), frame
.window
, ShapeBounding
,
1673 frame
.margin
.left
- frame
.border_w
,
1674 frame
.margin
.top
- frame
.border_w
,
1680 bool BlackboxWindow::setInputFocus(void) {
1681 if (flags
.focused
) return True
;
1683 assert(flags
.stuck
|| // window must be on the current workspace or sticky
1684 blackbox_attrib
.workspace
== screen
->getCurrentWorkspaceID());
1687 We only do this check for normal windows and dialogs because other windows
1688 do this on purpose, such as kde's kicker, and we don't want to go moving
1691 if (window_type
== Type_Normal
|| window_type
== Type_Dialog
)
1692 if (! frame
.rect
.intersects(screen
->getRect())) {
1693 // client is outside the screen, move it to the center
1694 configure((screen
->getWidth() - frame
.rect
.width()) / 2,
1695 (screen
->getHeight() - frame
.rect
.height()) / 2,
1696 frame
.rect
.width(), frame
.rect
.height());
1699 if (client
.transientList
.size() > 0) {
1700 // transfer focus to any modal transients
1701 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1702 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1703 if ((*it
)->flags
.modal
) return (*it
)->setInputFocus();
1707 if (focus_mode
== F_LocallyActive
|| focus_mode
== F_Passive
) {
1708 XSetInputFocus(blackbox
->getXDisplay(), client
.window
,
1709 RevertToPointerRoot
, CurrentTime
);
1711 /* we could set the focus to none, since the window doesn't accept focus,
1712 * but we shouldn't set focus to nothing since this would surely make
1718 if (flags
.send_focus_message
) {
1720 ce
.xclient
.type
= ClientMessage
;
1721 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1722 ce
.xclient
.display
= blackbox
->getXDisplay();
1723 ce
.xclient
.window
= client
.window
;
1724 ce
.xclient
.format
= 32;
1725 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_take_focus
);
1726 ce
.xclient
.data
.l
[1] = blackbox
->getLastTime();
1727 ce
.xclient
.data
.l
[2] = 0l;
1728 ce
.xclient
.data
.l
[3] = 0l;
1729 ce
.xclient
.data
.l
[4] = 0l;
1730 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1732 XFlush(blackbox
->getXDisplay());
1739 void BlackboxWindow::iconify(void) {
1740 if (flags
.iconic
|| ! (functions
& Func_Iconify
)) return;
1742 // We don't need to worry about resizing because resizing always grabs the X
1743 // server. This should only ever happen if using opaque moving.
1747 if (windowmenu
) windowmenu
->hide();
1750 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1751 * we need to clear the event mask on client.window for a split second.
1752 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1753 * split second, leaving us with a ghost window... so, we need to do this
1754 * while the X server is grabbed
1756 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1757 StructureNotifyMask
;
1758 XGrabServer(blackbox
->getXDisplay());
1759 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1760 event_mask
& ~StructureNotifyMask
);
1761 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1762 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1763 XUngrabServer(blackbox
->getXDisplay());
1765 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1766 flags
.visible
= False
;
1767 flags
.iconic
= True
;
1769 setState(IconicState
);
1771 screen
->getWorkspace(blackbox_attrib
.workspace
)->removeWindow(this);
1773 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
1774 if (i
!= blackbox_attrib
.workspace
)
1775 screen
->getWorkspace(i
)->removeWindow(this, True
);
1778 if (isTransient()) {
1779 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1780 ! client
.transient_for
->flags
.iconic
) {
1781 // iconify our transient_for
1782 client
.transient_for
->iconify();
1786 screen
->addIcon(this);
1788 if (client
.transientList
.size() > 0) {
1789 // iconify all transients
1790 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1791 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1792 if (! (*it
)->flags
.iconic
) (*it
)->iconify();
1795 screen
->updateStackingList();
1799 void BlackboxWindow::show(void) {
1800 flags
.visible
= True
;
1801 flags
.iconic
= False
;
1803 current_state
= (flags
.shaded
) ? IconicState
: NormalState
;
1804 setState(current_state
);
1806 XMapWindow(blackbox
->getXDisplay(), client
.window
);
1807 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
1808 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
1813 XTranslateCoordinates(blackbox
->getXDisplay(), client
.window
,
1814 screen
->getRootWindow(),
1815 0, 0, &real_x
, &real_y
, &child
);
1816 fprintf(stderr
, "%s -- assumed: (%d, %d), real: (%d, %d)\n", getTitle(),
1817 client
.rect
.left(), client
.rect
.top(), real_x
, real_y
);
1818 assert(client
.rect
.left() == real_x
&& client
.rect
.top() == real_y
);
1823 void BlackboxWindow::deiconify(bool reassoc
, bool raise
) {
1824 if (flags
.iconic
|| reassoc
)
1825 screen
->reassociateWindow(this, BSENTINEL
, False
);
1826 else if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID())
1831 // reassociate and deiconify all transients
1832 if (reassoc
&& client
.transientList
.size() > 0) {
1833 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1834 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1835 (*it
)->deiconify(True
, False
);
1839 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1843 void BlackboxWindow::close(void) {
1844 if (! (functions
& Func_Close
)) return;
1847 ce
.xclient
.type
= ClientMessage
;
1848 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1849 ce
.xclient
.display
= blackbox
->getXDisplay();
1850 ce
.xclient
.window
= client
.window
;
1851 ce
.xclient
.format
= 32;
1852 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_delete_window
);
1853 ce
.xclient
.data
.l
[1] = CurrentTime
;
1854 ce
.xclient
.data
.l
[2] = 0l;
1855 ce
.xclient
.data
.l
[3] = 0l;
1856 ce
.xclient
.data
.l
[4] = 0l;
1857 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
, NoEventMask
, &ce
);
1858 XFlush(blackbox
->getXDisplay());
1862 void BlackboxWindow::withdraw(void) {
1863 // We don't need to worry about resizing because resizing always grabs the X
1864 // server. This should only ever happen if using opaque moving.
1868 flags
.visible
= False
;
1869 flags
.iconic
= False
;
1871 setState(current_state
);
1873 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1875 XGrabServer(blackbox
->getXDisplay());
1877 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1878 StructureNotifyMask
;
1879 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1880 event_mask
& ~StructureNotifyMask
);
1881 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1882 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1884 XUngrabServer(blackbox
->getXDisplay());
1886 if (windowmenu
) windowmenu
->hide();
1890 void BlackboxWindow::maximize(unsigned int button
) {
1891 if (! (functions
& Func_Maximize
)) return;
1893 // We don't need to worry about resizing because resizing always grabs the X
1894 // server. This should only ever happen if using opaque moving.
1898 // handle case where menu is open then the max button is used instead
1899 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
1901 if (flags
.maximized
) {
1902 flags
.maximized
= 0;
1904 blackbox_attrib
.flags
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1905 blackbox_attrib
.attrib
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1908 when a resize finishes, maximize(0) is called to clear any maximization
1909 flags currently set. Otherwise it still thinks it is maximized.
1910 so we do not need to call configure() because resizing will handle it
1912 if (! flags
.resizing
)
1913 configure(blackbox_attrib
.premax_x
, blackbox_attrib
.premax_y
,
1914 blackbox_attrib
.premax_w
, blackbox_attrib
.premax_h
);
1916 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
1917 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
1919 redrawAllButtons(); // in case it is not called in configure()
1920 setState(current_state
);
1924 blackbox_attrib
.premax_x
= frame
.rect
.x();
1925 blackbox_attrib
.premax_y
= frame
.rect
.y();
1926 blackbox_attrib
.premax_w
= frame
.rect
.width();
1927 // use client.rect so that clients can be restored even if shaded
1928 blackbox_attrib
.premax_h
=
1929 client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
;
1932 if (screen
->isXineramaActive() && blackbox
->doXineramaMaximizing()) {
1933 // find the area to use
1934 RectList availableAreas
= screen
->allAvailableAreas();
1935 RectList::iterator it
, end
= availableAreas
.end();
1937 for (it
= availableAreas
.begin(); it
!= end
; ++it
)
1938 if (it
->intersects(frame
.rect
)) break;
1939 if (it
== end
) // the window isn't inside an area
1940 it
= availableAreas
.begin(); // so just default to the first one
1942 frame
.changing
= *it
;
1945 frame
.changing
= screen
->availableArea();
1949 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1950 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1954 blackbox_attrib
.flags
|= AttribMaxVert
;
1955 blackbox_attrib
.attrib
|= AttribMaxVert
;
1957 frame
.changing
.setX(frame
.rect
.x());
1958 frame
.changing
.setWidth(frame
.rect
.width());
1962 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1963 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1965 frame
.changing
.setY(frame
.rect
.y());
1966 frame
.changing
.setHeight(frame
.rect
.height());
1973 blackbox_attrib
.flags
^= AttribShaded
;
1974 blackbox_attrib
.attrib
^= AttribShaded
;
1975 flags
.shaded
= False
;
1978 flags
.maximized
= button
;
1980 configure(frame
.changing
.x(), frame
.changing
.y(),
1981 frame
.changing
.width(), frame
.changing
.height());
1983 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1984 redrawAllButtons(); // in case it is not called in configure()
1985 setState(current_state
);
1989 // re-maximizes the window to take into account availableArea changes
1990 void BlackboxWindow::remaximize(void) {
1992 // we only update the window's attributes otherwise we lose the shade bit
1993 switch(flags
.maximized
) {
1995 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1996 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
2000 blackbox_attrib
.flags
|= AttribMaxVert
;
2001 blackbox_attrib
.attrib
|= AttribMaxVert
;
2005 blackbox_attrib
.flags
|= AttribMaxHoriz
;
2006 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
2012 // save the original dimensions because maximize will wipe them out
2013 int premax_x
= blackbox_attrib
.premax_x
,
2014 premax_y
= blackbox_attrib
.premax_y
,
2015 premax_w
= blackbox_attrib
.premax_w
,
2016 premax_h
= blackbox_attrib
.premax_h
;
2018 unsigned int button
= flags
.maximized
;
2019 flags
.maximized
= 0; // trick maximize() into working
2022 // restore saved values
2023 blackbox_attrib
.premax_x
= premax_x
;
2024 blackbox_attrib
.premax_y
= premax_y
;
2025 blackbox_attrib
.premax_w
= premax_w
;
2026 blackbox_attrib
.premax_h
= premax_h
;
2030 void BlackboxWindow::setWorkspace(unsigned int n
) {
2031 blackbox_attrib
.flags
|= AttribWorkspace
;
2032 blackbox_attrib
.workspace
= n
;
2033 if (n
== BSENTINEL
) { // iconified window
2035 we set the workspace to 'all workspaces' so that taskbars will show the
2036 window. otherwise, it made uniconifying a window imposible without the
2037 blackbox workspace menu
2041 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
, n
);
2045 void BlackboxWindow::shade(void) {
2047 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
2048 frame
.inside_w
, frame
.inside_h
);
2049 flags
.shaded
= False
;
2050 blackbox_attrib
.flags
^= AttribShaded
;
2051 blackbox_attrib
.attrib
^= AttribShaded
;
2053 setState(NormalState
);
2055 // set the frame rect to the normal size
2056 frame
.rect
.setHeight(client
.rect
.height() + frame
.margin
.top
+
2057 frame
.margin
.bottom
);
2059 if (! (decorations
& Decor_Titlebar
))
2060 return; // can't shade it without a titlebar!
2062 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
2063 frame
.inside_w
, frame
.title_h
);
2064 flags
.shaded
= True
;
2065 blackbox_attrib
.flags
|= AttribShaded
;
2066 blackbox_attrib
.attrib
|= AttribShaded
;
2068 setState(IconicState
);
2070 // set the frame rect to the shaded size
2071 frame
.rect
.setHeight(frame
.title_h
+ (frame
.border_w
* 2));
2077 * (Un)Sticks a window and its relatives.
2079 void BlackboxWindow::stick(void) {
2081 blackbox_attrib
.flags
^= AttribOmnipresent
;
2082 blackbox_attrib
.attrib
^= AttribOmnipresent
;
2084 flags
.stuck
= False
;
2086 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
2087 if (i
!= blackbox_attrib
.workspace
)
2088 screen
->getWorkspace(i
)->removeWindow(this, True
);
2091 screen
->reassociateWindow(this, BSENTINEL
, True
);
2092 // temporary fix since sticky windows suck. set the hint to what we
2093 // actually hold in our data.
2094 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
2095 blackbox_attrib
.workspace
);
2097 setState(current_state
);
2101 blackbox_attrib
.flags
|= AttribOmnipresent
;
2102 blackbox_attrib
.attrib
|= AttribOmnipresent
;
2104 // temporary fix since sticky windows suck. set the hint to a different
2105 // value than that contained in the class' data.
2106 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
2109 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
2110 if (i
!= blackbox_attrib
.workspace
)
2111 screen
->getWorkspace(i
)->addWindow(this, False
, True
);
2113 setState(current_state
);
2119 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
2120 client
.transient_for
->isStuck() != flags
.stuck
)
2121 client
.transient_for
->stick();
2122 // go down the chain
2123 BlackboxWindowList::iterator it
;
2124 const BlackboxWindowList::iterator end
= client
.transientList
.end();
2125 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
2126 if ((*it
)->isStuck() != flags
.stuck
)
2131 void BlackboxWindow::redrawWindowFrame(void) const {
2132 if (decorations
& Decor_Titlebar
) {
2133 if (flags
.focused
) {
2135 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2136 frame
.title
, frame
.ftitle
);
2138 XSetWindowBackground(blackbox
->getXDisplay(),
2139 frame
.title
, frame
.ftitle_pixel
);
2142 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2143 frame
.title
, frame
.utitle
);
2145 XSetWindowBackground(blackbox
->getXDisplay(),
2146 frame
.title
, frame
.utitle_pixel
);
2148 XClearWindow(blackbox
->getXDisplay(), frame
.title
);
2154 if (decorations
& Decor_Handle
) {
2155 if (flags
.focused
) {
2157 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2158 frame
.handle
, frame
.fhandle
);
2160 XSetWindowBackground(blackbox
->getXDisplay(),
2161 frame
.handle
, frame
.fhandle_pixel
);
2164 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2165 frame
.left_grip
, frame
.fgrip
);
2166 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2167 frame
.right_grip
, frame
.fgrip
);
2169 XSetWindowBackground(blackbox
->getXDisplay(),
2170 frame
.left_grip
, frame
.fgrip_pixel
);
2171 XSetWindowBackground(blackbox
->getXDisplay(),
2172 frame
.right_grip
, frame
.fgrip_pixel
);
2176 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2177 frame
.handle
, frame
.uhandle
);
2179 XSetWindowBackground(blackbox
->getXDisplay(),
2180 frame
.handle
, frame
.uhandle_pixel
);
2183 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2184 frame
.left_grip
, frame
.ugrip
);
2185 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2186 frame
.right_grip
, frame
.ugrip
);
2188 XSetWindowBackground(blackbox
->getXDisplay(),
2189 frame
.left_grip
, frame
.ugrip_pixel
);
2190 XSetWindowBackground(blackbox
->getXDisplay(),
2191 frame
.right_grip
, frame
.ugrip_pixel
);
2194 XClearWindow(blackbox
->getXDisplay(), frame
.handle
);
2195 XClearWindow(blackbox
->getXDisplay(), frame
.left_grip
);
2196 XClearWindow(blackbox
->getXDisplay(), frame
.right_grip
);
2199 if (decorations
& Decor_Border
) {
2201 XSetWindowBorder(blackbox
->getXDisplay(),
2202 frame
.plate
, frame
.fborder_pixel
);
2204 XSetWindowBorder(blackbox
->getXDisplay(),
2205 frame
.plate
, frame
.uborder_pixel
);
2210 void BlackboxWindow::setFocusFlag(bool focus
) {
2211 // only focus a window if it is visible
2212 if (focus
&& ! flags
.visible
)
2215 flags
.focused
= focus
;
2217 redrawWindowFrame();
2220 blackbox
->setFocusedWindow(this);
2222 if (! flags
.iconic
) {
2223 // iconic windows arent in a workspace menu!
2225 screen
->getCurrentWorkspace()->setFocused(this, isFocused());
2227 screen
->getWorkspace(blackbox_attrib
.workspace
)->
2228 setFocused(this, flags
.focused
);
2233 void BlackboxWindow::installColormap(bool install
) {
2234 int i
= 0, ncmap
= 0;
2235 Colormap
*cmaps
= XListInstalledColormaps(blackbox
->getXDisplay(),
2236 client
.window
, &ncmap
);
2238 XWindowAttributes wattrib
;
2239 if (XGetWindowAttributes(blackbox
->getXDisplay(),
2240 client
.window
, &wattrib
)) {
2242 // install the window's colormap
2243 for (i
= 0; i
< ncmap
; i
++) {
2244 if (*(cmaps
+ i
) == wattrib
.colormap
)
2245 // this window is using an installed color map... do not install
2248 // otherwise, install the window's colormap
2250 XInstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2252 // uninstall the window's colormap
2253 for (i
= 0; i
< ncmap
; i
++) {
2254 if (*(cmaps
+ i
) == wattrib
.colormap
)
2255 // we found the colormap to uninstall
2256 XUninstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2266 void BlackboxWindow::setAllowedActions(void) {
2270 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_shade
);
2271 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_change_desktop
);
2272 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_close
);
2274 if (functions
& Func_Move
)
2275 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_move
);
2276 if (functions
& Func_Resize
)
2277 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_resize
);
2278 if (functions
& Func_Maximize
) {
2279 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_horz
);
2280 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_vert
);
2283 xatom
->setValue(client
.window
, XAtom::net_wm_allowed_actions
, XAtom::atom
,
2288 void BlackboxWindow::setState(unsigned long new_state
) {
2289 current_state
= new_state
;
2291 unsigned long state
[2];
2292 state
[0] = current_state
;
2294 xatom
->setValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
, state
, 2);
2296 xatom
->setValue(client
.window
, XAtom::blackbox_attributes
,
2297 XAtom::blackbox_attributes
, (unsigned long *)&blackbox_attrib
,
2298 PropBlackboxAttributesElements
);
2303 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_modal
);
2305 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_shaded
);
2307 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_hidden
);
2308 if (flags
.skip_taskbar
)
2309 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
);
2310 if (flags
.skip_pager
)
2311 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_pager
);
2312 if (flags
.fullscreen
)
2313 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_fullscreen
);
2314 if (flags
.maximized
== 1 || flags
.maximized
== 2)
2315 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_vert
);
2316 if (flags
.maximized
== 1 || flags
.maximized
== 3)
2317 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_horz
);
2318 xatom
->setValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
2323 bool BlackboxWindow::getState(void) {
2324 bool ret
= xatom
->getValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
,
2326 if (! ret
) current_state
= 0;
2331 void BlackboxWindow::restoreAttributes(void) {
2332 unsigned long num
= PropBlackboxAttributesElements
;
2333 BlackboxAttributes
*net
;
2334 if (! xatom
->getValue(client
.window
, XAtom::blackbox_attributes
,
2335 XAtom::blackbox_attributes
, num
,
2336 (unsigned long **)&net
))
2338 if (num
< PropBlackboxAttributesElements
) {
2343 if (net
->flags
& AttribShaded
&& net
->attrib
& AttribShaded
) {
2344 flags
.shaded
= False
;
2345 unsigned long orig_state
= current_state
;
2349 At this point in the life of a window, current_state should only be set
2350 to IconicState if the window was an *icon*, not if it was shaded.
2352 if (orig_state
!= IconicState
)
2353 current_state
= WithdrawnState
;
2356 if (net
->workspace
!= screen
->getCurrentWorkspaceID() &&
2357 net
->workspace
< screen
->getWorkspaceCount())
2358 screen
->reassociateWindow(this, net
->workspace
, True
);
2360 if ((blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID()) &&
2361 (blackbox_attrib
.workspace
< screen
->getWorkspaceCount())) {
2362 // set to WithdrawnState so it will be mapped on the new workspace
2363 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2364 } else if (current_state
== WithdrawnState
) {
2365 // the window is on this workspace and is Withdrawn, so it is waiting to
2367 current_state
= NormalState
;
2370 if (net
->flags
& AttribOmnipresent
&& net
->attrib
& AttribOmnipresent
&&
2374 // if the window was on another workspace, it was going to be hidden. this
2375 // specifies that the window should be mapped since it is sticky.
2376 if (current_state
== WithdrawnState
) current_state
= NormalState
;
2379 if (net
->flags
& AttribMaxHoriz
|| net
->flags
& AttribMaxVert
) {
2380 int x
= net
->premax_x
, y
= net
->premax_y
;
2381 unsigned int w
= net
->premax_w
, h
= net
->premax_h
;
2382 flags
.maximized
= 0;
2385 if ((net
->flags
& AttribMaxHoriz
) &&
2386 (net
->flags
& AttribMaxVert
))
2387 m
= (net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
2388 else if (net
->flags
& AttribMaxVert
)
2389 m
= (net
->attrib
& AttribMaxVert
) ? 2 : 0;
2390 else if (net
->flags
& AttribMaxHoriz
)
2391 m
= (net
->attrib
& AttribMaxHoriz
) ? 3 : 0;
2395 blackbox_attrib
.premax_x
= x
;
2396 blackbox_attrib
.premax_y
= y
;
2397 blackbox_attrib
.premax_w
= w
;
2398 blackbox_attrib
.premax_h
= h
;
2401 if (net
->flags
& AttribDecoration
) {
2402 switch (net
->decoration
) {
2407 /* since tools only let you toggle this anyways, we'll just make that all
2408 it supports for now.
2419 // with the state set it will then be the map event's job to read the
2420 // window's state and behave accordingly
2427 * Positions the Rect r according the the client window position and
2430 void BlackboxWindow::applyGravity(Rect
&r
) {
2431 // apply horizontal window gravity
2432 switch (client
.win_gravity
) {
2434 case NorthWestGravity
:
2435 case SouthWestGravity
:
2437 r
.setX(client
.rect
.x());
2443 r
.setX(client
.rect
.x() - (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2446 case NorthEastGravity
:
2447 case SouthEastGravity
:
2449 r
.setX(client
.rect
.x() - frame
.margin
.left
- frame
.margin
.right
+ 2);
2454 r
.setX(client
.rect
.x() - frame
.margin
.left
);
2458 // apply vertical window gravity
2459 switch (client
.win_gravity
) {
2461 case NorthWestGravity
:
2462 case NorthEastGravity
:
2464 r
.setY(client
.rect
.y());
2470 r
.setY(client
.rect
.y() - (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2473 case SouthWestGravity
:
2474 case SouthEastGravity
:
2476 r
.setY(client
.rect
.y() - frame
.margin
.top
- frame
.margin
.bottom
+ 2);
2481 r
.setY(client
.rect
.y() - frame
.margin
.top
);
2488 * The reverse of the applyGravity function.
2490 * Positions the Rect r according to the frame window position and
2493 void BlackboxWindow::restoreGravity(Rect
&r
) {
2494 // restore horizontal window gravity
2495 switch (client
.win_gravity
) {
2497 case NorthWestGravity
:
2498 case SouthWestGravity
:
2500 r
.setX(frame
.rect
.x());
2506 r
.setX(frame
.rect
.x() + (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2509 case NorthEastGravity
:
2510 case SouthEastGravity
:
2512 r
.setX(frame
.rect
.x() + frame
.margin
.left
+ frame
.margin
.right
- 2);
2517 r
.setX(frame
.rect
.x() + frame
.margin
.left
);
2521 // restore vertical window gravity
2522 switch (client
.win_gravity
) {
2524 case NorthWestGravity
:
2525 case NorthEastGravity
:
2527 r
.setY(frame
.rect
.y());
2533 r
.setY(frame
.rect
.y() + (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2536 case SouthWestGravity
:
2537 case SouthEastGravity
:
2539 r
.setY(frame
.rect
.y() + frame
.margin
.top
+ frame
.margin
.bottom
- 2);
2544 r
.setY(frame
.rect
.y() + frame
.margin
.top
);
2550 void BlackboxWindow::redrawLabel(void) const {
2551 if (flags
.focused
) {
2553 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2554 frame
.label
, frame
.flabel
);
2556 XSetWindowBackground(blackbox
->getXDisplay(),
2557 frame
.label
, frame
.flabel_pixel
);
2560 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2561 frame
.label
, frame
.ulabel
);
2563 XSetWindowBackground(blackbox
->getXDisplay(),
2564 frame
.label
, frame
.ulabel_pixel
);
2566 XClearWindow(blackbox
->getXDisplay(), frame
.label
);
2568 WindowStyle
*style
= screen
->getWindowStyle();
2570 int pos
= frame
.bevel_w
* 2;
2571 style
->doJustify(client
.title
.c_str(), pos
, frame
.label_w
, frame
.bevel_w
* 4);
2572 style
->font
->drawString(frame
.label
, pos
, 1,
2573 (flags
.focused
? style
->l_text_focus
:
2574 style
->l_text_unfocus
),
2579 void BlackboxWindow::redrawAllButtons(void) const {
2580 if (frame
.iconify_button
) redrawIconifyButton(False
);
2581 if (frame
.maximize_button
) redrawMaximizeButton(flags
.maximized
);
2582 if (frame
.close_button
) redrawCloseButton(False
);
2583 if (frame
.stick_button
) redrawStickyButton(flags
.stuck
);
2587 void BlackboxWindow::redrawIconifyButton(bool pressed
) const {
2589 if (flags
.focused
) {
2591 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2592 frame
.iconify_button
, frame
.fbutton
);
2594 XSetWindowBackground(blackbox
->getXDisplay(),
2595 frame
.iconify_button
, frame
.fbutton_pixel
);
2598 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2599 frame
.iconify_button
, frame
.ubutton
);
2601 XSetWindowBackground(blackbox
->getXDisplay(), frame
.iconify_button
,
2602 frame
.ubutton_pixel
);
2606 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2607 frame
.iconify_button
, frame
.pbutton
);
2609 XSetWindowBackground(blackbox
->getXDisplay(),
2610 frame
.iconify_button
, frame
.pbutton_pixel
);
2612 XClearWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
2614 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2615 screen
->getWindowStyle()->b_pic_unfocus
);
2616 XDrawRectangle(blackbox
->getXDisplay(), frame
.iconify_button
, pen
.gc(),
2617 2, (frame
.button_w
- 5), (frame
.button_w
- 5), 2);
2621 void BlackboxWindow::redrawMaximizeButton(bool pressed
) const {
2623 if (flags
.focused
) {
2625 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2626 frame
.maximize_button
, frame
.fbutton
);
2628 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2629 frame
.fbutton_pixel
);
2632 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2633 frame
.maximize_button
, frame
.ubutton
);
2635 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2636 frame
.ubutton_pixel
);
2640 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2641 frame
.maximize_button
, frame
.pbutton
);
2643 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2644 frame
.pbutton_pixel
);
2646 XClearWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
2648 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2649 screen
->getWindowStyle()->b_pic_unfocus
);
2650 XDrawRectangle(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2651 2, 2, (frame
.button_w
- 5), (frame
.button_w
- 5));
2652 XDrawLine(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2653 2, 3, (frame
.button_w
- 3), 3);
2657 void BlackboxWindow::redrawCloseButton(bool pressed
) const {
2659 if (flags
.focused
) {
2661 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2664 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2665 frame
.fbutton_pixel
);
2668 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2671 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2672 frame
.ubutton_pixel
);
2676 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2677 frame
.close_button
, frame
.pbutton
);
2679 XSetWindowBackground(blackbox
->getXDisplay(),
2680 frame
.close_button
, frame
.pbutton_pixel
);
2682 XClearWindow(blackbox
->getXDisplay(), frame
.close_button
);
2684 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2685 screen
->getWindowStyle()->b_pic_unfocus
, 0, 2);
2686 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2687 2, 2, (frame
.button_w
- 3), (frame
.button_w
- 3));
2688 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2689 2, (frame
.button_w
- 3), (frame
.button_w
- 3), 2);
2693 void BlackboxWindow::redrawStickyButton(bool pressed
) const {
2695 if (flags
.focused
) {
2697 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2698 frame
.stick_button
, frame
.fbutton
);
2700 XSetWindowBackground(blackbox
->getXDisplay(), frame
.stick_button
,
2701 frame
.fbutton_pixel
);
2704 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2705 frame
.stick_button
, frame
.ubutton
);
2707 XSetWindowBackground(blackbox
->getXDisplay(), frame
.stick_button
,
2708 frame
.ubutton_pixel
);
2712 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2713 frame
.stick_button
, frame
.pbutton
);
2715 XSetWindowBackground(blackbox
->getXDisplay(), frame
.stick_button
,
2716 frame
.pbutton_pixel
);
2718 XClearWindow(blackbox
->getXDisplay(), frame
.stick_button
);
2720 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2721 screen
->getWindowStyle()->b_pic_unfocus
);
2723 XFillRectangle(blackbox
->getXDisplay(), frame
.stick_button
, pen
.gc(),
2724 frame
.button_w
/2 - 1, frame
.button_w
/2 -1, 2, 2 );
2727 void BlackboxWindow::mapRequestEvent(const XMapRequestEvent
*re
) {
2728 if (re
->window
!= client
.window
)
2732 fprintf(stderr
, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2737 Even though the window wants to be shown, if it is not on the current
2738 workspace, then it isn't going to be shown right now.
2740 if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID() &&
2741 blackbox_attrib
.workspace
< screen
->getWorkspaceCount())
2742 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2744 switch (current_state
) {
2749 case WithdrawnState
:
2758 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2760 if (! blackbox
->isStartup()) {
2761 XSync(blackbox
->getXDisplay(), False
); // make sure the frame is mapped
2762 if (screen
->doFocusNew() || (isTransient() && getTransientFor() &&
2763 getTransientFor()->isFocused())) {
2766 if (screen
->getPlacementPolicy() == BScreen::ClickMousePlacement
) {
2770 XQueryPointer(blackbox
->getXDisplay(), screen
->getRootWindow(),
2771 &r
, &c
, &rx
, &ry
, &x
, &y
, &m
);
2781 void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent
*ue
) {
2782 if (ue
->window
!= client
.window
)
2786 fprintf(stderr
, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2790 screen
->unmanageWindow(this, False
);
2794 void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent
*de
) {
2795 if (de
->window
!= client
.window
)
2799 fprintf(stderr
, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2803 screen
->unmanageWindow(this, False
);
2807 void BlackboxWindow::reparentNotifyEvent(const XReparentEvent
*re
) {
2808 if (re
->window
!= client
.window
|| re
->parent
== frame
.plate
)
2812 fprintf(stderr
, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2813 "0x%lx.\n", client
.window
, re
->parent
);
2818 XPutBackEvent(blackbox
->getXDisplay(), &ev
);
2819 screen
->unmanageWindow(this, True
);
2823 void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent
*pe
) {
2824 if (pe
->state
== PropertyDelete
|| ! validateClient())
2828 fprintf(stderr
, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n",
2834 case XA_WM_CLIENT_MACHINE
:
2838 case XA_WM_TRANSIENT_FOR
: {
2839 bool s
= flags
.stuck
;
2841 // determine if this is a transient window
2844 if (flags
.stuck
!= s
) stick();
2846 // adjust the window decorations based on transience
2847 if (isTransient()) {
2848 functions
&= ~Func_Maximize
;
2849 setAllowedActions();
2861 case XA_WM_ICON_NAME
:
2863 if (flags
.iconic
) screen
->propagateWindowName(this);
2866 case XAtom::net_wm_name
:
2870 if (decorations
& Decor_Titlebar
)
2873 screen
->propagateWindowName(this);
2876 case XA_WM_NORMAL_HINTS
: {
2879 if ((client
.normal_hint_flags
& PMinSize
) &&
2880 (client
.normal_hint_flags
& PMaxSize
)) {
2881 // the window now can/can't resize itself, so the buttons need to be
2884 if (client
.max_width
<= client
.min_width
&&
2885 client
.max_height
<= client
.min_height
) {
2886 functions
&= ~(Func_Resize
| Func_Maximize
);
2888 if (! isTransient())
2889 functions
|= Func_Maximize
;
2890 functions
|= Func_Resize
;
2893 setAllowedActions();
2897 Rect old_rect
= frame
.rect
;
2901 if (old_rect
!= frame
.rect
)
2908 if (pe
->atom
== xatom
->getAtom(XAtom::wm_protocols
)) {
2911 if ((decorations
& Decor_Close
) && (! frame
.close_button
)) {
2912 createCloseButton();
2913 if (decorations
& Decor_Titlebar
) {
2914 positionButtons(True
);
2915 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
2917 if (windowmenu
) windowmenu
->reconfigure();
2919 } else if (pe
->atom
== xatom
->getAtom(XAtom::net_wm_strut
)) {
2928 void BlackboxWindow::exposeEvent(const XExposeEvent
*ee
) {
2930 fprintf(stderr
, "BlackboxWindow::exposeEvent() for 0x%lx\n", client
.window
);
2933 if (frame
.label
== ee
->window
&& (decorations
& Decor_Titlebar
))
2935 else if (frame
.close_button
== ee
->window
)
2936 redrawCloseButton(False
);
2937 else if (frame
.maximize_button
== ee
->window
)
2938 redrawMaximizeButton(flags
.maximized
);
2939 else if (frame
.iconify_button
== ee
->window
)
2940 redrawIconifyButton(False
);
2941 else if (frame
.stick_button
== ee
->window
)
2942 redrawStickyButton(flags
.stuck
);
2946 void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent
*cr
) {
2947 if (cr
->window
!= client
.window
|| flags
.iconic
)
2950 if (cr
->value_mask
& CWBorderWidth
)
2951 client
.old_bw
= cr
->border_width
;
2953 if (cr
->value_mask
& (CWX
| CWY
| CWWidth
| CWHeight
)) {
2954 frame
.changing
= frame
.rect
;
2956 if (cr
->value_mask
& (CWX
| CWY
)) {
2957 if (cr
->value_mask
& CWX
)
2958 client
.rect
.setX(cr
->x
);
2959 if (cr
->value_mask
& CWY
)
2960 client
.rect
.setY(cr
->y
);
2962 applyGravity(frame
.changing
);
2965 if (cr
->value_mask
& (CWWidth
| CWHeight
)) {
2966 if (cr
->value_mask
& CWWidth
)
2967 frame
.changing
.setWidth(cr
->width
+
2968 frame
.margin
.left
+ frame
.margin
.right
);
2970 if (cr
->value_mask
& CWHeight
)
2971 frame
.changing
.setHeight(cr
->height
+
2972 frame
.margin
.top
+ frame
.margin
.bottom
);
2975 if a position change ha been specified, then that position will be used
2976 instead of determining a position based on the window's gravity.
2978 if (cr
->value_mask
& (CWX
| CWY
)) {
2980 switch (client
.win_gravity
) {
2981 case NorthEastGravity
:
2985 case SouthWestGravity
:
2987 corner
= BottomLeft
;
2989 case SouthEastGravity
:
2990 corner
= BottomRight
;
2992 default: // NorthWest, Static, etc
2999 configure(frame
.changing
.x(), frame
.changing
.y(),
3000 frame
.changing
.width(), frame
.changing
.height());
3003 if (cr
->value_mask
& CWStackMode
&& !isDesktop()) {
3004 switch (cr
->detail
) {
3007 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
3013 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3020 void BlackboxWindow::buttonPressEvent(const XButtonEvent
*be
) {
3022 fprintf(stderr
, "BlackboxWindow::buttonPressEvent() for 0x%lx\n",
3026 if (frame
.maximize_button
== be
->window
&& be
->button
<= 3) {
3027 redrawMaximizeButton(True
);
3028 } else if (be
->button
== 1 || (be
->button
== 3 && be
->state
== mod_mask
)) {
3029 if (! flags
.focused
)
3032 if (frame
.iconify_button
== be
->window
) {
3033 redrawIconifyButton(True
);
3034 } else if (frame
.close_button
== be
->window
) {
3035 redrawCloseButton(True
);
3036 } else if (frame
.stick_button
== be
->window
) {
3037 redrawStickyButton(True
);
3038 } else if (frame
.plate
== be
->window
) {
3039 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
3041 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3043 XAllowEvents(blackbox
->getXDisplay(), ReplayPointer
, be
->time
);
3045 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
3046 if (((be
->time
- lastButtonPressTime
) <=
3047 blackbox
->getDoubleClickInterval()) ||
3048 (be
->state
== ControlMask
)) {
3049 lastButtonPressTime
= 0;
3052 lastButtonPressTime
= be
->time
;
3056 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
3058 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3060 } else if (be
->button
== 2 && (be
->window
!= frame
.iconify_button
) &&
3061 (be
->window
!= frame
.close_button
) &&
3062 (be
->window
!= frame
.stick_button
)) {
3063 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
3064 } else if (windowmenu
&& be
->button
== 3 &&
3065 (frame
.title
== be
->window
|| frame
.label
== be
->window
||
3066 frame
.handle
== be
->window
|| frame
.window
== be
->window
)) {
3067 if (windowmenu
->isVisible()) {
3070 int mx
= be
->x_root
- windowmenu
->getWidth() / 2,
3071 my
= be
->y_root
- windowmenu
->getHeight() / 2;
3073 // snap the window menu into a corner/side if necessary
3074 int left_edge
, right_edge
, top_edge
, bottom_edge
;
3077 the " + (frame.border_w * 2) - 1" bits are to get the proper width
3078 and height of the menu, as the sizes returned by it do not include
3081 left_edge
= frame
.rect
.x();
3082 right_edge
= frame
.rect
.right() -
3083 (windowmenu
->getWidth() + (frame
.border_w
* 2) - 1);
3084 top_edge
= client
.rect
.top() - (frame
.border_w
+ frame
.mwm_border_w
);
3085 bottom_edge
= client
.rect
.bottom() -
3086 (windowmenu
->getHeight() + (frame
.border_w
* 2) - 1) +
3087 (frame
.border_w
+ frame
.mwm_border_w
);
3091 if (mx
> right_edge
)
3095 if (my
> bottom_edge
)
3098 windowmenu
->move(mx
, my
);
3100 XRaiseWindow(blackbox
->getXDisplay(), windowmenu
->getWindowID());
3101 XRaiseWindow(blackbox
->getXDisplay(),
3102 windowmenu
->getSendToMenu()->getWindowID());
3105 } else if (be
->button
== 4) {
3106 if ((be
->window
== frame
.label
||
3107 be
->window
== frame
.title
||
3108 be
->window
== frame
.maximize_button
||
3109 be
->window
== frame
.iconify_button
||
3110 be
->window
== frame
.close_button
||
3111 be
->window
== frame
.stick_button
) &&
3115 } else if (be
->button
== 5) {
3116 if ((be
->window
== frame
.label
||
3117 be
->window
== frame
.title
||
3118 be
->window
== frame
.maximize_button
||
3119 be
->window
== frame
.iconify_button
||
3120 be
->window
== frame
.close_button
||
3121 be
->window
== frame
.stick_button
) &&
3128 void BlackboxWindow::buttonReleaseEvent(const XButtonEvent
*re
) {
3130 fprintf(stderr
, "BlackboxWindow::buttonReleaseEvent() for 0x%lx\n",
3134 if (re
->window
== frame
.maximize_button
&&
3135 re
->button
>= 1 && re
->button
<= 3) {
3136 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3137 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
3138 maximize(re
->button
);
3140 redrawMaximizeButton(flags
.maximized
);
3142 } else if (re
->window
== frame
.iconify_button
&& re
->button
== 1) {
3143 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3144 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
3147 redrawIconifyButton(False
);
3149 } else if (re
->window
== frame
.stick_button
&& re
->button
== 1) {
3150 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3151 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
3154 redrawStickyButton(False
);
3156 } else if (re
->window
== frame
.close_button
& re
->button
== 1) {
3157 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3158 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
)))
3160 redrawCloseButton(False
);
3161 } else if (flags
.moving
) {
3163 } else if (flags
.resizing
) {
3165 } else if (re
->window
== frame
.window
) {
3166 if (re
->button
== 2 && re
->state
== mod_mask
)
3167 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3173 void BlackboxWindow::beginMove(int x_root
, int y_root
) {
3174 if (! (functions
& Func_Move
)) return;
3176 assert(! (flags
.resizing
|| flags
.moving
));
3179 Only one window can be moved/resized at a time. If another window is already
3180 being moved or resized, then stop it before whating to work with this one.
3182 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3183 if (changing
&& changing
!= this) {
3184 if (changing
->flags
.moving
)
3185 changing
->endMove();
3186 else // if (changing->flags.resizing)
3187 changing
->endResize();
3190 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3191 PointerMotionMask
| ButtonReleaseMask
,
3192 GrabModeAsync
, GrabModeAsync
,
3193 None
, blackbox
->getMoveCursor(), CurrentTime
);
3195 if (windowmenu
&& windowmenu
->isVisible())
3198 flags
.moving
= True
;
3199 blackbox
->setChangingWindow(this);
3201 if (! screen
->doOpaqueMove()) {
3202 XGrabServer(blackbox
->getXDisplay());
3204 frame
.changing
= frame
.rect
;
3205 screen
->showPosition(frame
.changing
.x(), frame
.changing
.y());
3207 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3211 frame
.changing
.width() - 1,
3212 frame
.changing
.height() - 1);
3215 frame
.grab_x
= x_root
- frame
.rect
.x() - frame
.border_w
;
3216 frame
.grab_y
= y_root
- frame
.rect
.y() - frame
.border_w
;
3220 void BlackboxWindow::doMove(int x_root
, int y_root
) {
3221 assert(flags
.moving
);
3222 assert(blackbox
->getChangingWindow() == this);
3224 int dx
= x_root
- frame
.grab_x
, dy
= y_root
- frame
.grab_y
;
3225 dx
-= frame
.border_w
;
3226 dy
-= frame
.border_w
;
3228 doWindowSnapping(dx
, dy
);
3230 if (screen
->doOpaqueMove()) {
3231 if (screen
->doWorkspaceWarping())
3232 doWorkspaceWarping(x_root
, y_root
, dx
);
3234 configure(dx
, dy
, frame
.rect
.width(), frame
.rect
.height());
3236 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3240 frame
.changing
.width() - 1,
3241 frame
.changing
.height() - 1);
3243 if (screen
->doWorkspaceWarping())
3244 doWorkspaceWarping(x_root
, y_root
, dx
);
3246 frame
.changing
.setPos(dx
, dy
);
3248 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3252 frame
.changing
.width() - 1,
3253 frame
.changing
.height() - 1);
3256 screen
->showPosition(dx
, dy
);
3260 void BlackboxWindow::doWorkspaceWarping(int x_root
, int y_root
, int &dx
) {
3261 // workspace warping
3263 unsigned int dest
= screen
->getCurrentWorkspaceID();
3267 if (dest
> 0) dest
--;
3268 else dest
= screen
->getNumberOfWorkspaces() - 1;
3270 } else if (x_root
>= screen
->getRect().right()) {
3273 if (dest
< screen
->getNumberOfWorkspaces() - 1) dest
++;
3279 bool focus
= flags
.focused
; // had focus while moving?
3281 int dest_x
= x_root
;
3283 dest_x
+= screen
->getRect().width() - 1;
3284 dx
+= screen
->getRect().width() - 1;
3286 dest_x
-= screen
->getRect().width() - 1;
3287 dx
-= screen
->getRect().width() - 1;
3291 screen
->reassociateWindow(this, dest
, False
);
3292 screen
->changeWorkspaceID(dest
);
3294 if (screen
->doOpaqueMove())
3295 XGrabServer(blackbox
->getXDisplay());
3297 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3298 XWarpPointer(blackbox
->getXDisplay(), None
,
3299 screen
->getRootWindow(), 0, 0, 0, 0,
3301 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3302 PointerMotionMask
| ButtonReleaseMask
,
3303 GrabModeAsync
, GrabModeAsync
,
3304 None
, blackbox
->getMoveCursor(), CurrentTime
);
3306 if (screen
->doOpaqueMove())
3307 XUngrabServer(blackbox
->getXDisplay());
3315 void BlackboxWindow::doWindowSnapping(int &dx
, int &dy
) {
3316 // how much resistance to edges to provide
3317 const int resistance_size
= screen
->getResistanceSize();
3319 // how far away to snap
3320 const int snap_distance
= screen
->getSnapThreshold();
3322 // how to snap windows
3323 const int snap_to_windows
= screen
->getWindowToWindowSnap();
3324 const int snap_to_edges
= screen
->getWindowToEdgeSnap();
3325 // the amount of space away from the edge to provide resistance/snap
3326 const int snap_offset
= screen
->getSnapOffset();
3328 // find the geomeetery where the moving window currently is
3329 const Rect
&moving
= screen
->doOpaqueMove() ? frame
.rect
: frame
.changing
;
3332 const int wleft
= dx
,
3333 wright
= dx
+ frame
.rect
.width() - 1,
3335 wbottom
= dy
+ frame
.rect
.height() - 1;
3337 if (snap_to_windows
) {
3340 Workspace
*w
= screen
->getWorkspace(getWorkspaceNumber());
3343 // add windows on the workspace to the rect list
3344 const BlackboxWindowList
& stack_list
= w
->getStackingList();
3345 BlackboxWindowList::const_iterator st_it
, st_end
= stack_list
.end();
3346 for (st_it
= stack_list
.begin(); st_it
!= st_end
; ++st_it
)
3347 if (*st_it
!= this) // don't snap to ourself
3348 rectlist
.push_back( (*st_it
)->frameRect() );
3350 // add the toolbar and the slit to the rect list.
3351 // (only if they are not hidden)
3352 Toolbar
*tbar
= screen
->getToolbar();
3353 Slit
*slit
= screen
->getSlit();
3354 Rect tbar_rect
, slit_rect
;
3355 unsigned int bwidth
= screen
->getBorderWidth() * 2;
3357 if (! (screen
->doHideToolbar() || tbar
->isHidden())) {
3358 tbar_rect
.setRect(tbar
->getX(), tbar
->getY(), tbar
->getWidth() + bwidth
,
3359 tbar
->getHeight() + bwidth
);
3360 rectlist
.push_back(tbar_rect
);
3363 if (! slit
->isHidden()) {
3364 slit_rect
.setRect(slit
->getX(), slit
->getY(), slit
->getWidth() + bwidth
,
3365 slit
->getHeight() + bwidth
);
3366 rectlist
.push_back(slit_rect
);
3369 RectList::const_iterator it
, end
= rectlist
.end();
3370 for (it
= rectlist
.begin(); it
!= end
; ++it
) {
3371 bool snapped
= False
;
3372 const Rect
&winrect
= *it
;
3374 offsetrect
.setCoords(winrect
.left() - snap_offset
,
3375 winrect
.top() - snap_offset
,
3376 winrect
.right() + snap_offset
,
3377 winrect
.bottom() + snap_offset
);
3379 if (snap_to_windows
== BScreen::WindowResistance
)
3380 // if the window is already over top of this snap target, then
3381 // resistance is futile, so just ignore it
3382 if (winrect
.intersects(moving
))
3385 int dleft
, dright
, dtop
, dbottom
;
3387 // if the windows are in the same plane vertically
3388 if (wtop
>= (signed)(winrect
.y() - frame
.rect
.height() + 1) &&
3389 wtop
< (signed)(winrect
.y() + winrect
.height() - 1)) {
3391 if (snap_to_windows
== BScreen::WindowResistance
) {
3392 dleft
= wright
- offsetrect
.left();
3393 dright
= offsetrect
.right() - wleft
;
3395 // snap left of other window?
3396 if (dleft
>= 0 && dleft
< resistance_size
&&
3397 dleft
< (wright
- wleft
)) {
3398 dx
= offsetrect
.left() - frame
.rect
.width();
3401 // snap right of other window?
3402 else if (dright
>= 0 && dright
< resistance_size
&&
3403 dright
< (wright
- wleft
)) {
3404 dx
= offsetrect
.right() + 1;
3407 } else { // BScreen::WindowSnap
3408 dleft
= abs(wright
- offsetrect
.left());
3409 dright
= abs(wleft
- offsetrect
.right());
3411 // snap left of other window?
3412 if (dleft
< snap_distance
&& dleft
<= dright
) {
3413 dx
= offsetrect
.left() - frame
.rect
.width();
3416 // snap right of other window?
3417 else if (dright
< snap_distance
) {
3418 dx
= offsetrect
.right() + 1;
3424 if (screen
->getWindowCornerSnap()) {
3425 // try corner-snap to its other sides
3426 if (snap_to_windows
== BScreen::WindowResistance
) {
3427 dtop
= winrect
.top() - wtop
;
3428 dbottom
= wbottom
- winrect
.bottom();
3429 if (dtop
> 0 && dtop
< resistance_size
) {
3430 // if we're already past the top edge, then don't provide
3432 if (moving
.top() >= winrect
.top())
3434 } else if (dbottom
> 0 && dbottom
< resistance_size
) {
3435 // if we're already past the bottom edge, then don't provide
3437 if (moving
.bottom() <= winrect
.bottom())
3438 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
3440 } else { // BScreen::WindowSnap
3441 dtop
= abs(wtop
- winrect
.top());
3442 dbottom
= abs(wbottom
- winrect
.bottom());
3443 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3445 else if (dbottom
< snap_distance
)
3446 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
3454 // if the windows are on the same plane horizontally
3455 if (wleft
>= (signed)(winrect
.x() - frame
.rect
.width() + 1) &&
3456 wleft
< (signed)(winrect
.x() + winrect
.width() - 1)) {
3458 if (snap_to_windows
== BScreen::WindowResistance
) {
3459 dtop
= wbottom
- offsetrect
.top();
3460 dbottom
= offsetrect
.bottom() - wtop
;
3462 // snap top of other window?
3463 if (dtop
>= 0 && dtop
< resistance_size
&& dtop
< (wbottom
- wtop
)) {
3464 dy
= offsetrect
.top() - frame
.rect
.height();
3467 // snap bottom of other window?
3468 else if (dbottom
>= 0 && dbottom
< resistance_size
&&
3469 dbottom
< (wbottom
- wtop
)) {
3470 dy
= offsetrect
.bottom() + 1;
3473 } else { // BScreen::WindowSnap
3474 dtop
= abs(wbottom
- offsetrect
.top());
3475 dbottom
= abs(wtop
- offsetrect
.bottom());
3477 // snap top of other window?
3478 if (dtop
< snap_distance
&& dtop
<= dbottom
) {
3479 dy
= offsetrect
.top() - frame
.rect
.height();
3482 // snap bottom of other window?
3483 else if (dbottom
< snap_distance
) {
3484 dy
= offsetrect
.bottom() + 1;
3491 if (screen
->getWindowCornerSnap()) {
3492 // try corner-snap to its other sides
3493 if (snap_to_windows
== BScreen::WindowResistance
) {
3494 dleft
= winrect
.left() - wleft
;
3495 dright
= wright
- winrect
.right();
3496 if (dleft
> 0 && dleft
< resistance_size
) {
3497 // if we're already past the left edge, then don't provide
3499 if (moving
.left() >= winrect
.left())
3500 dx
= winrect
.left();
3501 } else if (dright
> 0 && dright
< resistance_size
) {
3502 // if we're already past the right edge, then don't provide
3504 if (moving
.right() <= winrect
.right())
3505 dx
= winrect
.right() - frame
.rect
.width() + 1;
3507 } else { // BScreen::WindowSnap
3508 dleft
= abs(wleft
- winrect
.left());
3509 dright
= abs(wright
- winrect
.right());
3510 if (dleft
< snap_distance
&& dleft
<= dright
)
3511 dx
= winrect
.left();
3512 else if (dright
< snap_distance
)
3513 dx
= winrect
.right() - frame
.rect
.width() + 1;
3523 if (snap_to_edges
) {
3526 // snap to the screen edges (and screen boundaries for xinerama)
3528 if (screen
->isXineramaActive() && blackbox
->doXineramaSnapping()) {
3529 rectlist
.insert(rectlist
.begin(),
3530 screen
->getXineramaAreas().begin(),
3531 screen
->getXineramaAreas().end());
3534 rectlist
.push_back(screen
->getRect());
3536 RectList::const_iterator it
, end
= rectlist
.end();
3537 for (it
= rectlist
.begin(); it
!= end
; ++it
) {
3538 const Rect
&srect
= *it
;
3540 offsetrect
.setCoords(srect
.left() + snap_offset
,
3541 srect
.top() + snap_offset
,
3542 srect
.right() - snap_offset
,
3543 srect
.bottom() - snap_offset
);
3545 if (snap_to_edges
== BScreen::WindowResistance
) {
3546 // if we're not in the rectangle then don't snap to it.
3547 if (! srect
.contains(moving
))
3549 } else { // BScreen::WindowSnap
3550 // if we're not in the rectangle then don't snap to it.
3551 if (! srect
.intersects(Rect(wleft
, wtop
, frame
.rect
.width(),
3552 frame
.rect
.height())))
3556 if (snap_to_edges
== BScreen::WindowResistance
) {
3557 int dleft
= offsetrect
.left() - wleft
,
3558 dright
= wright
- offsetrect
.right(),
3559 dtop
= offsetrect
.top() - wtop
,
3560 dbottom
= wbottom
- offsetrect
.bottom();
3563 if (dleft
> 0 && dleft
< resistance_size
)
3564 dx
= offsetrect
.left();
3566 else if (dright
> 0 && dright
< resistance_size
)
3567 dx
= offsetrect
.right() - frame
.rect
.width() + 1;
3570 if (dtop
> 0 && dtop
< resistance_size
)
3571 dy
= offsetrect
.top();
3573 else if (dbottom
> 0 && dbottom
< resistance_size
)
3574 dy
= offsetrect
.bottom() - frame
.rect
.height() + 1;
3575 } else { // BScreen::WindowSnap
3576 int dleft
= abs(wleft
- offsetrect
.left()),
3577 dright
= abs(wright
- offsetrect
.right()),
3578 dtop
= abs(wtop
- offsetrect
.top()),
3579 dbottom
= abs(wbottom
- offsetrect
.bottom());
3582 if (dleft
< snap_distance
&& dleft
<= dright
)
3583 dx
= offsetrect
.left();
3585 else if (dright
< snap_distance
)
3586 dx
= offsetrect
.right() - frame
.rect
.width() + 1;
3589 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3590 dy
= offsetrect
.top();
3592 else if (dbottom
< snap_distance
)
3593 dy
= offsetrect
.bottom() - frame
.rect
.height() + 1;
3600 void BlackboxWindow::endMove(void) {
3601 assert(flags
.moving
);
3602 assert(blackbox
->getChangingWindow() == this);
3604 flags
.moving
= False
;
3605 blackbox
->setChangingWindow(0);
3607 if (! screen
->doOpaqueMove()) {
3608 /* when drawing the rubber band, we need to make sure we only draw inside
3609 * the frame... frame.changing_* contain the new coords for the window,
3610 * so we need to subtract 1 from changing_w/changing_h every where we
3611 * draw the rubber band (for both moving and resizing)
3613 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3614 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3615 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3616 XUngrabServer(blackbox
->getXDisplay());
3618 configure(frame
.changing
.x(), frame
.changing
.y(),
3619 frame
.changing
.width(), frame
.changing
.height());
3621 configure(frame
.rect
.x(), frame
.rect
.y(),
3622 frame
.rect
.width(), frame
.rect
.height());
3624 screen
->hideGeometry();
3626 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3628 // if there are any left over motions from the move, drop them now
3629 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3631 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3636 void BlackboxWindow::beginResize(int x_root
, int y_root
, Corner dir
) {
3637 if (! (functions
& Func_Resize
)) return;
3639 assert(! (flags
.resizing
|| flags
.moving
));
3642 Only one window can be moved/resized at a time. If another window is
3643 already being moved or resized, then stop it before whating to work with
3646 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3647 if (changing
&& changing
!= this) {
3648 if (changing
->flags
.moving
)
3649 changing
->endMove();
3650 else // if (changing->flags.resizing)
3651 changing
->endResize();
3659 switch (resize_dir
) {
3662 cursor
= blackbox
->getLowerLeftAngleCursor();
3667 cursor
= blackbox
->getLowerRightAngleCursor();
3671 anchor
= BottomRight
;
3672 cursor
= blackbox
->getUpperLeftAngleCursor();
3676 anchor
= BottomLeft
;
3677 cursor
= blackbox
->getUpperRightAngleCursor();
3681 assert(false); // unhandled Corner
3682 return; // unreachable, for the compiler
3685 XGrabServer(blackbox
->getXDisplay());
3686 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3687 PointerMotionMask
| ButtonReleaseMask
,
3688 GrabModeAsync
, GrabModeAsync
, None
, cursor
, CurrentTime
);
3690 flags
.resizing
= True
;
3691 blackbox
->setChangingWindow(this);
3693 unsigned int gw
, gh
;
3694 frame
.changing
= frame
.rect
;
3696 constrain(anchor
, &gw
, &gh
);
3698 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3699 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3700 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3702 screen
->showGeometry(gw
, gh
);
3704 frame
.grab_x
= x_root
;
3705 frame
.grab_y
= y_root
;
3709 void BlackboxWindow::doResize(int x_root
, int y_root
) {
3710 assert(flags
.resizing
);
3711 assert(blackbox
->getChangingWindow() == this);
3713 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3714 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3715 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3717 unsigned int gw
, gh
;
3719 int dx
, dy
; // the amount of change in the size of the window
3721 switch (resize_dir
) {
3724 dx
= - (x_root
- frame
.grab_x
);
3725 dy
= + (y_root
- frame
.grab_y
);
3729 dx
= + (x_root
- frame
.grab_x
);
3730 dy
= + (y_root
- frame
.grab_y
);
3733 anchor
= BottomRight
;
3734 dx
= - (x_root
- frame
.grab_x
);
3735 dy
= - (y_root
- frame
.grab_y
);
3738 anchor
= BottomLeft
;
3739 dx
= + (x_root
- frame
.grab_x
);
3740 dy
= - (y_root
- frame
.grab_y
);
3744 assert(false); // unhandled Corner
3745 return; // unreachable, for the compiler
3748 // make sure the user cant resize the window smaller than 0, which makes it
3749 // wrap around and become huge
3750 if (dx
< -(signed)client
.rect
.width()) dx
= -(signed)client
.rect
.width();
3751 if (dy
< -(signed)client
.rect
.height()) dy
= -(signed)client
.rect
.height();
3753 frame
.changing
.setSize(frame
.rect
.width() + dx
, frame
.rect
.height() + dy
);
3755 constrain(anchor
, &gw
, &gh
);
3757 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3758 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3759 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3761 screen
->showGeometry(gw
, gh
);
3765 void BlackboxWindow::endResize(void) {
3766 assert(flags
.resizing
);
3767 assert(blackbox
->getChangingWindow() == this);
3769 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3770 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3771 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3772 XUngrabServer(blackbox
->getXDisplay());
3774 // unset maximized state after resized when fully maximized
3775 if (flags
.maximized
== 1)
3778 flags
.resizing
= False
;
3779 blackbox
->setChangingWindow(0);
3781 configure(frame
.changing
.x(), frame
.changing
.y(),
3782 frame
.changing
.width(), frame
.changing
.height());
3783 screen
->hideGeometry();
3785 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3787 // if there are any left over motions from the resize, drop them now
3788 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3790 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3795 void BlackboxWindow::motionNotifyEvent(const XMotionEvent
*me
) {
3797 fprintf(stderr
, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n",
3802 doMove(me
->x_root
, me
->y_root
);
3803 } else if (flags
.resizing
) {
3804 doResize(me
->x_root
, me
->y_root
);
3806 if ((functions
& Func_Move
) &&
3807 (me
->state
& Button1Mask
) &&
3808 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3809 frame
.handle
== me
->window
|| frame
.window
== me
->window
)) {
3810 beginMove(me
->x_root
, me
->y_root
);
3811 } else if ((functions
& Func_Resize
) &&
3812 ((me
->state
& Button1Mask
) && (me
->window
== frame
.right_grip
||
3813 me
->window
== frame
.left_grip
)) ||
3814 ((me
->state
& Button3Mask
) && (me
->state
& mod_mask
) &&
3815 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3816 frame
.handle
== me
->window
|| frame
.window
== me
->window
))) {
3817 unsigned int zones
= screen
->getResizeZones();
3820 if (me
->window
== frame
.left_grip
) {
3821 corner
= BottomLeft
;
3822 } else if (me
->window
== frame
.right_grip
|| zones
== 1) {
3823 corner
= BottomRight
;
3826 bool left
= (me
->x_root
- frame
.rect
.x() <=
3827 static_cast<signed>(frame
.rect
.width() / 2));
3830 else // (zones == 4)
3831 top
= (me
->y_root
- frame
.rect
.y() <=
3832 static_cast<signed>(frame
.rect
.height() / 2));
3833 corner
= (top
? (left
? TopLeft
: TopRight
) :
3834 (left
? BottomLeft
: BottomRight
));
3837 beginResize(me
->x_root
, me
->y_root
, corner
);
3843 void BlackboxWindow::enterNotifyEvent(const XCrossingEvent
* ce
) {
3844 if (! (screen
->isSloppyFocus() && isVisible() && isNormal()))
3848 bool leave
= False
, inferior
= False
;
3850 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), ce
->window
,
3852 if (e
.type
== LeaveNotify
&& e
.xcrossing
.mode
== NotifyNormal
) {
3854 inferior
= (e
.xcrossing
.detail
== NotifyInferior
);
3858 if (! leave
|| inferior
) {
3859 if (! isFocused()) {
3860 bool success
= setInputFocus();
3861 if (success
) // if focus succeeded install the colormap
3862 installColormap(True
); // XXX: shouldnt we honour no install?
3865 if (screen
->doAutoRaise())
3871 void BlackboxWindow::leaveNotifyEvent(const XCrossingEvent
*) {
3872 if (! (screen
->isSloppyFocus() && screen
->doAutoRaise() && isNormal()))
3875 installColormap(False
);
3877 if (timer
->isTiming())
3883 void BlackboxWindow::shapeEvent(XShapeEvent
*e
) {
3884 if (blackbox
->hasShapeExtensions()) {
3885 if (! e
->shaped
&& flags
.shaped
) {
3887 flags
.shaped
= False
;
3888 } else if (e
->shaped
) {
3890 flags
.shaped
= True
;
3897 bool BlackboxWindow::validateClient(void) const {
3898 XSync(blackbox
->getXDisplay(), False
);
3901 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3902 DestroyNotify
, &e
) ||
3903 XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3905 XPutBackEvent(blackbox
->getXDisplay(), &e
);
3914 void BlackboxWindow::restore(bool remap
) {
3915 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeDelete
);
3916 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
3917 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, NoEventMask
);
3919 // do not leave a shaded window as an icon unless it was an icon
3920 if (flags
.shaded
&& ! flags
.iconic
)
3921 setState(NormalState
);
3923 // erase the netwm stuff that we read when a window maps, so that it
3924 // doesn't persist between mappings.
3925 // (these are the ones read in getNetWMFlags().)
3926 xatom
->eraseValue(client
.window
, XAtom::net_wm_desktop
);
3927 xatom
->eraseValue(client
.window
, XAtom::net_wm_state
);
3929 restoreGravity(client
.rect
);
3931 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
3932 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
3934 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, client
.old_bw
);
3937 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3938 ReparentNotify
, &ev
)) {
3941 // according to the ICCCM - if the client doesn't reparent to
3942 // root, then we have to do it for them
3943 XReparentWindow(blackbox
->getXDisplay(), client
.window
,
3944 screen
->getRootWindow(),
3945 client
.rect
.x(), client
.rect
.y());
3948 if (remap
) XMapWindow(blackbox
->getXDisplay(), client
.window
);
3952 // timer for autoraise
3953 void BlackboxWindow::timeout(void) {
3954 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3958 void BlackboxWindow::changeBlackboxHints(const BlackboxHints
*net
) {
3959 if ((net
->flags
& AttribShaded
) &&
3960 ((blackbox_attrib
.attrib
& AttribShaded
) !=
3961 (net
->attrib
& AttribShaded
)))
3964 if (flags
.visible
&& // watch out for requests when we can not be seen
3965 (net
->flags
& (AttribMaxVert
| AttribMaxHoriz
)) &&
3966 ((blackbox_attrib
.attrib
& (AttribMaxVert
| AttribMaxHoriz
)) !=
3967 (net
->attrib
& (AttribMaxVert
| AttribMaxHoriz
)))) {
3968 if (flags
.maximized
) {
3973 if ((net
->flags
& AttribMaxHoriz
) && (net
->flags
& AttribMaxVert
))
3974 button
= ((net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0);
3975 else if (net
->flags
& AttribMaxVert
)
3976 button
= ((net
->attrib
& AttribMaxVert
) ? 2 : 0);
3977 else if (net
->flags
& AttribMaxHoriz
)
3978 button
= ((net
->attrib
& AttribMaxHoriz
) ? 3 : 0);
3984 if ((net
->flags
& AttribOmnipresent
) &&
3985 ((blackbox_attrib
.attrib
& AttribOmnipresent
) !=
3986 (net
->attrib
& AttribOmnipresent
)))
3989 if ((net
->flags
& AttribWorkspace
) &&
3990 (blackbox_attrib
.workspace
!= net
->workspace
)) {
3991 screen
->reassociateWindow(this, net
->workspace
, True
);
3993 if (screen
->getCurrentWorkspaceID() != net
->workspace
) {
3997 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
4001 if (net
->flags
& AttribDecoration
) {
4002 switch (net
->decoration
) {
4019 * Set the sizes of all components of the window frame
4020 * (the window decorations).
4021 * These values are based upon the current style settings and the client
4022 * window's dimensions.
4024 void BlackboxWindow::upsize(void) {
4025 frame
.bevel_w
= screen
->getBevelWidth();
4027 if (decorations
& Decor_Border
) {
4028 frame
.border_w
= screen
->getBorderWidth();
4029 if (! isTransient())
4030 frame
.mwm_border_w
= screen
->getFrameWidth();
4032 frame
.mwm_border_w
= 0;
4034 frame
.mwm_border_w
= frame
.border_w
= 0;
4037 if (decorations
& Decor_Titlebar
) {
4038 // the height of the titlebar is based upon the height of the font being
4039 // used to display the window's title
4040 WindowStyle
*style
= screen
->getWindowStyle();
4041 frame
.title_h
= style
->font
->height() + (frame
.bevel_w
* 2) + 2;
4043 frame
.label_h
= frame
.title_h
- (frame
.bevel_w
* 2);
4044 frame
.button_w
= (frame
.label_h
- 2);
4046 // set the top frame margin
4047 frame
.margin
.top
= frame
.border_w
+ frame
.title_h
+
4048 frame
.border_w
+ frame
.mwm_border_w
;
4054 // set the top frame margin
4055 frame
.margin
.top
= frame
.border_w
+ frame
.mwm_border_w
;
4058 // set the left/right frame margin
4059 frame
.margin
.left
= frame
.margin
.right
= frame
.border_w
+ frame
.mwm_border_w
;
4061 if (decorations
& Decor_Handle
) {
4062 frame
.grip_w
= frame
.button_w
* 2;
4063 frame
.handle_h
= screen
->getHandleWidth();
4065 // set the bottom frame margin
4066 frame
.margin
.bottom
= frame
.border_w
+ frame
.handle_h
+
4067 frame
.border_w
+ frame
.mwm_border_w
;
4072 // set the bottom frame margin
4073 frame
.margin
.bottom
= frame
.border_w
+ frame
.mwm_border_w
;
4077 We first get the normal dimensions and use this to define the inside_w/h
4078 then we modify the height if shading is in effect.
4079 If the shade state is not considered then frame.rect gets reset to the
4080 normal window size on a reconfigure() call resulting in improper
4081 dimensions appearing in move/resize and other events.
4084 height
= client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
,
4085 width
= client
.rect
.width() + frame
.margin
.left
+ frame
.margin
.right
;
4087 frame
.inside_w
= width
- (frame
.border_w
* 2);
4088 frame
.inside_h
= height
- (frame
.border_w
* 2);
4091 height
= frame
.title_h
+ (frame
.border_w
* 2);
4092 frame
.rect
.setSize(width
, height
);
4097 * Calculate the size of the client window and constrain it to the
4098 * size specified by the size hints of the client window.
4100 * The logical width and height are placed into pw and ph, if they
4101 * are non-zero. Logical size refers to the users perception of
4102 * the window size (for example an xterm resizes in cells, not in pixels).
4103 * pw and ph are then used to display the geometry during window moves, resize,
4106 * The physical geometry is placed into frame.changing_{x,y,width,height}.
4107 * Physical geometry refers to the geometry of the window in pixels.
4109 void BlackboxWindow::constrain(Corner anchor
,
4110 unsigned int *pw
, unsigned int *ph
) {
4111 // frame.changing represents the requested frame size, we need to
4112 // strip the frame margin off and constrain the client size
4113 frame
.changing
.setCoords(frame
.changing
.left() + frame
.margin
.left
,
4114 frame
.changing
.top() + frame
.margin
.top
,
4115 frame
.changing
.right() - frame
.margin
.right
,
4116 frame
.changing
.bottom() - frame
.margin
.bottom
);
4118 unsigned int dw
= frame
.changing
.width(), dh
= frame
.changing
.height(),
4119 base_width
= (client
.base_width
) ? client
.base_width
: client
.min_width
,
4120 base_height
= (client
.base_height
) ? client
.base_height
:
4124 if (dw
< client
.min_width
) dw
= client
.min_width
;
4125 if (dh
< client
.min_height
) dh
= client
.min_height
;
4126 if (dw
> client
.max_width
) dw
= client
.max_width
;
4127 if (dh
> client
.max_height
) dh
= client
.max_height
;
4129 assert(dw
>= base_width
&& dh
>= base_height
);
4131 if (client
.width_inc
> 1) {
4133 dw
/= client
.width_inc
;
4135 if (client
.height_inc
> 1) {
4137 dh
/= client
.height_inc
;
4146 if (client
.width_inc
> 1) {
4147 dw
*= client
.width_inc
;
4150 if (client
.height_inc
> 1) {
4151 dh
*= client
.height_inc
;
4155 frame
.changing
.setSize(dw
, dh
);
4157 // add the frame margin back onto frame.changing
4158 frame
.changing
.setCoords(frame
.changing
.left() - frame
.margin
.left
,
4159 frame
.changing
.top() - frame
.margin
.top
,
4160 frame
.changing
.right() + frame
.margin
.right
,
4161 frame
.changing
.bottom() + frame
.margin
.bottom
);
4163 // move frame.changing to the specified anchor
4171 dx
= frame
.rect
.right() - frame
.changing
.right();
4175 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
4179 dx
= frame
.rect
.right() - frame
.changing
.right();
4180 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
4184 assert(false); // unhandled corner
4186 frame
.changing
.setPos(frame
.changing
.x() + dx
, frame
.changing
.y() + dy
);
4190 void WindowStyle::doJustify(const std::string
&text
, int &start_pos
,
4191 unsigned int max_length
,
4192 unsigned int modifier
) const {
4193 size_t text_len
= text
.size();
4194 unsigned int length
;
4197 length
= font
->measureString(string(text
, 0, text_len
)) + modifier
;
4198 } while (length
> max_length
&& text_len
-- > 0);
4202 start_pos
+= max_length
- length
;
4206 start_pos
+= (max_length
- length
) / 2;
4216 BWindowGroup::BWindowGroup(Blackbox
*b
, Window _group
)
4217 : blackbox(b
), group(_group
) {
4218 XWindowAttributes wattrib
;
4219 if (! XGetWindowAttributes(blackbox
->getXDisplay(), group
, &wattrib
)) {
4220 // group window doesn't seem to exist anymore
4225 XSelectInput(blackbox
->getXDisplay(), group
,
4226 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
4228 blackbox
->saveGroupSearch(group
, this);
4232 BWindowGroup::~BWindowGroup(void) {
4233 blackbox
->removeGroupSearch(group
);
4238 BWindowGroup::find(BScreen
*screen
, bool allow_transients
) const {
4239 BlackboxWindow
*ret
= blackbox
->getFocusedWindow();
4241 // does the focus window match (or any transient_fors)?
4242 for (; ret
; ret
= ret
->getTransientFor()) {
4243 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
&&
4244 (! ret
->isTransient() || allow_transients
))
4248 if (ret
) return ret
;
4250 // the focus window didn't match, look in the group's window list
4251 BlackboxWindowList::const_iterator it
, end
= windowList
.end();
4252 for (it
= windowList
.begin(); it
!= end
; ++it
) {
4254 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
&&
4255 (! ret
->isTransient() || allow_transients
))