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 #ifdef DEBUG_WITH_ID
1129 // the 16 is the 8 chars of the debug text plus the number
1130 char *tmp
= new char[client
.title
.length() + 16];
1131 sprintf(tmp
, "%s; id: 0x%lx", client
.title
.c_str(), client
.window
);
1138 void BlackboxWindow::getWMIconName(void) {
1139 if (xatom
->getValue(client
.window
, XAtom::net_wm_icon_name
,
1140 XAtom::utf8
, client
.icon_title
) &&
1141 !client
.icon_title
.empty()) {
1142 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1145 //fall through to using WM_ICON_NAME
1146 if (xatom
->getValue(client
.window
, XAtom::wm_icon_name
, XAtom::ansi
,
1147 client
.icon_title
) &&
1148 !client
.icon_title
.empty()) {
1149 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1152 // fall back to using the main name
1153 client
.icon_title
= client
.title
;
1154 xatom
->setValue(client
.window
, XAtom::net_wm_visible_icon_name
, XAtom::utf8
,
1160 * Retrieve which WM Protocols are supported by the client window.
1161 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
1162 * window's decorations and allow the close behavior.
1163 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
1166 void BlackboxWindow::getWMProtocols(void) {
1170 if (XGetWMProtocols(blackbox
->getXDisplay(), client
.window
,
1171 &proto
, &num_return
)) {
1172 for (int i
= 0; i
< num_return
; ++i
) {
1173 if (proto
[i
] == xatom
->getAtom(XAtom::wm_delete_window
)) {
1174 decorations
|= Decor_Close
;
1175 functions
|= Func_Close
;
1176 } else if (proto
[i
] == xatom
->getAtom(XAtom::wm_take_focus
))
1177 flags
.send_focus_message
= True
;
1178 else if (proto
[i
] == xatom
->getAtom(XAtom::blackbox_structure_messages
))
1179 screen
->addNetizen(new Netizen(screen
, client
.window
));
1188 * Gets the value of the WM_HINTS property.
1189 * If the property is not set, then use a set of default values.
1191 void BlackboxWindow::getWMHints(void) {
1192 focus_mode
= F_Passive
;
1194 // remove from current window group
1195 if (client
.window_group
) {
1196 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1197 if (group
) group
->removeWindow(this);
1199 client
.window_group
= None
;
1201 XWMHints
*wmhint
= XGetWMHints(blackbox
->getXDisplay(), client
.window
);
1206 if (wmhint
->flags
& InputHint
) {
1207 if (wmhint
->input
== True
) {
1208 if (flags
.send_focus_message
)
1209 focus_mode
= F_LocallyActive
;
1211 if (flags
.send_focus_message
)
1212 focus_mode
= F_GloballyActive
;
1214 focus_mode
= F_NoInput
;
1218 if (wmhint
->flags
& StateHint
)
1219 current_state
= wmhint
->initial_state
;
1221 if (wmhint
->flags
& WindowGroupHint
) {
1222 client
.window_group
= wmhint
->window_group
;
1224 // add window to the appropriate group
1225 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1226 if (! group
) { // no group found, create it!
1227 new BWindowGroup(blackbox
, client
.window_group
);
1228 group
= blackbox
->searchGroup(client
.window_group
);
1231 group
->addWindow(this);
1239 * Gets the value of the WM_NORMAL_HINTS property.
1240 * If the property is not set, then use a set of default values.
1242 void BlackboxWindow::getWMNormalHints(void) {
1244 XSizeHints sizehint
;
1246 client
.min_width
= client
.min_height
=
1247 client
.width_inc
= client
.height_inc
= 1;
1248 client
.base_width
= client
.base_height
= 0;
1249 client
.win_gravity
= NorthWestGravity
;
1251 client
.min_aspect_x
= client
.min_aspect_y
=
1252 client
.max_aspect_x
= client
.max_aspect_y
= 1;
1255 // don't limit the size of a window, the default max width is the biggest
1257 client
.max_width
= (unsigned) -1;
1258 client
.max_height
= (unsigned) -1;
1261 if (! XGetWMNormalHints(blackbox
->getXDisplay(), client
.window
,
1262 &sizehint
, &icccm_mask
))
1265 client
.normal_hint_flags
= sizehint
.flags
;
1267 if (sizehint
.flags
& PMinSize
) {
1268 if (sizehint
.min_width
>= 0)
1269 client
.min_width
= sizehint
.min_width
;
1270 if (sizehint
.min_height
>= 0)
1271 client
.min_height
= sizehint
.min_height
;
1274 if (sizehint
.flags
& PMaxSize
) {
1275 if (sizehint
.max_width
> static_cast<signed>(client
.min_width
))
1276 client
.max_width
= sizehint
.max_width
;
1278 client
.max_width
= client
.min_width
;
1280 if (sizehint
.max_height
> static_cast<signed>(client
.min_height
))
1281 client
.max_height
= sizehint
.max_height
;
1283 client
.max_height
= client
.min_height
;
1286 if (sizehint
.flags
& PResizeInc
) {
1287 client
.width_inc
= sizehint
.width_inc
;
1288 client
.height_inc
= sizehint
.height_inc
;
1291 #if 0 // we do not support this at the moment
1292 if (sizehint
.flags
& PAspect
) {
1293 client
.min_aspect_x
= sizehint
.min_aspect
.x
;
1294 client
.min_aspect_y
= sizehint
.min_aspect
.y
;
1295 client
.max_aspect_x
= sizehint
.max_aspect
.x
;
1296 client
.max_aspect_y
= sizehint
.max_aspect
.y
;
1300 if (sizehint
.flags
& PBaseSize
) {
1301 client
.base_width
= sizehint
.base_width
;
1302 client
.base_height
= sizehint
.base_height
;
1305 if (sizehint
.flags
& PWinGravity
)
1306 client
.win_gravity
= sizehint
.win_gravity
;
1311 * Gets the NETWM hints for the class' contained window.
1313 void BlackboxWindow::getNetWMHints(void) {
1314 unsigned long workspace
;
1316 if (xatom
->getValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1318 if (workspace
== 0xffffffff)
1321 blackbox_attrib
.workspace
= workspace
;
1324 unsigned long *state
;
1325 unsigned long num
= (unsigned) -1;
1326 if (xatom
->getValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
1330 for (unsigned long i
= 0; i
< num
; ++i
) {
1331 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
))
1333 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_shaded
))
1334 flags
.shaded
= True
;
1335 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
))
1336 flags
.skip_taskbar
= True
;
1337 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_pager
))
1338 flags
.skip_pager
= True
;
1339 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_fullscreen
))
1340 flags
.fullscreen
= True
;
1341 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_hidden
))
1342 setState(IconicState
);
1343 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_vert
))
1345 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_horz
))
1349 flags
.maximized
= 1;
1351 flags
.maximized
= 2;
1353 flags
.maximized
= 3;
1361 * Gets the MWM hints for the class' contained window.
1362 * This is used while initializing the window to its first state, and not
1364 * Returns: true if the MWM hints are successfully retreived and applied;
1365 * false if they are not.
1367 void BlackboxWindow::getMWMHints(void) {
1371 num
= PropMwmHintsElements
;
1372 if (! xatom
->getValue(client
.window
, XAtom::motif_wm_hints
,
1373 XAtom::motif_wm_hints
, num
,
1374 (unsigned long **)&mwm_hint
))
1376 if (num
< PropMwmHintsElements
) {
1381 if (mwm_hint
->flags
& MwmHintsDecorations
) {
1382 if (mwm_hint
->decorations
& MwmDecorAll
) {
1383 mwm_decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
1384 Decor_Iconify
| Decor_Maximize
;
1386 mwm_decorations
= 0;
1388 if (mwm_hint
->decorations
& MwmDecorBorder
)
1389 mwm_decorations
|= Decor_Border
;
1390 if (mwm_hint
->decorations
& MwmDecorHandle
)
1391 mwm_decorations
|= Decor_Handle
;
1392 if (mwm_hint
->decorations
& MwmDecorTitle
)
1393 mwm_decorations
|= Decor_Titlebar
;
1394 if (mwm_hint
->decorations
& MwmDecorIconify
)
1395 mwm_decorations
|= Decor_Iconify
;
1396 if (mwm_hint
->decorations
& MwmDecorMaximize
)
1397 mwm_decorations
|= Decor_Maximize
;
1401 if (mwm_hint
->flags
& MwmHintsFunctions
) {
1402 if (mwm_hint
->functions
& MwmFuncAll
) {
1403 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
|
1408 if (mwm_hint
->functions
& MwmFuncResize
)
1409 functions
|= Func_Resize
;
1410 if (mwm_hint
->functions
& MwmFuncMove
)
1411 functions
|= Func_Move
;
1412 if (mwm_hint
->functions
& MwmFuncIconify
)
1413 functions
|= Func_Iconify
;
1414 if (mwm_hint
->functions
& MwmFuncMaximize
)
1415 functions
|= Func_Maximize
;
1416 if (mwm_hint
->functions
& MwmFuncClose
)
1417 functions
|= Func_Close
;
1425 * Gets the blackbox hints from the class' contained window.
1426 * This is used while initializing the window to its first state, and not
1428 * Returns: true if the hints are successfully retreived and applied; false if
1431 bool BlackboxWindow::getBlackboxHints(void) {
1433 BlackboxHints
*blackbox_hint
;
1435 num
= PropBlackboxHintsElements
;
1436 if (! xatom
->getValue(client
.window
, XAtom::blackbox_hints
,
1437 XAtom::blackbox_hints
, num
,
1438 (unsigned long **)&blackbox_hint
))
1440 if (num
< PropBlackboxHintsElements
) {
1441 delete [] blackbox_hint
;
1445 if (blackbox_hint
->flags
& AttribShaded
)
1446 flags
.shaded
= (blackbox_hint
->attrib
& AttribShaded
);
1448 if ((blackbox_hint
->flags
& AttribMaxHoriz
) &&
1449 (blackbox_hint
->flags
& AttribMaxVert
))
1450 flags
.maximized
= (blackbox_hint
->attrib
&
1451 (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1452 else if (blackbox_hint
->flags
& AttribMaxVert
)
1453 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxVert
) ? 2 : 0;
1454 else if (blackbox_hint
->flags
& AttribMaxHoriz
)
1455 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1457 if (blackbox_hint
->flags
& AttribOmnipresent
)
1458 flags
.stuck
= (blackbox_hint
->attrib
& AttribOmnipresent
);
1460 if (blackbox_hint
->flags
& AttribWorkspace
)
1461 blackbox_attrib
.workspace
= blackbox_hint
->workspace
;
1463 // if (blackbox_hint->flags & AttribStack)
1464 // don't yet have always on top/bottom for blackbox yet... working
1467 if (blackbox_hint
->flags
& AttribDecoration
) {
1468 switch (blackbox_hint
->decoration
) {
1470 blackbox_attrib
.decoration
= DecorNone
;
1477 // blackbox_attrib.decoration defaults to DecorNormal
1482 delete [] blackbox_hint
;
1488 void BlackboxWindow::getTransientInfo(void) {
1489 if (client
.transient_for
&&
1490 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1491 // reset transient_for in preparation of looking for a new owner
1492 client
.transient_for
->client
.transientList
.remove(this);
1495 // we have no transient_for until we find a new one
1496 client
.transient_for
= (BlackboxWindow
*) 0;
1499 if (! XGetTransientForHint(blackbox
->getXDisplay(), client
.window
,
1501 // transient_for hint not set
1505 if (trans_for
== client
.window
) {
1506 // wierd client... treat this window as a normal window
1510 if (trans_for
== None
|| trans_for
== screen
->getRootWindow()) {
1511 // this is an undocumented interpretation of the ICCCM. a transient
1512 // associated with None/Root/itself is assumed to be a modal root
1513 // transient. we don't support the concept of a global transient,
1514 // so we just associate this transient with nothing, and perhaps
1515 // we will add support later for global modality.
1516 client
.transient_for
= (BlackboxWindow
*) ~0ul;
1521 client
.transient_for
= blackbox
->searchWindow(trans_for
);
1522 if (! client
.transient_for
&&
1523 client
.window_group
&& trans_for
== client
.window_group
) {
1524 // no direct transient_for, perhaps this is a group transient?
1525 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1526 if (group
) client
.transient_for
= group
->find(screen
);
1529 if (! client
.transient_for
|| client
.transient_for
== this) {
1530 // no transient_for found, or we have a wierd client that wants to be
1531 // a transient for itself, so we treat this window as a normal window
1532 client
.transient_for
= (BlackboxWindow
*) 0;
1536 // Check for a circular transient state: this can lock up Blackbox
1537 // when it tries to find the non-transient window for a transient.
1538 BlackboxWindow
*w
= this;
1539 while(w
->client
.transient_for
&&
1540 w
->client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1541 if(w
->client
.transient_for
== this) {
1542 client
.transient_for
= (BlackboxWindow
*) 0;
1545 w
= w
->client
.transient_for
;
1548 if (client
.transient_for
&&
1549 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1550 // register ourselves with our new transient_for
1551 client
.transient_for
->client
.transientList
.push_back(this);
1552 flags
.stuck
= client
.transient_for
->flags
.stuck
;
1557 BlackboxWindow
*BlackboxWindow::getTransientFor(void) const {
1558 if (client
.transient_for
&&
1559 client
.transient_for
!= (BlackboxWindow
*) ~0ul)
1560 return client
.transient_for
;
1566 * This function is responsible for updating both the client and the frame
1568 * According to the ICCCM a client message is not sent for a resize, only a
1571 void BlackboxWindow::configure(int dx
, int dy
,
1572 unsigned int dw
, unsigned int dh
) {
1573 bool send_event
= ((frame
.rect
.x() != dx
|| frame
.rect
.y() != dy
) &&
1576 if (dw
!= frame
.rect
.width() || dh
!= frame
.rect
.height()) {
1577 frame
.rect
.setRect(dx
, dy
, dw
, dh
);
1578 frame
.inside_w
= frame
.rect
.width() - (frame
.border_w
* 2);
1579 frame
.inside_h
= frame
.rect
.height() - (frame
.border_w
* 2);
1581 if (frame
.rect
.right() <= 0 || frame
.rect
.bottom() <= 0)
1582 frame
.rect
.setPos(0, 0);
1584 client
.rect
.setCoords(frame
.rect
.left() + frame
.margin
.left
,
1585 frame
.rect
.top() + frame
.margin
.top
,
1586 frame
.rect
.right() - frame
.margin
.right
,
1587 frame
.rect
.bottom() - frame
.margin
.bottom
);
1590 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
1597 redrawWindowFrame();
1599 frame
.rect
.setPos(dx
, dy
);
1601 XMoveWindow(blackbox
->getXDisplay(), frame
.window
,
1602 frame
.rect
.x(), frame
.rect
.y());
1604 we may have been called just after an opaque window move, so even though
1605 the old coords match the new ones no ConfigureNotify has been sent yet.
1606 There are likely other times when this will be relevant as well.
1608 if (! flags
.moving
) send_event
= True
;
1612 // if moving, the update and event will occur when the move finishes
1613 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1614 frame
.rect
.top() + frame
.margin
.top
);
1617 event
.type
= ConfigureNotify
;
1619 event
.xconfigure
.display
= blackbox
->getXDisplay();
1620 event
.xconfigure
.event
= client
.window
;
1621 event
.xconfigure
.window
= client
.window
;
1622 event
.xconfigure
.x
= client
.rect
.x();
1623 event
.xconfigure
.y
= client
.rect
.y();
1624 event
.xconfigure
.width
= client
.rect
.width();
1625 event
.xconfigure
.height
= client
.rect
.height();
1626 event
.xconfigure
.border_width
= client
.old_bw
;
1627 event
.xconfigure
.above
= frame
.window
;
1628 event
.xconfigure
.override_redirect
= False
;
1630 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1631 StructureNotifyMask
, &event
);
1632 screen
->updateNetizenConfigNotify(&event
);
1633 XFlush(blackbox
->getXDisplay());
1639 void BlackboxWindow::configureShape(void) {
1640 XShapeCombineShape(blackbox
->getXDisplay(), frame
.window
, ShapeBounding
,
1641 frame
.margin
.left
- frame
.border_w
,
1642 frame
.margin
.top
- frame
.border_w
,
1643 client
.window
, ShapeBounding
, ShapeSet
);
1646 XRectangle xrect
[2];
1648 if (decorations
& Decor_Titlebar
) {
1649 xrect
[0].x
= xrect
[0].y
= -frame
.border_w
;
1650 xrect
[0].width
= frame
.rect
.width();
1651 xrect
[0].height
= frame
.title_h
+ (frame
.border_w
* 2);
1655 if (decorations
& Decor_Handle
) {
1656 xrect
[1].x
= -frame
.border_w
;
1657 xrect
[1].y
= frame
.rect
.height() - frame
.margin
.bottom
+
1658 frame
.mwm_border_w
- frame
.border_w
;
1659 xrect
[1].width
= frame
.rect
.width();
1660 xrect
[1].height
= frame
.handle_h
+ (frame
.border_w
* 2);
1664 XShapeCombineRectangles(blackbox
->getXDisplay(), frame
.window
,
1665 ShapeBounding
, 0, 0, xrect
, num
,
1666 ShapeUnion
, Unsorted
);
1670 void BlackboxWindow::clearShape(void) {
1671 XShapeCombineMask(blackbox
->getXDisplay(), frame
.window
, ShapeBounding
,
1672 frame
.margin
.left
- frame
.border_w
,
1673 frame
.margin
.top
- frame
.border_w
,
1679 bool BlackboxWindow::setInputFocus(void) {
1680 if (flags
.focused
) return True
;
1682 assert(flags
.stuck
|| // window must be on the current workspace or sticky
1683 blackbox_attrib
.workspace
== screen
->getCurrentWorkspaceID());
1686 We only do this check for normal windows and dialogs because other windows
1687 do this on purpose, such as kde's kicker, and we don't want to go moving
1690 if (window_type
== Type_Normal
|| window_type
== Type_Dialog
)
1691 if (! frame
.rect
.intersects(screen
->getRect())) {
1692 // client is outside the screen, move it to the center
1693 configure((screen
->getWidth() - frame
.rect
.width()) / 2,
1694 (screen
->getHeight() - frame
.rect
.height()) / 2,
1695 frame
.rect
.width(), frame
.rect
.height());
1698 if (client
.transientList
.size() > 0) {
1699 // transfer focus to any modal transients
1700 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1701 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1702 if ((*it
)->flags
.modal
) return (*it
)->setInputFocus();
1706 if (focus_mode
== F_LocallyActive
|| focus_mode
== F_Passive
) {
1707 XSetInputFocus(blackbox
->getXDisplay(), client
.window
,
1708 RevertToPointerRoot
, CurrentTime
);
1710 /* we could set the focus to none, since the window doesn't accept focus,
1711 * but we shouldn't set focus to nothing since this would surely make
1717 if (flags
.send_focus_message
) {
1719 ce
.xclient
.type
= ClientMessage
;
1720 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1721 ce
.xclient
.display
= blackbox
->getXDisplay();
1722 ce
.xclient
.window
= client
.window
;
1723 ce
.xclient
.format
= 32;
1724 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_take_focus
);
1725 ce
.xclient
.data
.l
[1] = blackbox
->getLastTime();
1726 ce
.xclient
.data
.l
[2] = 0l;
1727 ce
.xclient
.data
.l
[3] = 0l;
1728 ce
.xclient
.data
.l
[4] = 0l;
1729 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1731 XFlush(blackbox
->getXDisplay());
1738 void BlackboxWindow::iconify(void) {
1739 if (flags
.iconic
|| ! (functions
& Func_Iconify
)) return;
1741 // We don't need to worry about resizing because resizing always grabs the X
1742 // server. This should only ever happen if using opaque moving.
1746 if (windowmenu
) windowmenu
->hide();
1749 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1750 * we need to clear the event mask on client.window for a split second.
1751 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1752 * split second, leaving us with a ghost window... so, we need to do this
1753 * while the X server is grabbed
1755 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1756 StructureNotifyMask
;
1757 XGrabServer(blackbox
->getXDisplay());
1758 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1759 event_mask
& ~StructureNotifyMask
);
1760 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1761 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1762 XUngrabServer(blackbox
->getXDisplay());
1764 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1765 flags
.visible
= False
;
1766 flags
.iconic
= True
;
1768 setState(IconicState
);
1770 screen
->getWorkspace(blackbox_attrib
.workspace
)->removeWindow(this);
1772 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
1773 if (i
!= blackbox_attrib
.workspace
)
1774 screen
->getWorkspace(i
)->removeWindow(this, True
);
1777 if (isTransient()) {
1778 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1779 ! client
.transient_for
->flags
.iconic
) {
1780 // iconify our transient_for
1781 client
.transient_for
->iconify();
1785 screen
->addIcon(this);
1787 if (client
.transientList
.size() > 0) {
1788 // iconify all transients
1789 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1790 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1791 if (! (*it
)->flags
.iconic
) (*it
)->iconify();
1794 screen
->updateStackingList();
1798 void BlackboxWindow::show(void) {
1799 flags
.visible
= True
;
1800 flags
.iconic
= False
;
1802 current_state
= (flags
.shaded
) ? IconicState
: NormalState
;
1803 setState(current_state
);
1805 XMapWindow(blackbox
->getXDisplay(), client
.window
);
1806 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
1807 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
1812 XTranslateCoordinates(blackbox
->getXDisplay(), client
.window
,
1813 screen
->getRootWindow(),
1814 0, 0, &real_x
, &real_y
, &child
);
1815 fprintf(stderr
, "%s -- assumed: (%d, %d), real: (%d, %d)\n", getTitle(),
1816 client
.rect
.left(), client
.rect
.top(), real_x
, real_y
);
1817 assert(client
.rect
.left() == real_x
&& client
.rect
.top() == real_y
);
1822 void BlackboxWindow::deiconify(bool reassoc
, bool raise
) {
1823 if (flags
.iconic
|| reassoc
)
1824 screen
->reassociateWindow(this, BSENTINEL
, False
);
1825 else if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID())
1830 // reassociate and deiconify all transients
1831 if (reassoc
&& client
.transientList
.size() > 0) {
1832 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1833 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1834 (*it
)->deiconify(True
, False
);
1838 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1842 void BlackboxWindow::close(void) {
1843 if (! (functions
& Func_Close
)) return;
1846 ce
.xclient
.type
= ClientMessage
;
1847 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1848 ce
.xclient
.display
= blackbox
->getXDisplay();
1849 ce
.xclient
.window
= client
.window
;
1850 ce
.xclient
.format
= 32;
1851 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_delete_window
);
1852 ce
.xclient
.data
.l
[1] = CurrentTime
;
1853 ce
.xclient
.data
.l
[2] = 0l;
1854 ce
.xclient
.data
.l
[3] = 0l;
1855 ce
.xclient
.data
.l
[4] = 0l;
1856 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
, NoEventMask
, &ce
);
1857 XFlush(blackbox
->getXDisplay());
1861 void BlackboxWindow::withdraw(void) {
1862 // We don't need to worry about resizing because resizing always grabs the X
1863 // server. This should only ever happen if using opaque moving.
1867 flags
.visible
= False
;
1868 flags
.iconic
= False
;
1870 setState(current_state
);
1872 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1874 XGrabServer(blackbox
->getXDisplay());
1876 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1877 StructureNotifyMask
;
1878 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1879 event_mask
& ~StructureNotifyMask
);
1880 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1881 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1883 XUngrabServer(blackbox
->getXDisplay());
1885 if (windowmenu
) windowmenu
->hide();
1889 void BlackboxWindow::maximize(unsigned int button
) {
1890 if (! (functions
& Func_Maximize
)) return;
1892 // We don't need to worry about resizing because resizing always grabs the X
1893 // server. This should only ever happen if using opaque moving.
1897 // handle case where menu is open then the max button is used instead
1898 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
1900 if (flags
.maximized
) {
1901 flags
.maximized
= 0;
1903 blackbox_attrib
.flags
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1904 blackbox_attrib
.attrib
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1907 when a resize finishes, maximize(0) is called to clear any maximization
1908 flags currently set. Otherwise it still thinks it is maximized.
1909 so we do not need to call configure() because resizing will handle it
1911 if (! flags
.resizing
)
1912 configure(blackbox_attrib
.premax_x
, blackbox_attrib
.premax_y
,
1913 blackbox_attrib
.premax_w
, blackbox_attrib
.premax_h
);
1915 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
1916 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
1918 redrawAllButtons(); // in case it is not called in configure()
1919 setState(current_state
);
1923 blackbox_attrib
.premax_x
= frame
.rect
.x();
1924 blackbox_attrib
.premax_y
= frame
.rect
.y();
1925 blackbox_attrib
.premax_w
= frame
.rect
.width();
1926 // use client.rect so that clients can be restored even if shaded
1927 blackbox_attrib
.premax_h
=
1928 client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
;
1931 if (screen
->isXineramaActive() && blackbox
->doXineramaMaximizing()) {
1932 // find the area to use
1933 RectList availableAreas
= screen
->allAvailableAreas();
1934 RectList::iterator it
, end
= availableAreas
.end();
1936 for (it
= availableAreas
.begin(); it
!= end
; ++it
)
1937 if (it
->intersects(frame
.rect
)) break;
1938 if (it
== end
) // the window isn't inside an area
1939 it
= availableAreas
.begin(); // so just default to the first one
1941 frame
.changing
= *it
;
1944 frame
.changing
= screen
->availableArea();
1948 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1949 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1953 blackbox_attrib
.flags
|= AttribMaxVert
;
1954 blackbox_attrib
.attrib
|= AttribMaxVert
;
1956 frame
.changing
.setX(frame
.rect
.x());
1957 frame
.changing
.setWidth(frame
.rect
.width());
1961 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1962 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1964 frame
.changing
.setY(frame
.rect
.y());
1965 frame
.changing
.setHeight(frame
.rect
.height());
1972 blackbox_attrib
.flags
^= AttribShaded
;
1973 blackbox_attrib
.attrib
^= AttribShaded
;
1974 flags
.shaded
= False
;
1977 flags
.maximized
= button
;
1979 configure(frame
.changing
.x(), frame
.changing
.y(),
1980 frame
.changing
.width(), frame
.changing
.height());
1982 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1983 redrawAllButtons(); // in case it is not called in configure()
1984 setState(current_state
);
1988 // re-maximizes the window to take into account availableArea changes
1989 void BlackboxWindow::remaximize(void) {
1991 // we only update the window's attributes otherwise we lose the shade bit
1992 switch(flags
.maximized
) {
1994 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1995 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1999 blackbox_attrib
.flags
|= AttribMaxVert
;
2000 blackbox_attrib
.attrib
|= AttribMaxVert
;
2004 blackbox_attrib
.flags
|= AttribMaxHoriz
;
2005 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
2011 // save the original dimensions because maximize will wipe them out
2012 int premax_x
= blackbox_attrib
.premax_x
,
2013 premax_y
= blackbox_attrib
.premax_y
,
2014 premax_w
= blackbox_attrib
.premax_w
,
2015 premax_h
= blackbox_attrib
.premax_h
;
2017 unsigned int button
= flags
.maximized
;
2018 flags
.maximized
= 0; // trick maximize() into working
2021 // restore saved values
2022 blackbox_attrib
.premax_x
= premax_x
;
2023 blackbox_attrib
.premax_y
= premax_y
;
2024 blackbox_attrib
.premax_w
= premax_w
;
2025 blackbox_attrib
.premax_h
= premax_h
;
2029 void BlackboxWindow::setWorkspace(unsigned int n
) {
2030 blackbox_attrib
.flags
|= AttribWorkspace
;
2031 blackbox_attrib
.workspace
= n
;
2032 if (n
== BSENTINEL
) { // iconified window
2034 we set the workspace to 'all workspaces' so that taskbars will show the
2035 window. otherwise, it made uniconifying a window imposible without the
2036 blackbox workspace menu
2040 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
, n
);
2044 void BlackboxWindow::shade(void) {
2046 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
2047 frame
.inside_w
, frame
.inside_h
);
2048 flags
.shaded
= False
;
2049 blackbox_attrib
.flags
^= AttribShaded
;
2050 blackbox_attrib
.attrib
^= AttribShaded
;
2052 setState(NormalState
);
2054 // set the frame rect to the normal size
2055 frame
.rect
.setHeight(client
.rect
.height() + frame
.margin
.top
+
2056 frame
.margin
.bottom
);
2058 if (! (decorations
& Decor_Titlebar
))
2059 return; // can't shade it without a titlebar!
2061 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
2062 frame
.inside_w
, frame
.title_h
);
2063 flags
.shaded
= True
;
2064 blackbox_attrib
.flags
|= AttribShaded
;
2065 blackbox_attrib
.attrib
|= AttribShaded
;
2067 setState(IconicState
);
2069 // set the frame rect to the shaded size
2070 frame
.rect
.setHeight(frame
.title_h
+ (frame
.border_w
* 2));
2076 * (Un)Sticks a window and its relatives.
2078 void BlackboxWindow::stick(void) {
2080 blackbox_attrib
.flags
^= AttribOmnipresent
;
2081 blackbox_attrib
.attrib
^= AttribOmnipresent
;
2083 flags
.stuck
= False
;
2085 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
2086 if (i
!= blackbox_attrib
.workspace
)
2087 screen
->getWorkspace(i
)->removeWindow(this, True
);
2090 screen
->reassociateWindow(this, BSENTINEL
, True
);
2091 // temporary fix since sticky windows suck. set the hint to what we
2092 // actually hold in our data.
2093 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
2094 blackbox_attrib
.workspace
);
2096 setState(current_state
);
2100 blackbox_attrib
.flags
|= AttribOmnipresent
;
2101 blackbox_attrib
.attrib
|= AttribOmnipresent
;
2103 // temporary fix since sticky windows suck. set the hint to a different
2104 // value than that contained in the class' data.
2105 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
2108 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
2109 if (i
!= blackbox_attrib
.workspace
)
2110 screen
->getWorkspace(i
)->addWindow(this, False
, True
);
2112 setState(current_state
);
2118 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
2119 client
.transient_for
->isStuck() != flags
.stuck
)
2120 client
.transient_for
->stick();
2121 // go down the chain
2122 BlackboxWindowList::iterator it
;
2123 const BlackboxWindowList::iterator end
= client
.transientList
.end();
2124 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
2125 if ((*it
)->isStuck() != flags
.stuck
)
2130 void BlackboxWindow::redrawWindowFrame(void) const {
2131 if (decorations
& Decor_Titlebar
) {
2132 if (flags
.focused
) {
2134 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2135 frame
.title
, frame
.ftitle
);
2137 XSetWindowBackground(blackbox
->getXDisplay(),
2138 frame
.title
, frame
.ftitle_pixel
);
2141 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2142 frame
.title
, frame
.utitle
);
2144 XSetWindowBackground(blackbox
->getXDisplay(),
2145 frame
.title
, frame
.utitle_pixel
);
2147 XClearWindow(blackbox
->getXDisplay(), frame
.title
);
2153 if (decorations
& Decor_Handle
) {
2154 if (flags
.focused
) {
2156 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2157 frame
.handle
, frame
.fhandle
);
2159 XSetWindowBackground(blackbox
->getXDisplay(),
2160 frame
.handle
, frame
.fhandle_pixel
);
2163 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2164 frame
.left_grip
, frame
.fgrip
);
2165 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2166 frame
.right_grip
, frame
.fgrip
);
2168 XSetWindowBackground(blackbox
->getXDisplay(),
2169 frame
.left_grip
, frame
.fgrip_pixel
);
2170 XSetWindowBackground(blackbox
->getXDisplay(),
2171 frame
.right_grip
, frame
.fgrip_pixel
);
2175 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2176 frame
.handle
, frame
.uhandle
);
2178 XSetWindowBackground(blackbox
->getXDisplay(),
2179 frame
.handle
, frame
.uhandle_pixel
);
2182 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2183 frame
.left_grip
, frame
.ugrip
);
2184 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2185 frame
.right_grip
, frame
.ugrip
);
2187 XSetWindowBackground(blackbox
->getXDisplay(),
2188 frame
.left_grip
, frame
.ugrip_pixel
);
2189 XSetWindowBackground(blackbox
->getXDisplay(),
2190 frame
.right_grip
, frame
.ugrip_pixel
);
2193 XClearWindow(blackbox
->getXDisplay(), frame
.handle
);
2194 XClearWindow(blackbox
->getXDisplay(), frame
.left_grip
);
2195 XClearWindow(blackbox
->getXDisplay(), frame
.right_grip
);
2198 if (decorations
& Decor_Border
) {
2200 XSetWindowBorder(blackbox
->getXDisplay(),
2201 frame
.plate
, frame
.fborder_pixel
);
2203 XSetWindowBorder(blackbox
->getXDisplay(),
2204 frame
.plate
, frame
.uborder_pixel
);
2209 void BlackboxWindow::setFocusFlag(bool focus
) {
2210 // only focus a window if it is visible
2211 if (focus
&& ! flags
.visible
)
2214 flags
.focused
= focus
;
2216 redrawWindowFrame();
2219 blackbox
->setFocusedWindow(this);
2221 if (! flags
.iconic
) {
2222 // iconic windows arent in a workspace menu!
2224 screen
->getCurrentWorkspace()->setFocused(this, isFocused());
2226 screen
->getWorkspace(blackbox_attrib
.workspace
)->
2227 setFocused(this, flags
.focused
);
2232 void BlackboxWindow::installColormap(bool install
) {
2233 int i
= 0, ncmap
= 0;
2234 Colormap
*cmaps
= XListInstalledColormaps(blackbox
->getXDisplay(),
2235 client
.window
, &ncmap
);
2237 XWindowAttributes wattrib
;
2238 if (XGetWindowAttributes(blackbox
->getXDisplay(),
2239 client
.window
, &wattrib
)) {
2241 // install the window's colormap
2242 for (i
= 0; i
< ncmap
; i
++) {
2243 if (*(cmaps
+ i
) == wattrib
.colormap
)
2244 // this window is using an installed color map... do not install
2247 // otherwise, install the window's colormap
2249 XInstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2251 // uninstall the window's colormap
2252 for (i
= 0; i
< ncmap
; i
++) {
2253 if (*(cmaps
+ i
) == wattrib
.colormap
)
2254 // we found the colormap to uninstall
2255 XUninstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2265 void BlackboxWindow::setAllowedActions(void) {
2269 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_shade
);
2270 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_change_desktop
);
2271 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_close
);
2273 if (functions
& Func_Move
)
2274 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_move
);
2275 if (functions
& Func_Resize
)
2276 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_resize
);
2277 if (functions
& Func_Maximize
) {
2278 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_horz
);
2279 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_vert
);
2282 xatom
->setValue(client
.window
, XAtom::net_wm_allowed_actions
, XAtom::atom
,
2287 void BlackboxWindow::setState(unsigned long new_state
) {
2288 current_state
= new_state
;
2290 unsigned long state
[2];
2291 state
[0] = current_state
;
2293 xatom
->setValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
, state
, 2);
2295 xatom
->setValue(client
.window
, XAtom::blackbox_attributes
,
2296 XAtom::blackbox_attributes
, (unsigned long *)&blackbox_attrib
,
2297 PropBlackboxAttributesElements
);
2302 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_modal
);
2304 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_shaded
);
2306 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_hidden
);
2307 if (flags
.skip_taskbar
)
2308 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
);
2309 if (flags
.skip_pager
)
2310 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_pager
);
2311 if (flags
.fullscreen
)
2312 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_fullscreen
);
2313 if (flags
.maximized
== 1 || flags
.maximized
== 2)
2314 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_vert
);
2315 if (flags
.maximized
== 1 || flags
.maximized
== 3)
2316 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_horz
);
2317 xatom
->setValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
2322 bool BlackboxWindow::getState(void) {
2323 bool ret
= xatom
->getValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
,
2325 if (! ret
) current_state
= 0;
2330 void BlackboxWindow::restoreAttributes(void) {
2331 unsigned long num
= PropBlackboxAttributesElements
;
2332 BlackboxAttributes
*net
;
2333 if (! xatom
->getValue(client
.window
, XAtom::blackbox_attributes
,
2334 XAtom::blackbox_attributes
, num
,
2335 (unsigned long **)&net
))
2337 if (num
< PropBlackboxAttributesElements
) {
2342 if (net
->flags
& AttribShaded
&& net
->attrib
& AttribShaded
) {
2343 flags
.shaded
= False
;
2344 unsigned long orig_state
= current_state
;
2348 At this point in the life of a window, current_state should only be set
2349 to IconicState if the window was an *icon*, not if it was shaded.
2351 if (orig_state
!= IconicState
)
2352 current_state
= WithdrawnState
;
2355 if (net
->workspace
!= screen
->getCurrentWorkspaceID() &&
2356 net
->workspace
< screen
->getWorkspaceCount())
2357 screen
->reassociateWindow(this, net
->workspace
, True
);
2359 if ((blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID()) &&
2360 (blackbox_attrib
.workspace
< screen
->getWorkspaceCount())) {
2361 // set to WithdrawnState so it will be mapped on the new workspace
2362 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2363 } else if (current_state
== WithdrawnState
) {
2364 // the window is on this workspace and is Withdrawn, so it is waiting to
2366 current_state
= NormalState
;
2369 if (net
->flags
& AttribOmnipresent
&& net
->attrib
& AttribOmnipresent
&&
2373 // if the window was on another workspace, it was going to be hidden. this
2374 // specifies that the window should be mapped since it is sticky.
2375 if (current_state
== WithdrawnState
) current_state
= NormalState
;
2378 if (net
->flags
& AttribMaxHoriz
|| net
->flags
& AttribMaxVert
) {
2379 int x
= net
->premax_x
, y
= net
->premax_y
;
2380 unsigned int w
= net
->premax_w
, h
= net
->premax_h
;
2381 flags
.maximized
= 0;
2384 if ((net
->flags
& AttribMaxHoriz
) &&
2385 (net
->flags
& AttribMaxVert
))
2386 m
= (net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
2387 else if (net
->flags
& AttribMaxVert
)
2388 m
= (net
->attrib
& AttribMaxVert
) ? 2 : 0;
2389 else if (net
->flags
& AttribMaxHoriz
)
2390 m
= (net
->attrib
& AttribMaxHoriz
) ? 3 : 0;
2394 blackbox_attrib
.premax_x
= x
;
2395 blackbox_attrib
.premax_y
= y
;
2396 blackbox_attrib
.premax_w
= w
;
2397 blackbox_attrib
.premax_h
= h
;
2400 if (net
->flags
& AttribDecoration
) {
2401 switch (net
->decoration
) {
2406 /* since tools only let you toggle this anyways, we'll just make that all
2407 it supports for now.
2418 // with the state set it will then be the map event's job to read the
2419 // window's state and behave accordingly
2426 * Positions the Rect r according the the client window position and
2429 void BlackboxWindow::applyGravity(Rect
&r
) {
2430 // apply horizontal window gravity
2431 switch (client
.win_gravity
) {
2433 case NorthWestGravity
:
2434 case SouthWestGravity
:
2436 r
.setX(client
.rect
.x());
2442 r
.setX(client
.rect
.x() - (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2445 case NorthEastGravity
:
2446 case SouthEastGravity
:
2448 r
.setX(client
.rect
.x() - frame
.margin
.left
- frame
.margin
.right
+ 2);
2453 r
.setX(client
.rect
.x() - frame
.margin
.left
);
2457 // apply vertical window gravity
2458 switch (client
.win_gravity
) {
2460 case NorthWestGravity
:
2461 case NorthEastGravity
:
2463 r
.setY(client
.rect
.y());
2469 r
.setY(client
.rect
.y() - (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2472 case SouthWestGravity
:
2473 case SouthEastGravity
:
2475 r
.setY(client
.rect
.y() - frame
.margin
.top
- frame
.margin
.bottom
+ 2);
2480 r
.setY(client
.rect
.y() - frame
.margin
.top
);
2487 * The reverse of the applyGravity function.
2489 * Positions the Rect r according to the frame window position and
2492 void BlackboxWindow::restoreGravity(Rect
&r
) {
2493 // restore horizontal window gravity
2494 switch (client
.win_gravity
) {
2496 case NorthWestGravity
:
2497 case SouthWestGravity
:
2499 r
.setX(frame
.rect
.x());
2505 r
.setX(frame
.rect
.x() + (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2508 case NorthEastGravity
:
2509 case SouthEastGravity
:
2511 r
.setX(frame
.rect
.x() + frame
.margin
.left
+ frame
.margin
.right
- 2);
2516 r
.setX(frame
.rect
.x() + frame
.margin
.left
);
2520 // restore vertical window gravity
2521 switch (client
.win_gravity
) {
2523 case NorthWestGravity
:
2524 case NorthEastGravity
:
2526 r
.setY(frame
.rect
.y());
2532 r
.setY(frame
.rect
.y() + (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2535 case SouthWestGravity
:
2536 case SouthEastGravity
:
2538 r
.setY(frame
.rect
.y() + frame
.margin
.top
+ frame
.margin
.bottom
- 2);
2543 r
.setY(frame
.rect
.y() + frame
.margin
.top
);
2549 void BlackboxWindow::redrawLabel(void) const {
2550 if (flags
.focused
) {
2552 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2553 frame
.label
, frame
.flabel
);
2555 XSetWindowBackground(blackbox
->getXDisplay(),
2556 frame
.label
, frame
.flabel_pixel
);
2559 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2560 frame
.label
, frame
.ulabel
);
2562 XSetWindowBackground(blackbox
->getXDisplay(),
2563 frame
.label
, frame
.ulabel_pixel
);
2565 XClearWindow(blackbox
->getXDisplay(), frame
.label
);
2567 WindowStyle
*style
= screen
->getWindowStyle();
2569 int pos
= frame
.bevel_w
* 2;
2570 style
->doJustify(client
.title
.c_str(), pos
, frame
.label_w
, frame
.bevel_w
* 4);
2571 style
->font
->drawString(frame
.label
, pos
, 1,
2572 (flags
.focused
? style
->l_text_focus
:
2573 style
->l_text_unfocus
),
2578 void BlackboxWindow::redrawAllButtons(void) const {
2579 if (frame
.iconify_button
) redrawIconifyButton(False
);
2580 if (frame
.maximize_button
) redrawMaximizeButton(flags
.maximized
);
2581 if (frame
.close_button
) redrawCloseButton(False
);
2582 if (frame
.stick_button
) redrawStickyButton(flags
.stuck
);
2586 void BlackboxWindow::redrawIconifyButton(bool pressed
) const {
2588 if (flags
.focused
) {
2590 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2591 frame
.iconify_button
, frame
.fbutton
);
2593 XSetWindowBackground(blackbox
->getXDisplay(),
2594 frame
.iconify_button
, frame
.fbutton_pixel
);
2597 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2598 frame
.iconify_button
, frame
.ubutton
);
2600 XSetWindowBackground(blackbox
->getXDisplay(), frame
.iconify_button
,
2601 frame
.ubutton_pixel
);
2605 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2606 frame
.iconify_button
, frame
.pbutton
);
2608 XSetWindowBackground(blackbox
->getXDisplay(),
2609 frame
.iconify_button
, frame
.pbutton_pixel
);
2611 XClearWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
2613 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2614 screen
->getWindowStyle()->b_pic_unfocus
);
2615 XDrawRectangle(blackbox
->getXDisplay(), frame
.iconify_button
, pen
.gc(),
2616 2, (frame
.button_w
- 5), (frame
.button_w
- 5), 2);
2620 void BlackboxWindow::redrawMaximizeButton(bool pressed
) const {
2622 if (flags
.focused
) {
2624 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2625 frame
.maximize_button
, frame
.fbutton
);
2627 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2628 frame
.fbutton_pixel
);
2631 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2632 frame
.maximize_button
, frame
.ubutton
);
2634 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2635 frame
.ubutton_pixel
);
2639 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2640 frame
.maximize_button
, frame
.pbutton
);
2642 XSetWindowBackground(blackbox
->getXDisplay(), frame
.maximize_button
,
2643 frame
.pbutton_pixel
);
2645 XClearWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
2647 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2648 screen
->getWindowStyle()->b_pic_unfocus
);
2649 XDrawRectangle(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2650 2, 2, (frame
.button_w
- 5), (frame
.button_w
- 5));
2651 XDrawLine(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2652 2, 3, (frame
.button_w
- 3), 3);
2656 void BlackboxWindow::redrawCloseButton(bool pressed
) const {
2658 if (flags
.focused
) {
2660 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2663 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2664 frame
.fbutton_pixel
);
2667 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), frame
.close_button
,
2670 XSetWindowBackground(blackbox
->getXDisplay(), frame
.close_button
,
2671 frame
.ubutton_pixel
);
2675 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2676 frame
.close_button
, frame
.pbutton
);
2678 XSetWindowBackground(blackbox
->getXDisplay(),
2679 frame
.close_button
, frame
.pbutton_pixel
);
2681 XClearWindow(blackbox
->getXDisplay(), frame
.close_button
);
2683 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2684 screen
->getWindowStyle()->b_pic_unfocus
, 0, 2);
2685 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2686 2, 2, (frame
.button_w
- 3), (frame
.button_w
- 3));
2687 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2688 2, (frame
.button_w
- 3), (frame
.button_w
- 3), 2);
2692 void BlackboxWindow::redrawStickyButton(bool pressed
) const {
2694 if (flags
.focused
) {
2696 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2697 frame
.stick_button
, frame
.fbutton
);
2699 XSetWindowBackground(blackbox
->getXDisplay(), frame
.stick_button
,
2700 frame
.fbutton_pixel
);
2703 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2704 frame
.stick_button
, frame
.ubutton
);
2706 XSetWindowBackground(blackbox
->getXDisplay(), frame
.stick_button
,
2707 frame
.ubutton_pixel
);
2711 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2712 frame
.stick_button
, frame
.pbutton
);
2714 XSetWindowBackground(blackbox
->getXDisplay(), frame
.stick_button
,
2715 frame
.pbutton_pixel
);
2717 XClearWindow(blackbox
->getXDisplay(), frame
.stick_button
);
2719 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2720 screen
->getWindowStyle()->b_pic_unfocus
);
2722 XFillRectangle(blackbox
->getXDisplay(), frame
.stick_button
, pen
.gc(),
2723 frame
.button_w
/2 - 1, frame
.button_w
/2 -1, 2, 2 );
2726 void BlackboxWindow::mapRequestEvent(const XMapRequestEvent
*re
) {
2727 if (re
->window
!= client
.window
)
2731 fprintf(stderr
, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2736 Even though the window wants to be shown, if it is not on the current
2737 workspace, then it isn't going to be shown right now.
2739 if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID() &&
2740 blackbox_attrib
.workspace
< screen
->getWorkspaceCount())
2741 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2743 switch (current_state
) {
2748 case WithdrawnState
:
2757 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2759 if (! blackbox
->isStartup()) {
2760 XSync(blackbox
->getXDisplay(), False
); // make sure the frame is mapped
2761 if (screen
->doFocusNew() || (isTransient() && getTransientFor() &&
2762 getTransientFor()->isFocused())) {
2765 if (screen
->getPlacementPolicy() == BScreen::ClickMousePlacement
) {
2769 XQueryPointer(blackbox
->getXDisplay(), screen
->getRootWindow(),
2770 &r
, &c
, &rx
, &ry
, &x
, &y
, &m
);
2780 void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent
*ue
) {
2781 if (ue
->window
!= client
.window
)
2785 fprintf(stderr
, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2789 screen
->unmanageWindow(this, False
);
2793 void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent
*de
) {
2794 if (de
->window
!= client
.window
)
2798 fprintf(stderr
, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2802 screen
->unmanageWindow(this, False
);
2806 void BlackboxWindow::reparentNotifyEvent(const XReparentEvent
*re
) {
2807 if (re
->window
!= client
.window
|| re
->parent
== frame
.plate
)
2811 fprintf(stderr
, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2812 "0x%lx.\n", client
.window
, re
->parent
);
2817 XPutBackEvent(blackbox
->getXDisplay(), &ev
);
2818 screen
->unmanageWindow(this, True
);
2822 void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent
*pe
) {
2823 if (pe
->state
== PropertyDelete
|| ! validateClient())
2827 fprintf(stderr
, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n",
2833 case XA_WM_CLIENT_MACHINE
:
2837 case XA_WM_TRANSIENT_FOR
: {
2838 bool s
= flags
.stuck
;
2840 // determine if this is a transient window
2843 if (flags
.stuck
!= s
) stick();
2845 // adjust the window decorations based on transience
2846 if (isTransient()) {
2847 functions
&= ~Func_Maximize
;
2848 setAllowedActions();
2860 case XA_WM_ICON_NAME
:
2862 if (flags
.iconic
) screen
->propagateWindowName(this);
2865 case XAtom::net_wm_name
:
2869 if (decorations
& Decor_Titlebar
)
2872 screen
->propagateWindowName(this);
2875 case XA_WM_NORMAL_HINTS
: {
2878 if ((client
.normal_hint_flags
& PMinSize
) &&
2879 (client
.normal_hint_flags
& PMaxSize
)) {
2880 // the window now can/can't resize itself, so the buttons need to be
2883 if (client
.max_width
<= client
.min_width
&&
2884 client
.max_height
<= client
.min_height
) {
2885 functions
&= ~(Func_Resize
| Func_Maximize
);
2887 if (! isTransient())
2888 functions
|= Func_Maximize
;
2889 functions
|= Func_Resize
;
2892 setAllowedActions();
2896 Rect old_rect
= frame
.rect
;
2900 if (old_rect
!= frame
.rect
)
2907 if (pe
->atom
== xatom
->getAtom(XAtom::wm_protocols
)) {
2910 if ((decorations
& Decor_Close
) && (! frame
.close_button
)) {
2911 createCloseButton();
2912 if (decorations
& Decor_Titlebar
) {
2913 positionButtons(True
);
2914 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
2916 if (windowmenu
) windowmenu
->reconfigure();
2918 } else if (pe
->atom
== xatom
->getAtom(XAtom::net_wm_strut
)) {
2927 void BlackboxWindow::exposeEvent(const XExposeEvent
*ee
) {
2929 fprintf(stderr
, "BlackboxWindow::exposeEvent() for 0x%lx\n", client
.window
);
2932 if (frame
.label
== ee
->window
&& (decorations
& Decor_Titlebar
))
2934 else if (frame
.close_button
== ee
->window
)
2935 redrawCloseButton(False
);
2936 else if (frame
.maximize_button
== ee
->window
)
2937 redrawMaximizeButton(flags
.maximized
);
2938 else if (frame
.iconify_button
== ee
->window
)
2939 redrawIconifyButton(False
);
2940 else if (frame
.stick_button
== ee
->window
)
2941 redrawStickyButton(flags
.stuck
);
2945 void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent
*cr
) {
2946 if (cr
->window
!= client
.window
|| flags
.iconic
)
2949 if (cr
->value_mask
& CWBorderWidth
)
2950 client
.old_bw
= cr
->border_width
;
2952 if (cr
->value_mask
& (CWX
| CWY
| CWWidth
| CWHeight
)) {
2953 frame
.changing
= frame
.rect
;
2955 if (cr
->value_mask
& (CWX
| CWY
)) {
2956 if (cr
->value_mask
& CWX
)
2957 client
.rect
.setX(cr
->x
);
2958 if (cr
->value_mask
& CWY
)
2959 client
.rect
.setY(cr
->y
);
2961 applyGravity(frame
.changing
);
2964 if (cr
->value_mask
& (CWWidth
| CWHeight
)) {
2965 if (cr
->value_mask
& CWWidth
)
2966 frame
.changing
.setWidth(cr
->width
+
2967 frame
.margin
.left
+ frame
.margin
.right
);
2969 if (cr
->value_mask
& CWHeight
)
2970 frame
.changing
.setHeight(cr
->height
+
2971 frame
.margin
.top
+ frame
.margin
.bottom
);
2974 if a position change has been specified, then that position will be
2975 used instead of determining a position based on the window's gravity.
2977 if (! (cr
->value_mask
& (CWX
| CWY
))) {
2979 switch (client
.win_gravity
) {
2980 case NorthEastGravity
:
2984 case SouthWestGravity
:
2986 corner
= BottomLeft
;
2988 case SouthEastGravity
:
2989 corner
= BottomRight
;
2991 default: // NorthWest, Static, etc
2998 configure(frame
.changing
.x(), frame
.changing
.y(),
2999 frame
.changing
.width(), frame
.changing
.height());
3002 if (cr
->value_mask
& CWStackMode
&& !isDesktop()) {
3003 switch (cr
->detail
) {
3006 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
3012 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3019 void BlackboxWindow::buttonPressEvent(const XButtonEvent
*be
) {
3021 fprintf(stderr
, "BlackboxWindow::buttonPressEvent() for 0x%lx\n",
3025 if (frame
.maximize_button
== be
->window
&& be
->button
<= 3) {
3026 redrawMaximizeButton(True
);
3027 } else if (be
->button
== 1 || (be
->button
== 3 && be
->state
== mod_mask
)) {
3028 if (! flags
.focused
)
3031 if (frame
.iconify_button
== be
->window
) {
3032 redrawIconifyButton(True
);
3033 } else if (frame
.close_button
== be
->window
) {
3034 redrawCloseButton(True
);
3035 } else if (frame
.stick_button
== be
->window
) {
3036 redrawStickyButton(True
);
3037 } else if (frame
.plate
== be
->window
) {
3038 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
3040 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3042 XAllowEvents(blackbox
->getXDisplay(), ReplayPointer
, be
->time
);
3044 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
3045 if (((be
->time
- lastButtonPressTime
) <=
3046 blackbox
->getDoubleClickInterval()) ||
3047 (be
->state
== ControlMask
)) {
3048 lastButtonPressTime
= 0;
3051 lastButtonPressTime
= be
->time
;
3055 if (windowmenu
&& windowmenu
->isVisible()) windowmenu
->hide();
3057 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3059 } else if (be
->button
== 2 && (be
->window
!= frame
.iconify_button
) &&
3060 (be
->window
!= frame
.close_button
) &&
3061 (be
->window
!= frame
.stick_button
)) {
3062 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
3063 } else if (windowmenu
&& be
->button
== 3 &&
3064 (frame
.title
== be
->window
|| frame
.label
== be
->window
||
3065 frame
.handle
== be
->window
|| frame
.window
== be
->window
)) {
3066 if (windowmenu
->isVisible()) {
3069 int mx
= be
->x_root
- windowmenu
->getWidth() / 2,
3070 my
= be
->y_root
- windowmenu
->getHeight() / 2;
3072 // snap the window menu into a corner/side if necessary
3073 int left_edge
, right_edge
, top_edge
, bottom_edge
;
3076 the " + (frame.border_w * 2) - 1" bits are to get the proper width
3077 and height of the menu, as the sizes returned by it do not include
3080 left_edge
= frame
.rect
.x();
3081 right_edge
= frame
.rect
.right() -
3082 (windowmenu
->getWidth() + (frame
.border_w
* 2) - 1);
3083 top_edge
= client
.rect
.top() - (frame
.border_w
+ frame
.mwm_border_w
);
3084 bottom_edge
= client
.rect
.bottom() -
3085 (windowmenu
->getHeight() + (frame
.border_w
* 2) - 1) +
3086 (frame
.border_w
+ frame
.mwm_border_w
);
3090 if (mx
> right_edge
)
3094 if (my
> bottom_edge
)
3097 windowmenu
->move(mx
, my
);
3099 XRaiseWindow(blackbox
->getXDisplay(), windowmenu
->getWindowID());
3100 XRaiseWindow(blackbox
->getXDisplay(),
3101 windowmenu
->getSendToMenu()->getWindowID());
3104 } else if (be
->button
== 4) {
3105 if ((be
->window
== frame
.label
||
3106 be
->window
== frame
.title
||
3107 be
->window
== frame
.maximize_button
||
3108 be
->window
== frame
.iconify_button
||
3109 be
->window
== frame
.close_button
||
3110 be
->window
== frame
.stick_button
) &&
3114 } else if (be
->button
== 5) {
3115 if ((be
->window
== frame
.label
||
3116 be
->window
== frame
.title
||
3117 be
->window
== frame
.maximize_button
||
3118 be
->window
== frame
.iconify_button
||
3119 be
->window
== frame
.close_button
||
3120 be
->window
== frame
.stick_button
) &&
3127 void BlackboxWindow::buttonReleaseEvent(const XButtonEvent
*re
) {
3129 fprintf(stderr
, "BlackboxWindow::buttonReleaseEvent() for 0x%lx\n",
3133 if (re
->window
== frame
.maximize_button
&&
3134 re
->button
>= 1 && re
->button
<= 3) {
3135 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3136 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
3137 maximize(re
->button
);
3139 redrawMaximizeButton(flags
.maximized
);
3141 } else if (re
->window
== frame
.iconify_button
&& re
->button
== 1) {
3142 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3143 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
3146 redrawIconifyButton(False
);
3148 } else if (re
->window
== frame
.stick_button
&& re
->button
== 1) {
3149 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3150 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
3153 redrawStickyButton(False
);
3155 } else if (re
->window
== frame
.close_button
& re
->button
== 1) {
3156 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3157 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
)))
3159 redrawCloseButton(False
);
3160 } else if (flags
.moving
) {
3162 } else if (flags
.resizing
) {
3164 } else if (re
->window
== frame
.window
) {
3165 if (re
->button
== 2 && re
->state
== mod_mask
)
3166 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3172 void BlackboxWindow::beginMove(int x_root
, int y_root
) {
3173 if (! (functions
& Func_Move
)) return;
3175 assert(! (flags
.resizing
|| flags
.moving
));
3178 Only one window can be moved/resized at a time. If another window is already
3179 being moved or resized, then stop it before whating to work with this one.
3181 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3182 if (changing
&& changing
!= this) {
3183 if (changing
->flags
.moving
)
3184 changing
->endMove();
3185 else // if (changing->flags.resizing)
3186 changing
->endResize();
3189 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3190 PointerMotionMask
| ButtonReleaseMask
,
3191 GrabModeAsync
, GrabModeAsync
,
3192 None
, blackbox
->getMoveCursor(), CurrentTime
);
3194 if (windowmenu
&& windowmenu
->isVisible())
3197 flags
.moving
= True
;
3198 blackbox
->setChangingWindow(this);
3200 if (! screen
->doOpaqueMove()) {
3201 XGrabServer(blackbox
->getXDisplay());
3203 frame
.changing
= frame
.rect
;
3204 screen
->showPosition(frame
.changing
.x(), frame
.changing
.y());
3206 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3210 frame
.changing
.width() - 1,
3211 frame
.changing
.height() - 1);
3214 frame
.grab_x
= x_root
- frame
.rect
.x() - frame
.border_w
;
3215 frame
.grab_y
= y_root
- frame
.rect
.y() - frame
.border_w
;
3219 void BlackboxWindow::doMove(int x_root
, int y_root
) {
3220 assert(flags
.moving
);
3221 assert(blackbox
->getChangingWindow() == this);
3223 int dx
= x_root
- frame
.grab_x
, dy
= y_root
- frame
.grab_y
;
3224 dx
-= frame
.border_w
;
3225 dy
-= frame
.border_w
;
3227 doWindowSnapping(dx
, dy
);
3229 if (screen
->doOpaqueMove()) {
3230 if (screen
->doWorkspaceWarping())
3231 doWorkspaceWarping(x_root
, y_root
, dx
);
3233 configure(dx
, dy
, frame
.rect
.width(), frame
.rect
.height());
3235 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3239 frame
.changing
.width() - 1,
3240 frame
.changing
.height() - 1);
3242 if (screen
->doWorkspaceWarping())
3243 doWorkspaceWarping(x_root
, y_root
, dx
);
3245 frame
.changing
.setPos(dx
, dy
);
3247 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3251 frame
.changing
.width() - 1,
3252 frame
.changing
.height() - 1);
3255 screen
->showPosition(dx
, dy
);
3259 void BlackboxWindow::doWorkspaceWarping(int x_root
, int y_root
, int &dx
) {
3260 // workspace warping
3262 unsigned int dest
= screen
->getCurrentWorkspaceID();
3266 if (dest
> 0) dest
--;
3267 else dest
= screen
->getNumberOfWorkspaces() - 1;
3269 } else if (x_root
>= screen
->getRect().right()) {
3272 if (dest
< screen
->getNumberOfWorkspaces() - 1) dest
++;
3278 bool focus
= flags
.focused
; // had focus while moving?
3280 int dest_x
= x_root
;
3282 dest_x
+= screen
->getRect().width() - 1;
3283 dx
+= screen
->getRect().width() - 1;
3285 dest_x
-= screen
->getRect().width() - 1;
3286 dx
-= screen
->getRect().width() - 1;
3290 screen
->reassociateWindow(this, dest
, False
);
3291 screen
->changeWorkspaceID(dest
);
3293 if (screen
->doOpaqueMove())
3294 XGrabServer(blackbox
->getXDisplay());
3296 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3297 XWarpPointer(blackbox
->getXDisplay(), None
,
3298 screen
->getRootWindow(), 0, 0, 0, 0,
3300 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3301 PointerMotionMask
| ButtonReleaseMask
,
3302 GrabModeAsync
, GrabModeAsync
,
3303 None
, blackbox
->getMoveCursor(), CurrentTime
);
3305 if (screen
->doOpaqueMove())
3306 XUngrabServer(blackbox
->getXDisplay());
3314 void BlackboxWindow::doWindowSnapping(int &dx
, int &dy
) {
3315 // how much resistance to edges to provide
3316 const int resistance_size
= screen
->getResistanceSize();
3318 // how far away to snap
3319 const int snap_distance
= screen
->getSnapThreshold();
3321 // how to snap windows
3322 const int snap_to_windows
= screen
->getWindowToWindowSnap();
3323 const int snap_to_edges
= screen
->getWindowToEdgeSnap();
3324 // the amount of space away from the edge to provide resistance/snap
3325 const int snap_offset
= screen
->getSnapOffset();
3327 // find the geomeetery where the moving window currently is
3328 const Rect
&moving
= screen
->doOpaqueMove() ? frame
.rect
: frame
.changing
;
3331 const int wleft
= dx
,
3332 wright
= dx
+ frame
.rect
.width() - 1,
3334 wbottom
= dy
+ frame
.rect
.height() - 1;
3336 if (snap_to_windows
) {
3339 Workspace
*w
= screen
->getWorkspace(getWorkspaceNumber());
3342 // add windows on the workspace to the rect list
3343 const BlackboxWindowList
& stack_list
= w
->getStackingList();
3344 BlackboxWindowList::const_iterator st_it
, st_end
= stack_list
.end();
3345 for (st_it
= stack_list
.begin(); st_it
!= st_end
; ++st_it
)
3346 if (*st_it
!= this) // don't snap to ourself
3347 rectlist
.push_back( (*st_it
)->frameRect() );
3349 // add the toolbar and the slit to the rect list.
3350 // (only if they are not hidden)
3351 Toolbar
*tbar
= screen
->getToolbar();
3352 Slit
*slit
= screen
->getSlit();
3353 Rect tbar_rect
, slit_rect
;
3354 unsigned int bwidth
= screen
->getBorderWidth() * 2;
3356 if (! (screen
->doHideToolbar() || tbar
->isHidden())) {
3357 tbar_rect
.setRect(tbar
->getX(), tbar
->getY(), tbar
->getWidth() + bwidth
,
3358 tbar
->getHeight() + bwidth
);
3359 rectlist
.push_back(tbar_rect
);
3362 if (! slit
->isHidden()) {
3363 slit_rect
.setRect(slit
->getX(), slit
->getY(), slit
->getWidth() + bwidth
,
3364 slit
->getHeight() + bwidth
);
3365 rectlist
.push_back(slit_rect
);
3368 RectList::const_iterator it
, end
= rectlist
.end();
3369 for (it
= rectlist
.begin(); it
!= end
; ++it
) {
3370 bool snapped
= False
;
3371 const Rect
&winrect
= *it
;
3373 offsetrect
.setCoords(winrect
.left() - snap_offset
,
3374 winrect
.top() - snap_offset
,
3375 winrect
.right() + snap_offset
,
3376 winrect
.bottom() + snap_offset
);
3378 if (snap_to_windows
== BScreen::WindowResistance
)
3379 // if the window is already over top of this snap target, then
3380 // resistance is futile, so just ignore it
3381 if (winrect
.intersects(moving
))
3384 int dleft
, dright
, dtop
, dbottom
;
3386 // if the windows are in the same plane vertically
3387 if (wtop
>= (signed)(winrect
.y() - frame
.rect
.height() + 1) &&
3388 wtop
< (signed)(winrect
.y() + winrect
.height() - 1)) {
3390 if (snap_to_windows
== BScreen::WindowResistance
) {
3391 dleft
= wright
- offsetrect
.left();
3392 dright
= offsetrect
.right() - wleft
;
3394 // snap left of other window?
3395 if (dleft
>= 0 && dleft
< resistance_size
&&
3396 dleft
< (wright
- wleft
)) {
3397 dx
= offsetrect
.left() - frame
.rect
.width();
3400 // snap right of other window?
3401 else if (dright
>= 0 && dright
< resistance_size
&&
3402 dright
< (wright
- wleft
)) {
3403 dx
= offsetrect
.right() + 1;
3406 } else { // BScreen::WindowSnap
3407 dleft
= abs(wright
- offsetrect
.left());
3408 dright
= abs(wleft
- offsetrect
.right());
3410 // snap left of other window?
3411 if (dleft
< snap_distance
&& dleft
<= dright
) {
3412 dx
= offsetrect
.left() - frame
.rect
.width();
3415 // snap right of other window?
3416 else if (dright
< snap_distance
) {
3417 dx
= offsetrect
.right() + 1;
3423 if (screen
->getWindowCornerSnap()) {
3424 // try corner-snap to its other sides
3425 if (snap_to_windows
== BScreen::WindowResistance
) {
3426 dtop
= winrect
.top() - wtop
;
3427 dbottom
= wbottom
- winrect
.bottom();
3428 if (dtop
> 0 && dtop
< resistance_size
) {
3429 // if we're already past the top edge, then don't provide
3431 if (moving
.top() >= winrect
.top())
3433 } else if (dbottom
> 0 && dbottom
< resistance_size
) {
3434 // if we're already past the bottom edge, then don't provide
3436 if (moving
.bottom() <= winrect
.bottom())
3437 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
3439 } else { // BScreen::WindowSnap
3440 dtop
= abs(wtop
- winrect
.top());
3441 dbottom
= abs(wbottom
- winrect
.bottom());
3442 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3444 else if (dbottom
< snap_distance
)
3445 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
3453 // if the windows are on the same plane horizontally
3454 if (wleft
>= (signed)(winrect
.x() - frame
.rect
.width() + 1) &&
3455 wleft
< (signed)(winrect
.x() + winrect
.width() - 1)) {
3457 if (snap_to_windows
== BScreen::WindowResistance
) {
3458 dtop
= wbottom
- offsetrect
.top();
3459 dbottom
= offsetrect
.bottom() - wtop
;
3461 // snap top of other window?
3462 if (dtop
>= 0 && dtop
< resistance_size
&& dtop
< (wbottom
- wtop
)) {
3463 dy
= offsetrect
.top() - frame
.rect
.height();
3466 // snap bottom of other window?
3467 else if (dbottom
>= 0 && dbottom
< resistance_size
&&
3468 dbottom
< (wbottom
- wtop
)) {
3469 dy
= offsetrect
.bottom() + 1;
3472 } else { // BScreen::WindowSnap
3473 dtop
= abs(wbottom
- offsetrect
.top());
3474 dbottom
= abs(wtop
- offsetrect
.bottom());
3476 // snap top of other window?
3477 if (dtop
< snap_distance
&& dtop
<= dbottom
) {
3478 dy
= offsetrect
.top() - frame
.rect
.height();
3481 // snap bottom of other window?
3482 else if (dbottom
< snap_distance
) {
3483 dy
= offsetrect
.bottom() + 1;
3490 if (screen
->getWindowCornerSnap()) {
3491 // try corner-snap to its other sides
3492 if (snap_to_windows
== BScreen::WindowResistance
) {
3493 dleft
= winrect
.left() - wleft
;
3494 dright
= wright
- winrect
.right();
3495 if (dleft
> 0 && dleft
< resistance_size
) {
3496 // if we're already past the left edge, then don't provide
3498 if (moving
.left() >= winrect
.left())
3499 dx
= winrect
.left();
3500 } else if (dright
> 0 && dright
< resistance_size
) {
3501 // if we're already past the right edge, then don't provide
3503 if (moving
.right() <= winrect
.right())
3504 dx
= winrect
.right() - frame
.rect
.width() + 1;
3506 } else { // BScreen::WindowSnap
3507 dleft
= abs(wleft
- winrect
.left());
3508 dright
= abs(wright
- winrect
.right());
3509 if (dleft
< snap_distance
&& dleft
<= dright
)
3510 dx
= winrect
.left();
3511 else if (dright
< snap_distance
)
3512 dx
= winrect
.right() - frame
.rect
.width() + 1;
3522 if (snap_to_edges
) {
3525 // snap to the screen edges (and screen boundaries for xinerama)
3527 if (screen
->isXineramaActive() && blackbox
->doXineramaSnapping()) {
3528 rectlist
.insert(rectlist
.begin(),
3529 screen
->getXineramaAreas().begin(),
3530 screen
->getXineramaAreas().end());
3533 rectlist
.push_back(screen
->getRect());
3535 RectList::const_iterator it
, end
= rectlist
.end();
3536 for (it
= rectlist
.begin(); it
!= end
; ++it
) {
3537 const Rect
&srect
= *it
;
3539 offsetrect
.setCoords(srect
.left() + snap_offset
,
3540 srect
.top() + snap_offset
,
3541 srect
.right() - snap_offset
,
3542 srect
.bottom() - snap_offset
);
3544 if (snap_to_edges
== BScreen::WindowResistance
) {
3545 // if we're not in the rectangle then don't snap to it.
3546 if (! srect
.contains(moving
))
3548 } else { // BScreen::WindowSnap
3549 // if we're not in the rectangle then don't snap to it.
3550 if (! srect
.intersects(Rect(wleft
, wtop
, frame
.rect
.width(),
3551 frame
.rect
.height())))
3555 if (snap_to_edges
== BScreen::WindowResistance
) {
3556 int dleft
= offsetrect
.left() - wleft
,
3557 dright
= wright
- offsetrect
.right(),
3558 dtop
= offsetrect
.top() - wtop
,
3559 dbottom
= wbottom
- offsetrect
.bottom();
3562 if (dleft
> 0 && dleft
< resistance_size
)
3563 dx
= offsetrect
.left();
3565 else if (dright
> 0 && dright
< resistance_size
)
3566 dx
= offsetrect
.right() - frame
.rect
.width() + 1;
3569 if (dtop
> 0 && dtop
< resistance_size
)
3570 dy
= offsetrect
.top();
3572 else if (dbottom
> 0 && dbottom
< resistance_size
)
3573 dy
= offsetrect
.bottom() - frame
.rect
.height() + 1;
3574 } else { // BScreen::WindowSnap
3575 int dleft
= abs(wleft
- offsetrect
.left()),
3576 dright
= abs(wright
- offsetrect
.right()),
3577 dtop
= abs(wtop
- offsetrect
.top()),
3578 dbottom
= abs(wbottom
- offsetrect
.bottom());
3581 if (dleft
< snap_distance
&& dleft
<= dright
)
3582 dx
= offsetrect
.left();
3584 else if (dright
< snap_distance
)
3585 dx
= offsetrect
.right() - frame
.rect
.width() + 1;
3588 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3589 dy
= offsetrect
.top();
3591 else if (dbottom
< snap_distance
)
3592 dy
= offsetrect
.bottom() - frame
.rect
.height() + 1;
3599 void BlackboxWindow::endMove(void) {
3600 assert(flags
.moving
);
3601 assert(blackbox
->getChangingWindow() == this);
3603 flags
.moving
= False
;
3604 blackbox
->setChangingWindow(0);
3606 if (! screen
->doOpaqueMove()) {
3607 /* when drawing the rubber band, we need to make sure we only draw inside
3608 * the frame... frame.changing_* contain the new coords for the window,
3609 * so we need to subtract 1 from changing_w/changing_h every where we
3610 * draw the rubber band (for both moving and resizing)
3612 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3613 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3614 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3615 XUngrabServer(blackbox
->getXDisplay());
3617 configure(frame
.changing
.x(), frame
.changing
.y(),
3618 frame
.changing
.width(), frame
.changing
.height());
3620 configure(frame
.rect
.x(), frame
.rect
.y(),
3621 frame
.rect
.width(), frame
.rect
.height());
3623 screen
->hideGeometry();
3625 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3627 // if there are any left over motions from the move, drop them now
3628 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3630 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3635 void BlackboxWindow::beginResize(int x_root
, int y_root
, Corner dir
) {
3636 if (! (functions
& Func_Resize
)) return;
3638 assert(! (flags
.resizing
|| flags
.moving
));
3641 Only one window can be moved/resized at a time. If another window is
3642 already being moved or resized, then stop it before whating to work with
3645 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3646 if (changing
&& changing
!= this) {
3647 if (changing
->flags
.moving
)
3648 changing
->endMove();
3649 else // if (changing->flags.resizing)
3650 changing
->endResize();
3658 switch (resize_dir
) {
3661 cursor
= blackbox
->getLowerLeftAngleCursor();
3666 cursor
= blackbox
->getLowerRightAngleCursor();
3670 anchor
= BottomRight
;
3671 cursor
= blackbox
->getUpperLeftAngleCursor();
3675 anchor
= BottomLeft
;
3676 cursor
= blackbox
->getUpperRightAngleCursor();
3680 assert(false); // unhandled Corner
3681 return; // unreachable, for the compiler
3684 XGrabServer(blackbox
->getXDisplay());
3685 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3686 PointerMotionMask
| ButtonReleaseMask
,
3687 GrabModeAsync
, GrabModeAsync
, None
, cursor
, CurrentTime
);
3689 flags
.resizing
= True
;
3690 blackbox
->setChangingWindow(this);
3692 unsigned int gw
, gh
;
3693 frame
.changing
= frame
.rect
;
3695 constrain(anchor
, &gw
, &gh
);
3697 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3698 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3699 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3701 screen
->showGeometry(gw
, gh
);
3703 frame
.grab_x
= x_root
;
3704 frame
.grab_y
= y_root
;
3708 void BlackboxWindow::doResize(int x_root
, int y_root
) {
3709 assert(flags
.resizing
);
3710 assert(blackbox
->getChangingWindow() == this);
3712 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3713 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3714 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3716 unsigned int gw
, gh
;
3718 int dx
, dy
; // the amount of change in the size of the window
3720 switch (resize_dir
) {
3723 dx
= - (x_root
- frame
.grab_x
);
3724 dy
= + (y_root
- frame
.grab_y
);
3728 dx
= + (x_root
- frame
.grab_x
);
3729 dy
= + (y_root
- frame
.grab_y
);
3732 anchor
= BottomRight
;
3733 dx
= - (x_root
- frame
.grab_x
);
3734 dy
= - (y_root
- frame
.grab_y
);
3737 anchor
= BottomLeft
;
3738 dx
= + (x_root
- frame
.grab_x
);
3739 dy
= - (y_root
- frame
.grab_y
);
3743 assert(false); // unhandled Corner
3744 return; // unreachable, for the compiler
3747 // make sure the user cant resize the window smaller than 0, which makes it
3748 // wrap around and become huge
3749 if (dx
< -(signed)client
.rect
.width()) dx
= -(signed)client
.rect
.width();
3750 if (dy
< -(signed)client
.rect
.height()) dy
= -(signed)client
.rect
.height();
3752 frame
.changing
.setSize(frame
.rect
.width() + dx
, frame
.rect
.height() + dy
);
3754 constrain(anchor
, &gw
, &gh
);
3756 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3757 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3758 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3760 screen
->showGeometry(gw
, gh
);
3764 void BlackboxWindow::endResize(void) {
3765 assert(flags
.resizing
);
3766 assert(blackbox
->getChangingWindow() == this);
3768 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3769 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3770 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3771 XUngrabServer(blackbox
->getXDisplay());
3773 // unset maximized state after resized when fully maximized
3774 if (flags
.maximized
== 1)
3777 flags
.resizing
= False
;
3778 blackbox
->setChangingWindow(0);
3780 configure(frame
.changing
.x(), frame
.changing
.y(),
3781 frame
.changing
.width(), frame
.changing
.height());
3782 screen
->hideGeometry();
3784 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3786 // if there are any left over motions from the resize, drop them now
3787 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3789 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3794 void BlackboxWindow::motionNotifyEvent(const XMotionEvent
*me
) {
3796 fprintf(stderr
, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n",
3801 doMove(me
->x_root
, me
->y_root
);
3802 } else if (flags
.resizing
) {
3803 doResize(me
->x_root
, me
->y_root
);
3805 if ((functions
& Func_Move
) &&
3806 (me
->state
& Button1Mask
) &&
3807 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3808 frame
.handle
== me
->window
|| frame
.window
== me
->window
)) {
3809 beginMove(me
->x_root
, me
->y_root
);
3810 } else if ((functions
& Func_Resize
) &&
3811 ((me
->state
& Button1Mask
) && (me
->window
== frame
.right_grip
||
3812 me
->window
== frame
.left_grip
)) ||
3813 ((me
->state
& Button3Mask
) && (me
->state
& mod_mask
) &&
3814 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3815 frame
.handle
== me
->window
|| frame
.window
== me
->window
))) {
3816 unsigned int zones
= screen
->getResizeZones();
3819 if (me
->window
== frame
.left_grip
) {
3820 corner
= BottomLeft
;
3821 } else if (me
->window
== frame
.right_grip
|| zones
== 1) {
3822 corner
= BottomRight
;
3825 bool left
= (me
->x_root
- frame
.rect
.x() <=
3826 static_cast<signed>(frame
.rect
.width() / 2));
3829 else // (zones == 4)
3830 top
= (me
->y_root
- frame
.rect
.y() <=
3831 static_cast<signed>(frame
.rect
.height() / 2));
3832 corner
= (top
? (left
? TopLeft
: TopRight
) :
3833 (left
? BottomLeft
: BottomRight
));
3836 beginResize(me
->x_root
, me
->y_root
, corner
);
3842 void BlackboxWindow::enterNotifyEvent(const XCrossingEvent
* ce
) {
3843 if (! (screen
->isSloppyFocus() && isVisible() && isNormal()))
3847 bool leave
= False
, inferior
= False
;
3849 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), ce
->window
,
3851 if (e
.type
== LeaveNotify
&& e
.xcrossing
.mode
== NotifyNormal
) {
3853 inferior
= (e
.xcrossing
.detail
== NotifyInferior
);
3857 if (! leave
|| inferior
) {
3858 if (! isFocused()) {
3859 bool success
= setInputFocus();
3860 if (success
) // if focus succeeded install the colormap
3861 installColormap(True
); // XXX: shouldnt we honour no install?
3864 if (screen
->doAutoRaise())
3870 void BlackboxWindow::leaveNotifyEvent(const XCrossingEvent
*) {
3871 if (! (screen
->isSloppyFocus() && screen
->doAutoRaise() && isNormal()))
3874 installColormap(False
);
3876 if (timer
->isTiming())
3882 void BlackboxWindow::shapeEvent(XShapeEvent
*e
) {
3883 if (blackbox
->hasShapeExtensions()) {
3884 if (! e
->shaped
&& flags
.shaped
) {
3886 flags
.shaped
= False
;
3887 } else if (e
->shaped
) {
3889 flags
.shaped
= True
;
3896 bool BlackboxWindow::validateClient(void) const {
3897 XSync(blackbox
->getXDisplay(), False
);
3900 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3901 DestroyNotify
, &e
) ||
3902 XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3904 XPutBackEvent(blackbox
->getXDisplay(), &e
);
3913 void BlackboxWindow::restore(bool remap
) {
3914 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeDelete
);
3915 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
3916 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, NoEventMask
);
3918 // do not leave a shaded window as an icon unless it was an icon
3919 if (flags
.shaded
&& ! flags
.iconic
)
3920 setState(NormalState
);
3922 // erase the netwm stuff that we read when a window maps, so that it
3923 // doesn't persist between mappings.
3924 // (these are the ones read in getNetWMFlags().)
3925 xatom
->eraseValue(client
.window
, XAtom::net_wm_desktop
);
3926 xatom
->eraseValue(client
.window
, XAtom::net_wm_state
);
3928 restoreGravity(client
.rect
);
3930 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
3931 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
3933 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, client
.old_bw
);
3936 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3937 ReparentNotify
, &ev
)) {
3940 // according to the ICCCM - if the client doesn't reparent to
3941 // root, then we have to do it for them
3942 XReparentWindow(blackbox
->getXDisplay(), client
.window
,
3943 screen
->getRootWindow(),
3944 client
.rect
.x(), client
.rect
.y());
3947 if (remap
) XMapWindow(blackbox
->getXDisplay(), client
.window
);
3951 // timer for autoraise
3952 void BlackboxWindow::timeout(void) {
3953 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3957 void BlackboxWindow::changeBlackboxHints(const BlackboxHints
*net
) {
3958 if ((net
->flags
& AttribShaded
) &&
3959 ((blackbox_attrib
.attrib
& AttribShaded
) !=
3960 (net
->attrib
& AttribShaded
)))
3963 if (flags
.visible
&& // watch out for requests when we can not be seen
3964 (net
->flags
& (AttribMaxVert
| AttribMaxHoriz
)) &&
3965 ((blackbox_attrib
.attrib
& (AttribMaxVert
| AttribMaxHoriz
)) !=
3966 (net
->attrib
& (AttribMaxVert
| AttribMaxHoriz
)))) {
3967 if (flags
.maximized
) {
3972 if ((net
->flags
& AttribMaxHoriz
) && (net
->flags
& AttribMaxVert
))
3973 button
= ((net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0);
3974 else if (net
->flags
& AttribMaxVert
)
3975 button
= ((net
->attrib
& AttribMaxVert
) ? 2 : 0);
3976 else if (net
->flags
& AttribMaxHoriz
)
3977 button
= ((net
->attrib
& AttribMaxHoriz
) ? 3 : 0);
3983 if ((net
->flags
& AttribOmnipresent
) &&
3984 ((blackbox_attrib
.attrib
& AttribOmnipresent
) !=
3985 (net
->attrib
& AttribOmnipresent
)))
3988 if ((net
->flags
& AttribWorkspace
) &&
3989 (blackbox_attrib
.workspace
!= net
->workspace
)) {
3990 screen
->reassociateWindow(this, net
->workspace
, True
);
3992 if (screen
->getCurrentWorkspaceID() != net
->workspace
) {
3996 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
4000 if (net
->flags
& AttribDecoration
) {
4001 switch (net
->decoration
) {
4018 * Set the sizes of all components of the window frame
4019 * (the window decorations).
4020 * These values are based upon the current style settings and the client
4021 * window's dimensions.
4023 void BlackboxWindow::upsize(void) {
4024 frame
.bevel_w
= screen
->getBevelWidth();
4026 if (decorations
& Decor_Border
) {
4027 frame
.border_w
= screen
->getBorderWidth();
4028 if (! isTransient())
4029 frame
.mwm_border_w
= screen
->getFrameWidth();
4031 frame
.mwm_border_w
= 0;
4033 frame
.mwm_border_w
= frame
.border_w
= 0;
4036 if (decorations
& Decor_Titlebar
) {
4037 // the height of the titlebar is based upon the height of the font being
4038 // used to display the window's title
4039 WindowStyle
*style
= screen
->getWindowStyle();
4040 frame
.title_h
= style
->font
->height() + (frame
.bevel_w
* 2) + 2;
4042 frame
.label_h
= frame
.title_h
- (frame
.bevel_w
* 2);
4043 frame
.button_w
= (frame
.label_h
- 2);
4045 // set the top frame margin
4046 frame
.margin
.top
= frame
.border_w
+ frame
.title_h
+
4047 frame
.border_w
+ frame
.mwm_border_w
;
4053 // set the top frame margin
4054 frame
.margin
.top
= frame
.border_w
+ frame
.mwm_border_w
;
4057 // set the left/right frame margin
4058 frame
.margin
.left
= frame
.margin
.right
= frame
.border_w
+ frame
.mwm_border_w
;
4060 if (decorations
& Decor_Handle
) {
4061 frame
.grip_w
= frame
.button_w
* 2;
4062 frame
.handle_h
= screen
->getHandleWidth();
4064 // set the bottom frame margin
4065 frame
.margin
.bottom
= frame
.border_w
+ frame
.handle_h
+
4066 frame
.border_w
+ frame
.mwm_border_w
;
4071 // set the bottom frame margin
4072 frame
.margin
.bottom
= frame
.border_w
+ frame
.mwm_border_w
;
4076 We first get the normal dimensions and use this to define the inside_w/h
4077 then we modify the height if shading is in effect.
4078 If the shade state is not considered then frame.rect gets reset to the
4079 normal window size on a reconfigure() call resulting in improper
4080 dimensions appearing in move/resize and other events.
4083 height
= client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
,
4084 width
= client
.rect
.width() + frame
.margin
.left
+ frame
.margin
.right
;
4086 frame
.inside_w
= width
- (frame
.border_w
* 2);
4087 frame
.inside_h
= height
- (frame
.border_w
* 2);
4090 height
= frame
.title_h
+ (frame
.border_w
* 2);
4091 frame
.rect
.setSize(width
, height
);
4096 * Calculate the size of the client window and constrain it to the
4097 * size specified by the size hints of the client window.
4099 * The logical width and height are placed into pw and ph, if they
4100 * are non-zero. Logical size refers to the users perception of
4101 * the window size (for example an xterm resizes in cells, not in pixels).
4102 * pw and ph are then used to display the geometry during window moves, resize,
4105 * The physical geometry is placed into frame.changing_{x,y,width,height}.
4106 * Physical geometry refers to the geometry of the window in pixels.
4108 void BlackboxWindow::constrain(Corner anchor
,
4109 unsigned int *pw
, unsigned int *ph
) {
4110 // frame.changing represents the requested frame size, we need to
4111 // strip the frame margin off and constrain the client size
4112 frame
.changing
.setCoords(frame
.changing
.left() + frame
.margin
.left
,
4113 frame
.changing
.top() + frame
.margin
.top
,
4114 frame
.changing
.right() - frame
.margin
.right
,
4115 frame
.changing
.bottom() - frame
.margin
.bottom
);
4117 unsigned int dw
= frame
.changing
.width(), dh
= frame
.changing
.height(),
4118 base_width
= (client
.base_width
) ? client
.base_width
: client
.min_width
,
4119 base_height
= (client
.base_height
) ? client
.base_height
:
4122 // constrain, but only if the min/max are being used. if they aren't, then
4123 // this resize is going to be from a ConfigureRequest because the window
4124 // isn't allowed to be resized by the user. And in that case, we don't want
4125 // to limit what the app can do
4126 if (client
.max_width
> client
.min_width
||
4127 client
.max_height
> client
.min_height
) {
4128 if (dw
< client
.min_width
) dw
= client
.min_width
;
4129 if (dh
< client
.min_height
) dh
= client
.min_height
;
4130 if (dw
> client
.max_width
) dw
= client
.max_width
;
4131 if (dh
> client
.max_height
) dh
= client
.max_height
;
4134 assert(dw
>= base_width
&& dh
>= base_height
);
4136 if (client
.width_inc
> 1) {
4138 dw
/= client
.width_inc
;
4140 if (client
.height_inc
> 1) {
4142 dh
/= client
.height_inc
;
4151 if (client
.width_inc
> 1) {
4152 dw
*= client
.width_inc
;
4155 if (client
.height_inc
> 1) {
4156 dh
*= client
.height_inc
;
4160 frame
.changing
.setSize(dw
, dh
);
4162 // add the frame margin back onto frame.changing
4163 frame
.changing
.setCoords(frame
.changing
.left() - frame
.margin
.left
,
4164 frame
.changing
.top() - frame
.margin
.top
,
4165 frame
.changing
.right() + frame
.margin
.right
,
4166 frame
.changing
.bottom() + frame
.margin
.bottom
);
4168 // move frame.changing to the specified anchor
4176 dx
= frame
.rect
.right() - frame
.changing
.right();
4180 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
4184 dx
= frame
.rect
.right() - frame
.changing
.right();
4185 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
4189 assert(false); // unhandled corner
4191 frame
.changing
.setPos(frame
.changing
.x() + dx
, frame
.changing
.y() + dy
);
4195 void WindowStyle::doJustify(const std::string
&text
, int &start_pos
,
4196 unsigned int max_length
,
4197 unsigned int modifier
) const {
4198 size_t text_len
= text
.size();
4199 unsigned int length
;
4202 length
= font
->measureString(string(text
, 0, text_len
)) + modifier
;
4203 } while (length
> max_length
&& text_len
-- > 0);
4207 start_pos
+= max_length
- length
;
4211 start_pos
+= (max_length
- length
) / 2;
4221 BWindowGroup::BWindowGroup(Blackbox
*b
, Window _group
)
4222 : blackbox(b
), group(_group
) {
4223 XWindowAttributes wattrib
;
4224 if (! XGetWindowAttributes(blackbox
->getXDisplay(), group
, &wattrib
)) {
4225 // group window doesn't seem to exist anymore
4230 XSelectInput(blackbox
->getXDisplay(), group
,
4231 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
4233 blackbox
->saveGroupSearch(group
, this);
4237 BWindowGroup::~BWindowGroup(void) {
4238 blackbox
->removeGroupSearch(group
);
4243 BWindowGroup::find(BScreen
*screen
, bool allow_transients
) const {
4244 BlackboxWindow
*ret
= blackbox
->getFocusedWindow();
4246 // does the focus window match (or any transient_fors)?
4247 for (; ret
; ret
= ret
->getTransientFor()) {
4248 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
&&
4249 (! ret
->isTransient() || allow_transients
))
4253 if (ret
) return ret
;
4255 // the focus window didn't match, look in the group's window list
4256 BlackboxWindowList::const_iterator it
, end
= windowList
.end();
4257 for (it
= windowList
.begin(); it
!= end
; ++it
) {
4259 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
&&
4260 (! ret
->isTransient() || allow_transients
))