1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
4 # include "../config.h"
5 #endif // HAVE_CONFIG_H
9 #include <X11/keysym.h>
13 #endif // HAVE_STRING_H
18 # endif // HAVE_STDIO_H
23 #endif // HAVE_STDLIB_H
26 #include "blackbox.hh"
33 #include "workspace.hh"
39 * Initializes the class with default values/the window's set initial values.
41 BlackboxWindow::BlackboxWindow(Blackbox
*b
, Window w
, BScreen
*s
) {
42 // fprintf(stderr, "BlackboxWindow size: %d bytes\n",
43 // sizeof(BlackboxWindow));
46 fprintf(stderr
, "BlackboxWindow::BlackboxWindow(): creating 0x%lx\n", w
);
50 set timer to zero... it is initialized properly later, so we check
51 if timer is zero in the destructor, and assume that the window is not
52 fully constructed if timer is zero...
58 xatom
= blackbox
->getXAtom();
60 if (! validateClient()) {
65 // fetch client size and placement
66 XWindowAttributes wattrib
;
67 if (! XGetWindowAttributes(blackbox
->getXDisplay(),
68 client
.window
, &wattrib
) ||
69 ! wattrib
.screen
|| wattrib
.override_redirect
) {
72 "BlackboxWindow::BlackboxWindow(): XGetWindowAttributes failed\n");
79 // set the eventmask early in the game so that we make sure we get
80 // all the events we are interested in
81 XSetWindowAttributes attrib_set
;
82 attrib_set
.event_mask
= PropertyChangeMask
| FocusChangeMask
|
84 attrib_set
.do_not_propagate_mask
= ButtonPressMask
| ButtonReleaseMask
|
86 XChangeWindowAttributes(blackbox
->getXDisplay(), client
.window
,
87 CWEventMask
|CWDontPropagate
, &attrib_set
);
89 flags
.moving
= flags
.resizing
= flags
.shaded
= flags
.visible
=
90 flags
.iconic
= flags
.focused
= flags
.stuck
= flags
.modal
=
91 flags
.send_focus_message
= flags
.shaped
= flags
.skip_taskbar
=
92 flags
.skip_pager
= flags
.fullscreen
= False
;
95 blackbox_attrib
.workspace
= window_number
= BSENTINEL
;
97 blackbox_attrib
.flags
= blackbox_attrib
.attrib
= blackbox_attrib
.stack
= 0l;
98 blackbox_attrib
.decoration
= DecorNormal
;
99 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
100 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
103 frame
.window
= frame
.plate
= frame
.title
= frame
.handle
= None
;
104 frame
.close_button
= frame
.iconify_button
= frame
.maximize_button
=
105 frame
.stick_button
= None
;
106 frame
.right_grip
= frame
.left_grip
= None
;
108 frame
.ulabel_pixel
= frame
.flabel_pixel
= frame
.utitle_pixel
=
109 frame
.ftitle_pixel
= frame
.uhandle_pixel
= frame
.fhandle_pixel
=
110 frame
.ubutton_pixel
= frame
.fbutton_pixel
= frame
.uborder_pixel
=
111 frame
.fborder_pixel
= frame
.ugrip_pixel
= frame
.fgrip_pixel
= 0;
112 frame
.utitle
= frame
.ftitle
= frame
.uhandle
= frame
.fhandle
= None
;
113 frame
.ulabel
= frame
.flabel
= frame
.ubutton
= frame
.fbutton
= None
;
114 frame
.ugrip
= frame
.fgrip
= None
;
116 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
117 mwm_decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
118 Decor_Iconify
| Decor_Maximize
;
120 client
.normal_hint_flags
= 0;
121 client
.window_group
= None
;
122 client
.transient_for
= 0;
124 current_state
= NormalState
;
127 set the initial size and location of client window (relative to the
128 _root window_). This position is the reference point used with the
129 window's gravity to find the window's initial position.
131 client
.rect
.setRect(wattrib
.x
, wattrib
.y
, wattrib
.width
, wattrib
.height
);
132 client
.old_bw
= wattrib
.border_width
;
134 lastButtonPressTime
= 0;
136 timer
= new BTimer(blackbox
, this);
137 timer
->setTimeout(blackbox
->getAutoRaiseDelay());
139 // get size, aspect, minimum/maximum size and other hints set by the
142 if (! getBlackboxHints())
149 frame
.window
= createToplevelWindow();
151 blackbox
->saveWindowSearch(frame
.window
, this);
153 frame
.plate
= createChildWindow(frame
.window
, ExposureMask
);
154 blackbox
->saveWindowSearch(frame
.plate
, this);
156 // determine if this is a transient window
159 // determine the window's type, so we can decide its decorations and
160 // functionality, or if we should not manage it at all
161 if (getWindowType()) {
162 // adjust the window decorations/behavior based on the window type
163 switch (window_type
) {
167 blackbox_attrib
.workspace
= 0; // we do need to belong to a workspace
168 flags
.stuck
= True
; // we show up on all workspaces
170 // none of these windows are manipulated by the window manager
176 // these windows get less functionality
177 functions
&= ~(Func_Maximize
| Func_Resize
| Func_Iconify
);
181 // dialogs cannot be maximized
182 functions
&= ~Func_Maximize
;
186 // normal windows retain all of the possible decorations and
194 // further adjeust the window's decorations/behavior based on window sizes
195 if ((client
.normal_hint_flags
& PMinSize
) &&
196 (client
.normal_hint_flags
& PMaxSize
) &&
197 client
.max_width
<= client
.min_width
&&
198 client
.max_height
<= client
.min_height
) {
199 functions
&= ~(Func_Resize
| Func_Maximize
);
206 if (decorations
& Decor_Titlebar
)
209 if (decorations
& Decor_Handle
)
212 // apply the size and gravity hint to the frame
216 bool place_window
= True
;
217 if (blackbox
->isStartup() || isTransient() ||
218 client
.normal_hint_flags
& (PPosition
|USPosition
)) {
219 applyGravity(frame
.rect
);
221 if (blackbox
->isStartup() || client
.rect
.intersects(screen
->getRect()))
222 place_window
= False
;
225 // add the window's strut. note this is done *after* placing the window.
226 screen
->addStrut(&client
.strut
);
230 the server needs to be grabbed here to prevent client's from sending
231 events while we are in the process of configuring their window.
232 We hold the grab until after we are done moving the window around.
235 XGrabServer(blackbox
->getXDisplay());
237 associateClientWindow();
239 blackbox
->saveWindowSearch(client
.window
, this);
241 if (blackbox_attrib
.workspace
>= screen
->getWorkspaceCount())
242 screen
->getCurrentWorkspace()->addWindow(this, place_window
);
244 screen
->getWorkspace(blackbox_attrib
.workspace
)->
245 addWindow(this, place_window
);
247 if (! place_window
) {
248 // don't need to call configure if we are letting the workspace
250 configure(frame
.rect
.x(), frame
.rect
.y(),
251 frame
.rect
.width(), frame
.rect
.height());
257 XUngrabServer(blackbox
->getXDisplay());
260 if (blackbox
->hasShapeExtensions() && flags
.shaped
)
264 // now that we know where to put the window and what it should look like
265 // we apply the decorations
270 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
272 // this ensures the title, buttons, and other decor are properly displayed
275 // preserve the window's initial state on first map, and its current state
277 unsigned long initial_state
= current_state
;
279 current_state
= initial_state
;
281 // get sticky state from our parent window if we've got one
282 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
283 client
.transient_for
->isStuck() != flags
.stuck
)
287 flags
.shaded
= False
;
288 initial_state
= current_state
;
292 At this point in the life of a window, current_state should only be set
293 to IconicState if the window was an *icon*, not if it was shaded.
295 if (initial_state
!= IconicState
)
296 current_state
= NormalState
;
304 if (flags
.maximized
&& (functions
& Func_Maximize
))
309 BlackboxWindow::~BlackboxWindow(void) {
311 fprintf(stderr
, "BlackboxWindow::~BlackboxWindow: destroying 0x%lx\n",
315 if (! timer
) // window not managed...
321 screen
->removeStrut(&client
.strut
);
322 screen
->updateAvailableArea();
324 // We don't need to worry about resizing because resizing always grabs the X
325 // server. This should only ever happen if using opaque moving.
331 if (client
.window_group
) {
332 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
333 if (group
) group
->removeWindow(this);
336 // remove ourselves from our transient_for
338 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul)
339 client
.transient_for
->client
.transientList
.remove(this);
340 client
.transient_for
= (BlackboxWindow
*) 0;
343 if (client
.transientList
.size() > 0) {
344 // reset transient_for for all transients
345 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
346 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
347 (*it
)->client
.transient_for
= (BlackboxWindow
*) 0;
357 blackbox
->removeWindowSearch(frame
.plate
);
358 XDestroyWindow(blackbox
->getXDisplay(), frame
.plate
);
362 blackbox
->removeWindowSearch(frame
.window
);
363 XDestroyWindow(blackbox
->getXDisplay(), frame
.window
);
366 blackbox
->removeWindowSearch(client
.window
);
370 void BlackboxWindow::enableDecor(bool enable
) {
371 blackbox_attrib
.flags
|= AttribDecoration
;
372 blackbox_attrib
.decoration
= enable
? DecorNormal
: DecorNone
;
375 // we can not be shaded if we lack a titlebar
376 if (! (decorations
& Decor_Titlebar
) && flags
.shaded
)
379 if (flags
.visible
&& frame
.window
) {
380 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
381 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
385 setState(current_state
);
389 void BlackboxWindow::setupDecor() {
390 if (blackbox_attrib
.decoration
!= DecorNone
) {
391 // start with everything on
392 decorations
= Decor_Close
|
393 (mwm_decorations
& Decor_Titlebar
? Decor_Titlebar
: 0) |
394 (mwm_decorations
& Decor_Border
? Decor_Border
: 0) |
395 (mwm_decorations
& Decor_Handle
? Decor_Handle
: 0) |
396 (mwm_decorations
& Decor_Iconify
? Decor_Iconify
: 0) |
397 (mwm_decorations
& Decor_Maximize
? Decor_Maximize
: 0);
399 if (! (functions
& Func_Close
)) decorations
&= ~Decor_Close
;
400 if (! (functions
& Func_Maximize
)) decorations
&= ~Decor_Maximize
;
401 if (! (functions
& Func_Iconify
)) decorations
&= ~Decor_Iconify
;
402 if (! (functions
& Func_Resize
)) decorations
&= ~Decor_Handle
;
404 switch (window_type
) {
409 // none of these windows are decorated by the window manager at all
415 decorations
&= ~(Decor_Border
);
419 decorations
&= ~Decor_Handle
;
431 * Creates a new top level window, with a given location, size, and border
433 * Returns: the newly created window
435 Window
BlackboxWindow::createToplevelWindow(void) {
436 XSetWindowAttributes attrib_create
;
437 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
| CWColormap
|
438 CWOverrideRedirect
| CWEventMask
;
440 attrib_create
.background_pixmap
= None
;
441 attrib_create
.colormap
= screen
->getColormap();
442 attrib_create
.override_redirect
= True
;
443 attrib_create
.event_mask
= EnterWindowMask
| LeaveWindowMask
|
446 We catch button presses because other wise they get passed down to the
447 root window, which will then cause root menus to show when you click the
451 return XCreateWindow(blackbox
->getXDisplay(), screen
->getRootWindow(),
452 0, 0, 1, 1, frame
.border_w
, screen
->getDepth(),
453 InputOutput
, screen
->getVisual(), create_mask
,
459 * Creates a child window, and optionally associates a given cursor with
462 Window
BlackboxWindow::createChildWindow(Window parent
,
463 unsigned long event_mask
,
465 XSetWindowAttributes attrib_create
;
466 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
|
469 attrib_create
.background_pixmap
= None
;
470 attrib_create
.event_mask
= event_mask
;
473 create_mask
|= CWCursor
;
474 attrib_create
.cursor
= cursor
;
477 return XCreateWindow(blackbox
->getXDisplay(), parent
, 0, 0, 1, 1, 0,
478 screen
->getDepth(), InputOutput
, screen
->getVisual(),
479 create_mask
, &attrib_create
);
483 void BlackboxWindow::associateClientWindow(void) {
484 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, 0);
488 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeInsert
);
490 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, SubstructureRedirectMask
);
493 note we used to grab around this call to XReparentWindow however the
494 server is now grabbed before this method is called
496 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
498 XSelectInput(blackbox
->getXDisplay(), client
.window
,
499 event_mask
& ~StructureNotifyMask
);
500 XReparentWindow(blackbox
->getXDisplay(), client
.window
, frame
.plate
, 0, 0);
501 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
503 XRaiseWindow(blackbox
->getXDisplay(), frame
.plate
);
504 XMapSubwindows(blackbox
->getXDisplay(), frame
.plate
);
507 if (blackbox
->hasShapeExtensions()) {
508 XShapeSelectInput(blackbox
->getXDisplay(), client
.window
,
515 XShapeQueryExtents(blackbox
->getXDisplay(), client
.window
, &shaped
,
516 &foo
, &foo
, &ufoo
, &ufoo
, &foo
, &foo
, &foo
,
518 flags
.shaped
= shaped
;
524 void BlackboxWindow::decorate(void) {
527 texture
= &(screen
->getWindowStyle()->b_focus
);
528 frame
.fbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
531 frame
.fbutton_pixel
= texture
->color().pixel();
533 texture
= &(screen
->getWindowStyle()->b_unfocus
);
534 frame
.ubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
537 frame
.ubutton_pixel
= texture
->color().pixel();
539 unsigned char needsPressed
= 0;
541 texture
= &(screen
->getWindowStyle()->b_pressed_focus
);
543 if (texture
->texture() != BTexture::NoTexture
) {
544 frame
.pfbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
546 if (! frame
.pfbutton
)
547 frame
.pfbutton_pixel
= texture
->color().pixel();
552 texture
= &(screen
->getWindowStyle()->b_pressed_unfocus
);
554 if (texture
->texture() != BTexture::NoTexture
) {
555 frame
.pubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
557 if (! frame
.pubutton
)
558 frame
.pubutton
= texture
->color().pixel();
563 // if we either pressed unfocused, or pressed focused were undefined,
564 // make them inherit from the old resource. It's a hack for sure, but
565 // it allows for some backwards and forwards compatibility.
567 texture
= &(screen
->getWindowStyle()->b_pressed
);
569 if (needsPressed
& 0x1) {
570 frame
.pfbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
572 if (! frame
.pfbutton
)
573 frame
.pfbutton_pixel
= texture
->color().pixel();
575 if (needsPressed
& 0x2) {
576 frame
.pubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
578 if (! frame
.pubutton
)
579 frame
.pubutton
= texture
->color().pixel();
584 if (decorations
& Decor_Titlebar
) {
585 texture
= &(screen
->getWindowStyle()->t_focus
);
586 frame
.ftitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
589 frame
.ftitle_pixel
= texture
->color().pixel();
591 texture
= &(screen
->getWindowStyle()->t_unfocus
);
592 frame
.utitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
595 frame
.utitle_pixel
= texture
->color().pixel();
597 XSetWindowBorder(blackbox
->getXDisplay(), frame
.title
,
598 screen
->getBorderColor()->pixel());
603 if (decorations
& Decor_Border
) {
604 frame
.fborder_pixel
= screen
->getWindowStyle()->f_focus
.color().pixel();
605 frame
.uborder_pixel
= screen
->getWindowStyle()->f_unfocus
.color().pixel();
608 if (decorations
& Decor_Handle
) {
609 texture
= &(screen
->getWindowStyle()->h_focus
);
610 frame
.fhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
613 frame
.fhandle_pixel
= texture
->color().pixel();
615 texture
= &(screen
->getWindowStyle()->h_unfocus
);
616 frame
.uhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
619 frame
.uhandle_pixel
= texture
->color().pixel();
621 texture
= &(screen
->getWindowStyle()->g_focus
);
622 frame
.fgrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.fgrip
);
624 frame
.fgrip_pixel
= texture
->color().pixel();
626 texture
= &(screen
->getWindowStyle()->g_unfocus
);
627 frame
.ugrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.ugrip
);
629 frame
.ugrip_pixel
= texture
->color().pixel();
631 XSetWindowBorder(blackbox
->getXDisplay(), frame
.handle
,
632 screen
->getBorderColor()->pixel());
633 XSetWindowBorder(blackbox
->getXDisplay(), frame
.left_grip
,
634 screen
->getBorderColor()->pixel());
635 XSetWindowBorder(blackbox
->getXDisplay(), frame
.right_grip
,
636 screen
->getBorderColor()->pixel());
639 XSetWindowBorder(blackbox
->getXDisplay(), frame
.window
,
640 screen
->getBorderColor()->pixel());
644 void BlackboxWindow::decorateLabel(void) {
647 texture
= &(screen
->getWindowStyle()->l_focus
);
648 frame
.flabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.flabel
);
650 frame
.flabel_pixel
= texture
->color().pixel();
652 texture
= &(screen
->getWindowStyle()->l_unfocus
);
653 frame
.ulabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.ulabel
);
655 frame
.ulabel_pixel
= texture
->color().pixel();
659 void BlackboxWindow::createHandle(void) {
660 frame
.handle
= createChildWindow(frame
.window
,
661 ButtonPressMask
| ButtonReleaseMask
|
662 ButtonMotionMask
| ExposureMask
);
663 blackbox
->saveWindowSearch(frame
.handle
, this);
666 createChildWindow(frame
.handle
,
667 ButtonPressMask
| ButtonReleaseMask
|
668 ButtonMotionMask
| ExposureMask
,
669 blackbox
->getLowerLeftAngleCursor());
670 blackbox
->saveWindowSearch(frame
.left_grip
, this);
673 createChildWindow(frame
.handle
,
674 ButtonPressMask
| ButtonReleaseMask
|
675 ButtonMotionMask
| ExposureMask
,
676 blackbox
->getLowerRightAngleCursor());
677 blackbox
->saveWindowSearch(frame
.right_grip
, this);
681 void BlackboxWindow::destroyHandle(void) {
683 screen
->getImageControl()->removeImage(frame
.fhandle
);
686 screen
->getImageControl()->removeImage(frame
.uhandle
);
689 screen
->getImageControl()->removeImage(frame
.fgrip
);
692 screen
->getImageControl()->removeImage(frame
.ugrip
);
694 blackbox
->removeWindowSearch(frame
.left_grip
);
695 blackbox
->removeWindowSearch(frame
.right_grip
);
697 XDestroyWindow(blackbox
->getXDisplay(), frame
.left_grip
);
698 XDestroyWindow(blackbox
->getXDisplay(), frame
.right_grip
);
699 frame
.left_grip
= frame
.right_grip
= None
;
701 blackbox
->removeWindowSearch(frame
.handle
);
702 XDestroyWindow(blackbox
->getXDisplay(), frame
.handle
);
707 void BlackboxWindow::createTitlebar(void) {
708 frame
.title
= createChildWindow(frame
.window
,
709 ButtonPressMask
| ButtonReleaseMask
|
710 ButtonMotionMask
| ExposureMask
);
711 frame
.label
= createChildWindow(frame
.title
,
712 ButtonPressMask
| ButtonReleaseMask
|
713 ButtonMotionMask
| ExposureMask
);
714 blackbox
->saveWindowSearch(frame
.title
, this);
715 blackbox
->saveWindowSearch(frame
.label
, this);
717 if (decorations
& Decor_Iconify
) createIconifyButton();
718 if (decorations
& Decor_Maximize
) createMaximizeButton();
719 if (decorations
& Decor_Close
) createCloseButton();
723 void BlackboxWindow::destroyTitlebar(void) {
724 if (frame
.close_button
)
725 destroyCloseButton();
727 if (frame
.iconify_button
)
728 destroyIconifyButton();
730 if (frame
.maximize_button
)
731 destroyMaximizeButton();
733 if (frame
.stick_button
)
734 destroyStickyButton();
737 screen
->getImageControl()->removeImage(frame
.ftitle
);
740 screen
->getImageControl()->removeImage(frame
.utitle
);
743 screen
->getImageControl()->removeImage(frame
.flabel
);
746 screen
->getImageControl()->removeImage(frame
.ulabel
);
749 screen
->getImageControl()->removeImage(frame
.fbutton
);
752 screen
->getImageControl()->removeImage(frame
.ubutton
);
754 blackbox
->removeWindowSearch(frame
.title
);
755 blackbox
->removeWindowSearch(frame
.label
);
757 XDestroyWindow(blackbox
->getXDisplay(), frame
.label
);
758 XDestroyWindow(blackbox
->getXDisplay(), frame
.title
);
759 frame
.title
= frame
.label
= None
;
763 void BlackboxWindow::createCloseButton(void) {
764 if (frame
.title
!= None
) {
765 frame
.close_button
= createChildWindow(frame
.title
,
768 ButtonMotionMask
| ExposureMask
);
769 blackbox
->saveWindowSearch(frame
.close_button
, this);
774 void BlackboxWindow::destroyCloseButton(void) {
775 blackbox
->removeWindowSearch(frame
.close_button
);
776 XDestroyWindow(blackbox
->getXDisplay(), frame
.close_button
);
777 frame
.close_button
= None
;
781 void BlackboxWindow::createIconifyButton(void) {
782 if (frame
.title
!= None
) {
783 frame
.iconify_button
= createChildWindow(frame
.title
,
786 ButtonMotionMask
| ExposureMask
);
787 blackbox
->saveWindowSearch(frame
.iconify_button
, this);
792 void BlackboxWindow::destroyIconifyButton(void) {
793 blackbox
->removeWindowSearch(frame
.iconify_button
);
794 XDestroyWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
795 frame
.iconify_button
= None
;
799 void BlackboxWindow::createMaximizeButton(void) {
800 if (frame
.title
!= None
) {
801 frame
.maximize_button
= createChildWindow(frame
.title
,
804 ButtonMotionMask
| ExposureMask
);
805 blackbox
->saveWindowSearch(frame
.maximize_button
, this);
810 void BlackboxWindow::destroyMaximizeButton(void) {
811 blackbox
->removeWindowSearch(frame
.maximize_button
);
812 XDestroyWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
813 frame
.maximize_button
= None
;
816 void BlackboxWindow::createStickyButton(void) {
817 if (frame
.title
!= None
) {
818 frame
.stick_button
= createChildWindow(frame
.title
,
821 ButtonMotionMask
| ExposureMask
);
822 blackbox
->saveWindowSearch(frame
.stick_button
, this);
826 void BlackboxWindow::destroyStickyButton(void) {
827 blackbox
->removeWindowSearch(frame
.stick_button
);
828 XDestroyWindow(blackbox
->getXDisplay(), frame
.stick_button
);
829 frame
.stick_button
= None
;
832 void BlackboxWindow::positionButtons(bool redecorate_label
) {
833 string layout
= blackbox
->getTitlebarLayout();
836 bool hasclose
, hasiconify
, hasmaximize
, haslabel
, hasstick
;
837 hasclose
= hasiconify
= hasmaximize
= haslabel
= hasstick
= false;
839 string::const_iterator it
, end
;
840 for (it
= layout
.begin(), end
= layout
.end(); it
!= end
; ++it
) {
843 if (! hasclose
&& (decorations
& Decor_Close
)) {
849 if (! hasiconify
&& (decorations
& Decor_Iconify
)) {
861 if (! hasmaximize
&& (decorations
& Decor_Maximize
)) {
875 if (! hasclose
&& frame
.close_button
)
876 destroyCloseButton();
877 if (! hasiconify
&& frame
.iconify_button
)
878 destroyIconifyButton();
879 if (! hasmaximize
&& frame
.maximize_button
)
880 destroyMaximizeButton();
881 if (! hasstick
&& frame
.stick_button
)
882 destroyStickyButton();
884 parsed
+= 'L'; // require that the label be in the layout
886 const unsigned int bsep
= frame
.bevel_w
+ 1; // separation between elements
887 const unsigned int by
= frame
.bevel_w
+ 1;
888 const unsigned int ty
= frame
.bevel_w
;
890 frame
.label_w
= frame
.inside_w
- bsep
* 2 -
891 (frame
.button_w
+ bsep
) * (parsed
.size() - 1);
893 unsigned int x
= bsep
;
894 for (it
= parsed
.begin(), end
= parsed
.end(); it
!= end
; ++it
) {
897 if (! frame
.close_button
) createCloseButton();
898 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.close_button
, x
, by
,
899 frame
.button_w
, frame
.button_w
);
900 x
+= frame
.button_w
+ bsep
;
903 if (! frame
.iconify_button
) createIconifyButton();
904 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.iconify_button
, x
, by
,
905 frame
.button_w
, frame
.button_w
);
906 x
+= frame
.button_w
+ bsep
;
909 if (! frame
.stick_button
) createStickyButton();
910 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.stick_button
, x
, by
,
911 frame
.button_w
, frame
.button_w
);
912 x
+= frame
.button_w
+ bsep
;
915 if (! frame
.maximize_button
) createMaximizeButton();
916 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.maximize_button
, x
, by
,
917 frame
.button_w
, frame
.button_w
);
918 x
+= frame
.button_w
+ bsep
;
921 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.label
, x
, ty
,
922 frame
.label_w
, frame
.label_h
);
923 x
+= frame
.label_w
+ bsep
;
928 if (redecorate_label
) decorateLabel();
934 void BlackboxWindow::reconfigure(void) {
935 restoreGravity(client
.rect
);
937 applyGravity(frame
.rect
);
947 void BlackboxWindow::grabButtons(void) {
948 mod_mask
= blackbox
->getMouseModMask();
950 if (! screen
->isSloppyFocus() || screen
->doClickRaise())
951 // grab button 1 for changing focus/raising
952 blackbox
->grabButton(Button1
, 0, frame
.plate
, True
, ButtonPressMask
,
953 GrabModeSync
, GrabModeSync
, frame
.plate
, None
,
954 screen
->allowScrollLock());
956 if (functions
& Func_Move
)
957 blackbox
->grabButton(Button1
, mod_mask
, frame
.window
, True
,
958 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
959 GrabModeAsync
, frame
.window
, None
,
960 screen
->allowScrollLock());
961 if (functions
& Func_Resize
)
962 blackbox
->grabButton(Button3
, mod_mask
, frame
.window
, True
,
963 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
964 GrabModeAsync
, frame
.window
, None
,
965 screen
->allowScrollLock());
966 // alt+middle lowers the window
967 blackbox
->grabButton(Button2
, mod_mask
, frame
.window
, True
,
968 ButtonReleaseMask
, GrabModeAsync
, GrabModeAsync
,
969 frame
.window
, None
, screen
->allowScrollLock());
973 void BlackboxWindow::ungrabButtons(void) {
974 blackbox
->ungrabButton(Button1
, 0, frame
.plate
);
975 blackbox
->ungrabButton(Button1
, mod_mask
, frame
.window
);
976 blackbox
->ungrabButton(Button2
, mod_mask
, frame
.window
);
977 blackbox
->ungrabButton(Button3
, mod_mask
, frame
.window
);
981 void BlackboxWindow::positionWindows(void) {
982 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.window
,
983 frame
.rect
.x(), frame
.rect
.y(), frame
.inside_w
,
984 (flags
.shaded
) ? frame
.title_h
: frame
.inside_h
);
985 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.window
,
987 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.plate
,
989 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.plate
,
990 frame
.margin
.left
- frame
.mwm_border_w
- frame
.border_w
,
991 frame
.margin
.top
- frame
.mwm_border_w
- frame
.border_w
,
992 client
.rect
.width(), client
.rect
.height());
993 XMoveResizeWindow(blackbox
->getXDisplay(), client
.window
,
994 0, 0, client
.rect
.width(), client
.rect
.height());
995 // ensure client.rect contains the real location
996 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
997 frame
.rect
.top() + frame
.margin
.top
);
999 if (decorations
& Decor_Titlebar
) {
1000 if (frame
.title
== None
) createTitlebar();
1002 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.title
,
1004 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.title
, -frame
.border_w
,
1005 -frame
.border_w
, frame
.inside_w
, frame
.title_h
);
1008 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
1009 XMapWindow(blackbox
->getXDisplay(), frame
.title
);
1010 } else if (frame
.title
) {
1013 if (decorations
& Decor_Handle
) {
1014 if (frame
.handle
== None
) createHandle();
1015 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.handle
,
1017 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.left_grip
,
1019 XSetWindowBorderWidth(blackbox
->getXDisplay(), frame
.right_grip
,
1022 // use client.rect here so the value is correct even if shaded
1023 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.handle
,
1025 client
.rect
.height() + frame
.margin
.top
+
1026 frame
.mwm_border_w
- frame
.border_w
,
1027 frame
.inside_w
, frame
.handle_h
);
1028 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.left_grip
,
1029 -frame
.border_w
, -frame
.border_w
,
1030 frame
.grip_w
, frame
.handle_h
);
1031 XMoveResizeWindow(blackbox
->getXDisplay(), frame
.right_grip
,
1032 frame
.inside_w
- frame
.grip_w
- frame
.border_w
,
1033 -frame
.border_w
, frame
.grip_w
, frame
.handle_h
);
1035 XMapSubwindows(blackbox
->getXDisplay(), frame
.handle
);
1036 XMapWindow(blackbox
->getXDisplay(), frame
.handle
);
1037 } else if (frame
.handle
) {
1040 XSync(blackbox
->getXDisplay(), False
);
1044 void BlackboxWindow::updateStrut(void) {
1045 unsigned long num
= 4;
1046 unsigned long *data
;
1047 if (! xatom
->getValue(client
.window
, XAtom::net_wm_strut
, XAtom::cardinal
,
1052 client
.strut
.left
= data
[0];
1053 client
.strut
.right
= data
[1];
1054 client
.strut
.top
= data
[2];
1055 client
.strut
.bottom
= data
[3];
1057 screen
->updateAvailableArea();
1064 bool BlackboxWindow::getWindowType(void) {
1065 window_type
= (WindowType
) -1;
1068 unsigned long num
= (unsigned) -1;
1069 if (xatom
->getValue(client
.window
, XAtom::net_wm_window_type
, XAtom::atom
,
1071 for (unsigned long i
= 0; i
< num
; ++i
) {
1072 if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_desktop
))
1073 window_type
= Type_Desktop
;
1074 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_dock
))
1075 window_type
= Type_Dock
;
1076 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_toolbar
))
1077 window_type
= Type_Toolbar
;
1078 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_menu
))
1079 window_type
= Type_Menu
;
1080 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_utility
))
1081 window_type
= Type_Utility
;
1082 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_splash
))
1083 window_type
= Type_Splash
;
1084 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_dialog
))
1085 window_type
= Type_Dialog
;
1086 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_normal
))
1087 window_type
= Type_Normal
;
1089 xatom
->getAtom(XAtom::kde_net_wm_window_type_override
))
1090 mwm_decorations
= 0; // prevent this window from getting any decor
1095 if (window_type
== (WindowType
) -1) {
1097 * the window type hint was not set, which means we either classify ourself
1098 * as a normal window or a dialog, depending on if we are a transient.
1101 window_type
= Type_Dialog
;
1103 window_type
= Type_Normal
;
1112 void BlackboxWindow::getWMName(void) {
1113 if (xatom
->getValue(client
.window
, XAtom::net_wm_name
,
1114 XAtom::utf8
, client
.title
) &&
1115 !client
.title
.empty()) {
1116 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
1119 //fall through to using WM_NAME
1120 if (xatom
->getValue(client
.window
, XAtom::wm_name
, XAtom::ansi
, client
.title
)
1121 && !client
.title
.empty()) {
1122 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
1125 // fall back to an internal default
1126 client
.title
= "Unnamed";
1127 xatom
->setValue(client
.window
, XAtom::net_wm_visible_name
, XAtom::utf8
,
1130 #ifdef DEBUG_WITH_ID
1131 // the 16 is the 8 chars of the debug text plus the number
1132 char *tmp
= new char[client
.title
.length() + 16];
1133 sprintf(tmp
, "%s; id: 0x%lx", client
.title
.c_str(), client
.window
);
1140 void BlackboxWindow::getWMIconName(void) {
1141 if (xatom
->getValue(client
.window
, XAtom::net_wm_icon_name
,
1142 XAtom::utf8
, client
.icon_title
) &&
1143 !client
.icon_title
.empty()) {
1144 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1147 //fall through to using WM_ICON_NAME
1148 if (xatom
->getValue(client
.window
, XAtom::wm_icon_name
, XAtom::ansi
,
1149 client
.icon_title
) &&
1150 !client
.icon_title
.empty()) {
1151 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1154 // fall back to using the main name
1155 client
.icon_title
= client
.title
;
1156 xatom
->setValue(client
.window
, XAtom::net_wm_visible_icon_name
, XAtom::utf8
,
1162 * Retrieve which WM Protocols are supported by the client window.
1163 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
1164 * window's decorations and allow the close behavior.
1165 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
1168 void BlackboxWindow::getWMProtocols(void) {
1172 if (XGetWMProtocols(blackbox
->getXDisplay(), client
.window
,
1173 &proto
, &num_return
)) {
1174 for (int i
= 0; i
< num_return
; ++i
) {
1175 if (proto
[i
] == xatom
->getAtom(XAtom::wm_delete_window
)) {
1176 decorations
|= Decor_Close
;
1177 functions
|= Func_Close
;
1178 } else if (proto
[i
] == xatom
->getAtom(XAtom::wm_take_focus
))
1179 flags
.send_focus_message
= True
;
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 XFlush(blackbox
->getXDisplay());
1638 void BlackboxWindow::configureShape(void) {
1639 XShapeCombineShape(blackbox
->getXDisplay(), frame
.window
, ShapeBounding
,
1640 frame
.margin
.left
- frame
.border_w
,
1641 frame
.margin
.top
- frame
.border_w
,
1642 client
.window
, ShapeBounding
, ShapeSet
);
1645 XRectangle xrect
[2];
1647 if (decorations
& Decor_Titlebar
) {
1648 xrect
[0].x
= xrect
[0].y
= -frame
.border_w
;
1649 xrect
[0].width
= frame
.rect
.width();
1650 xrect
[0].height
= frame
.title_h
+ (frame
.border_w
* 2);
1654 if (decorations
& Decor_Handle
) {
1655 xrect
[1].x
= -frame
.border_w
;
1656 xrect
[1].y
= frame
.rect
.height() - frame
.margin
.bottom
+
1657 frame
.mwm_border_w
- frame
.border_w
;
1658 xrect
[1].width
= frame
.rect
.width();
1659 xrect
[1].height
= frame
.handle_h
+ (frame
.border_w
* 2);
1663 XShapeCombineRectangles(blackbox
->getXDisplay(), frame
.window
,
1664 ShapeBounding
, 0, 0, xrect
, num
,
1665 ShapeUnion
, Unsorted
);
1669 void BlackboxWindow::clearShape(void) {
1670 XShapeCombineMask(blackbox
->getXDisplay(), frame
.window
, ShapeBounding
,
1671 frame
.margin
.left
- frame
.border_w
,
1672 frame
.margin
.top
- frame
.border_w
,
1678 bool BlackboxWindow::setInputFocus(void) {
1679 if (flags
.focused
) return True
;
1681 assert(flags
.stuck
|| // window must be on the current workspace or sticky
1682 blackbox_attrib
.workspace
== screen
->getCurrentWorkspaceID());
1685 We only do this check for normal windows and dialogs because other windows
1686 do this on purpose, such as kde's kicker, and we don't want to go moving
1689 if (window_type
== Type_Normal
|| window_type
== Type_Dialog
)
1690 if (! frame
.rect
.intersects(screen
->getRect())) {
1691 // client is outside the screen, move it to the center
1692 configure((screen
->getWidth() - frame
.rect
.width()) / 2,
1693 (screen
->getHeight() - frame
.rect
.height()) / 2,
1694 frame
.rect
.width(), frame
.rect
.height());
1697 if (client
.transientList
.size() > 0) {
1698 // transfer focus to any modal transients
1699 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1700 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1701 if ((*it
)->flags
.modal
) return (*it
)->setInputFocus();
1705 if (focus_mode
== F_LocallyActive
|| focus_mode
== F_Passive
) {
1706 XSetInputFocus(blackbox
->getXDisplay(), client
.window
,
1707 RevertToPointerRoot
, CurrentTime
);
1709 /* we could set the focus to none, since the window doesn't accept focus,
1710 * but we shouldn't set focus to nothing since this would surely make
1716 if (flags
.send_focus_message
) {
1718 ce
.xclient
.type
= ClientMessage
;
1719 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1720 ce
.xclient
.display
= blackbox
->getXDisplay();
1721 ce
.xclient
.window
= client
.window
;
1722 ce
.xclient
.format
= 32;
1723 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_take_focus
);
1724 ce
.xclient
.data
.l
[1] = blackbox
->getLastTime();
1725 ce
.xclient
.data
.l
[2] = 0l;
1726 ce
.xclient
.data
.l
[3] = 0l;
1727 ce
.xclient
.data
.l
[4] = 0l;
1728 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
,
1730 XFlush(blackbox
->getXDisplay());
1737 void BlackboxWindow::iconify(void) {
1738 if (flags
.iconic
|| ! (functions
& Func_Iconify
)) return;
1740 // We don't need to worry about resizing because resizing always grabs the X
1741 // server. This should only ever happen if using opaque moving.
1746 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1747 * we need to clear the event mask on client.window for a split second.
1748 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1749 * split second, leaving us with a ghost window... so, we need to do this
1750 * while the X server is grabbed
1752 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1753 StructureNotifyMask
;
1754 XGrabServer(blackbox
->getXDisplay());
1755 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1756 event_mask
& ~StructureNotifyMask
);
1757 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1758 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1759 XUngrabServer(blackbox
->getXDisplay());
1761 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1762 flags
.visible
= False
;
1763 flags
.iconic
= True
;
1765 setState(IconicState
);
1767 screen
->getWorkspace(blackbox_attrib
.workspace
)->removeWindow(this);
1769 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
1770 if (i
!= blackbox_attrib
.workspace
)
1771 screen
->getWorkspace(i
)->removeWindow(this, True
);
1774 if (isTransient()) {
1775 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1776 ! client
.transient_for
->flags
.iconic
) {
1777 // iconify our transient_for
1778 client
.transient_for
->iconify();
1782 screen
->addIcon(this);
1784 if (client
.transientList
.size() > 0) {
1785 // iconify all transients
1786 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1787 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1788 if (! (*it
)->flags
.iconic
) (*it
)->iconify();
1791 screen
->updateStackingList();
1795 void BlackboxWindow::show(void) {
1796 flags
.visible
= True
;
1797 flags
.iconic
= False
;
1799 current_state
= (flags
.shaded
) ? IconicState
: NormalState
;
1800 setState(current_state
);
1802 XMapWindow(blackbox
->getXDisplay(), client
.window
);
1803 XMapSubwindows(blackbox
->getXDisplay(), frame
.window
);
1804 XMapWindow(blackbox
->getXDisplay(), frame
.window
);
1809 XTranslateCoordinates(blackbox
->getXDisplay(), client
.window
,
1810 screen
->getRootWindow(),
1811 0, 0, &real_x
, &real_y
, &child
);
1812 fprintf(stderr
, "%s -- assumed: (%d, %d), real: (%d, %d)\n", getTitle(),
1813 client
.rect
.left(), client
.rect
.top(), real_x
, real_y
);
1814 assert(client
.rect
.left() == real_x
&& client
.rect
.top() == real_y
);
1819 void BlackboxWindow::deiconify(bool reassoc
, bool raise
) {
1820 if (flags
.iconic
|| reassoc
)
1821 screen
->reassociateWindow(this, BSENTINEL
, False
);
1822 else if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID())
1827 // reassociate and deiconify all transients
1828 if (reassoc
&& client
.transientList
.size() > 0) {
1829 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1830 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1831 (*it
)->deiconify(True
, False
);
1835 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1839 void BlackboxWindow::close(void) {
1840 if (! (functions
& Func_Close
)) return;
1843 ce
.xclient
.type
= ClientMessage
;
1844 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1845 ce
.xclient
.display
= blackbox
->getXDisplay();
1846 ce
.xclient
.window
= client
.window
;
1847 ce
.xclient
.format
= 32;
1848 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_delete_window
);
1849 ce
.xclient
.data
.l
[1] = CurrentTime
;
1850 ce
.xclient
.data
.l
[2] = 0l;
1851 ce
.xclient
.data
.l
[3] = 0l;
1852 ce
.xclient
.data
.l
[4] = 0l;
1853 XSendEvent(blackbox
->getXDisplay(), client
.window
, False
, NoEventMask
, &ce
);
1854 XFlush(blackbox
->getXDisplay());
1858 void BlackboxWindow::withdraw(void) {
1859 // We don't need to worry about resizing because resizing always grabs the X
1860 // server. This should only ever happen if using opaque moving.
1864 flags
.visible
= False
;
1865 flags
.iconic
= False
;
1867 setState(current_state
);
1869 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
1871 XGrabServer(blackbox
->getXDisplay());
1873 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1874 StructureNotifyMask
;
1875 XSelectInput(blackbox
->getXDisplay(), client
.window
,
1876 event_mask
& ~StructureNotifyMask
);
1877 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
1878 XSelectInput(blackbox
->getXDisplay(), client
.window
, event_mask
);
1880 XUngrabServer(blackbox
->getXDisplay());
1884 void BlackboxWindow::maximize(unsigned int button
) {
1885 if (! (functions
& Func_Maximize
)) return;
1887 // We don't need to worry about resizing because resizing always grabs the X
1888 // server. This should only ever happen if using opaque moving.
1892 if (flags
.maximized
) {
1893 flags
.maximized
= 0;
1895 blackbox_attrib
.flags
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1896 blackbox_attrib
.attrib
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1899 when a resize finishes, maximize(0) is called to clear any maximization
1900 flags currently set. Otherwise it still thinks it is maximized.
1901 so we do not need to call configure() because resizing will handle it
1903 if (! flags
.resizing
)
1904 configure(blackbox_attrib
.premax_x
, blackbox_attrib
.premax_y
,
1905 blackbox_attrib
.premax_w
, blackbox_attrib
.premax_h
);
1907 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
1908 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
1910 redrawAllButtons(); // in case it is not called in configure()
1911 setState(current_state
);
1915 blackbox_attrib
.premax_x
= frame
.rect
.x();
1916 blackbox_attrib
.premax_y
= frame
.rect
.y();
1917 blackbox_attrib
.premax_w
= frame
.rect
.width();
1918 // use client.rect so that clients can be restored even if shaded
1919 blackbox_attrib
.premax_h
=
1920 client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
;
1923 if (screen
->isXineramaActive() && blackbox
->doXineramaMaximizing()) {
1924 // find the area to use
1925 RectList availableAreas
= screen
->allAvailableAreas();
1926 RectList::iterator it
, end
= availableAreas
.end();
1928 for (it
= availableAreas
.begin(); it
!= end
; ++it
)
1929 if (it
->intersects(frame
.rect
)) break;
1930 if (it
== end
) // the window isn't inside an area
1931 it
= availableAreas
.begin(); // so just default to the first one
1933 frame
.changing
= *it
;
1936 frame
.changing
= screen
->availableArea();
1940 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1941 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1945 blackbox_attrib
.flags
|= AttribMaxVert
;
1946 blackbox_attrib
.attrib
|= AttribMaxVert
;
1948 frame
.changing
.setX(frame
.rect
.x());
1949 frame
.changing
.setWidth(frame
.rect
.width());
1953 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1954 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1956 frame
.changing
.setY(frame
.rect
.y());
1957 frame
.changing
.setHeight(frame
.rect
.height());
1964 blackbox_attrib
.flags
^= AttribShaded
;
1965 blackbox_attrib
.attrib
^= AttribShaded
;
1966 flags
.shaded
= False
;
1969 flags
.maximized
= button
;
1971 configure(frame
.changing
.x(), frame
.changing
.y(),
1972 frame
.changing
.width(), frame
.changing
.height());
1974 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1975 redrawAllButtons(); // in case it is not called in configure()
1976 setState(current_state
);
1980 // re-maximizes the window to take into account availableArea changes
1981 void BlackboxWindow::remaximize(void) {
1983 // we only update the window's attributes otherwise we lose the shade bit
1984 switch(flags
.maximized
) {
1986 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1987 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1991 blackbox_attrib
.flags
|= AttribMaxVert
;
1992 blackbox_attrib
.attrib
|= AttribMaxVert
;
1996 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1997 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
2003 // save the original dimensions because maximize will wipe them out
2004 int premax_x
= blackbox_attrib
.premax_x
,
2005 premax_y
= blackbox_attrib
.premax_y
,
2006 premax_w
= blackbox_attrib
.premax_w
,
2007 premax_h
= blackbox_attrib
.premax_h
;
2009 unsigned int button
= flags
.maximized
;
2010 flags
.maximized
= 0; // trick maximize() into working
2013 // restore saved values
2014 blackbox_attrib
.premax_x
= premax_x
;
2015 blackbox_attrib
.premax_y
= premax_y
;
2016 blackbox_attrib
.premax_w
= premax_w
;
2017 blackbox_attrib
.premax_h
= premax_h
;
2021 void BlackboxWindow::setWorkspace(unsigned int n
) {
2022 blackbox_attrib
.flags
|= AttribWorkspace
;
2023 blackbox_attrib
.workspace
= n
;
2024 if (n
== BSENTINEL
) { // iconified window
2026 we set the workspace to 'all workspaces' so that taskbars will show the
2027 window. otherwise, it made uniconifying a window imposible without the
2028 blackbox workspace menu
2032 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
, n
);
2036 void BlackboxWindow::shade(void) {
2038 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
2039 frame
.inside_w
, frame
.inside_h
);
2040 flags
.shaded
= False
;
2041 blackbox_attrib
.flags
^= AttribShaded
;
2042 blackbox_attrib
.attrib
^= AttribShaded
;
2044 setState(NormalState
);
2046 // set the frame rect to the normal size
2047 frame
.rect
.setHeight(client
.rect
.height() + frame
.margin
.top
+
2048 frame
.margin
.bottom
);
2050 if (! (decorations
& Decor_Titlebar
))
2051 return; // can't shade it without a titlebar!
2053 XResizeWindow(blackbox
->getXDisplay(), frame
.window
,
2054 frame
.inside_w
, frame
.title_h
);
2055 flags
.shaded
= True
;
2056 blackbox_attrib
.flags
|= AttribShaded
;
2057 blackbox_attrib
.attrib
|= AttribShaded
;
2059 setState(IconicState
);
2061 // set the frame rect to the shaded size
2062 frame
.rect
.setHeight(frame
.title_h
+ (frame
.border_w
* 2));
2068 * (Un)Sticks a window and its relatives.
2070 void BlackboxWindow::stick(void) {
2072 blackbox_attrib
.flags
^= AttribOmnipresent
;
2073 blackbox_attrib
.attrib
^= AttribOmnipresent
;
2075 flags
.stuck
= False
;
2077 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
2078 if (i
!= blackbox_attrib
.workspace
)
2079 screen
->getWorkspace(i
)->removeWindow(this, True
);
2082 screen
->reassociateWindow(this, BSENTINEL
, True
);
2083 // temporary fix since sticky windows suck. set the hint to what we
2084 // actually hold in our data.
2085 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
2086 blackbox_attrib
.workspace
);
2088 setState(current_state
);
2092 blackbox_attrib
.flags
|= AttribOmnipresent
;
2093 blackbox_attrib
.attrib
|= AttribOmnipresent
;
2095 // temporary fix since sticky windows suck. set the hint to a different
2096 // value than that contained in the class' data.
2097 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
2100 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
2101 if (i
!= blackbox_attrib
.workspace
)
2102 screen
->getWorkspace(i
)->addWindow(this, False
, True
);
2104 setState(current_state
);
2110 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
2111 client
.transient_for
->isStuck() != flags
.stuck
)
2112 client
.transient_for
->stick();
2113 // go down the chain
2114 BlackboxWindowList::iterator it
;
2115 const BlackboxWindowList::iterator end
= client
.transientList
.end();
2116 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
2117 if ((*it
)->isStuck() != flags
.stuck
)
2122 void BlackboxWindow::redrawWindowFrame(void) const {
2123 if (decorations
& Decor_Titlebar
) {
2124 if (flags
.focused
) {
2126 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2127 frame
.title
, frame
.ftitle
);
2129 XSetWindowBackground(blackbox
->getXDisplay(),
2130 frame
.title
, frame
.ftitle_pixel
);
2133 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2134 frame
.title
, frame
.utitle
);
2136 XSetWindowBackground(blackbox
->getXDisplay(),
2137 frame
.title
, frame
.utitle_pixel
);
2139 XClearWindow(blackbox
->getXDisplay(), frame
.title
);
2145 if (decorations
& Decor_Handle
) {
2146 if (flags
.focused
) {
2148 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2149 frame
.handle
, frame
.fhandle
);
2151 XSetWindowBackground(blackbox
->getXDisplay(),
2152 frame
.handle
, frame
.fhandle_pixel
);
2155 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2156 frame
.left_grip
, frame
.fgrip
);
2157 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2158 frame
.right_grip
, frame
.fgrip
);
2160 XSetWindowBackground(blackbox
->getXDisplay(),
2161 frame
.left_grip
, frame
.fgrip_pixel
);
2162 XSetWindowBackground(blackbox
->getXDisplay(),
2163 frame
.right_grip
, frame
.fgrip_pixel
);
2167 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2168 frame
.handle
, frame
.uhandle
);
2170 XSetWindowBackground(blackbox
->getXDisplay(),
2171 frame
.handle
, frame
.uhandle_pixel
);
2174 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2175 frame
.left_grip
, frame
.ugrip
);
2176 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2177 frame
.right_grip
, frame
.ugrip
);
2179 XSetWindowBackground(blackbox
->getXDisplay(),
2180 frame
.left_grip
, frame
.ugrip_pixel
);
2181 XSetWindowBackground(blackbox
->getXDisplay(),
2182 frame
.right_grip
, frame
.ugrip_pixel
);
2185 XClearWindow(blackbox
->getXDisplay(), frame
.handle
);
2186 XClearWindow(blackbox
->getXDisplay(), frame
.left_grip
);
2187 XClearWindow(blackbox
->getXDisplay(), frame
.right_grip
);
2190 if (decorations
& Decor_Border
) {
2192 XSetWindowBorder(blackbox
->getXDisplay(),
2193 frame
.plate
, frame
.fborder_pixel
);
2195 XSetWindowBorder(blackbox
->getXDisplay(),
2196 frame
.plate
, frame
.uborder_pixel
);
2201 void BlackboxWindow::setFocusFlag(bool focus
) {
2202 // only focus a window if it is visible
2203 if (focus
&& ! flags
.visible
)
2206 flags
.focused
= focus
;
2208 redrawWindowFrame();
2211 blackbox
->setFocusedWindow(this);
2215 void BlackboxWindow::installColormap(bool install
) {
2216 int i
= 0, ncmap
= 0;
2217 Colormap
*cmaps
= XListInstalledColormaps(blackbox
->getXDisplay(),
2218 client
.window
, &ncmap
);
2220 XWindowAttributes wattrib
;
2221 if (XGetWindowAttributes(blackbox
->getXDisplay(),
2222 client
.window
, &wattrib
)) {
2224 // install the window's colormap
2225 for (i
= 0; i
< ncmap
; i
++) {
2226 if (*(cmaps
+ i
) == wattrib
.colormap
)
2227 // this window is using an installed color map... do not install
2230 // otherwise, install the window's colormap
2232 XInstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2234 // uninstall the window's colormap
2235 for (i
= 0; i
< ncmap
; i
++) {
2236 if (*(cmaps
+ i
) == wattrib
.colormap
)
2237 // we found the colormap to uninstall
2238 XUninstallColormap(blackbox
->getXDisplay(), wattrib
.colormap
);
2248 void BlackboxWindow::setAllowedActions(void) {
2252 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_shade
);
2253 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_change_desktop
);
2254 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_close
);
2256 if (functions
& Func_Move
)
2257 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_move
);
2258 if (functions
& Func_Resize
)
2259 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_resize
);
2260 if (functions
& Func_Maximize
) {
2261 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_horz
);
2262 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_vert
);
2265 xatom
->setValue(client
.window
, XAtom::net_wm_allowed_actions
, XAtom::atom
,
2270 void BlackboxWindow::setState(unsigned long new_state
) {
2271 current_state
= new_state
;
2273 unsigned long state
[2];
2274 state
[0] = current_state
;
2276 xatom
->setValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
, state
, 2);
2278 xatom
->setValue(client
.window
, XAtom::blackbox_attributes
,
2279 XAtom::blackbox_attributes
, (unsigned long *)&blackbox_attrib
,
2280 PropBlackboxAttributesElements
);
2285 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_modal
);
2287 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_shaded
);
2289 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_hidden
);
2290 if (flags
.skip_taskbar
)
2291 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
);
2292 if (flags
.skip_pager
)
2293 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_pager
);
2294 if (flags
.fullscreen
)
2295 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_fullscreen
);
2296 if (flags
.maximized
== 1 || flags
.maximized
== 2)
2297 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_vert
);
2298 if (flags
.maximized
== 1 || flags
.maximized
== 3)
2299 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_horz
);
2300 xatom
->setValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
2305 bool BlackboxWindow::getState(void) {
2306 bool ret
= xatom
->getValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
,
2308 if (! ret
) current_state
= 0;
2313 void BlackboxWindow::restoreAttributes(void) {
2314 unsigned long num
= PropBlackboxAttributesElements
;
2315 BlackboxAttributes
*net
;
2316 if (! xatom
->getValue(client
.window
, XAtom::blackbox_attributes
,
2317 XAtom::blackbox_attributes
, num
,
2318 (unsigned long **)&net
))
2320 if (num
< PropBlackboxAttributesElements
) {
2325 if (net
->flags
& AttribShaded
&& net
->attrib
& AttribShaded
) {
2326 flags
.shaded
= False
;
2327 unsigned long orig_state
= current_state
;
2331 At this point in the life of a window, current_state should only be set
2332 to IconicState if the window was an *icon*, not if it was shaded.
2334 if (orig_state
!= IconicState
)
2335 current_state
= WithdrawnState
;
2338 if (net
->workspace
!= screen
->getCurrentWorkspaceID() &&
2339 net
->workspace
< screen
->getWorkspaceCount())
2340 screen
->reassociateWindow(this, net
->workspace
, True
);
2342 if ((blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID()) &&
2343 (blackbox_attrib
.workspace
< screen
->getWorkspaceCount())) {
2344 // set to WithdrawnState so it will be mapped on the new workspace
2345 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2346 } else if (current_state
== WithdrawnState
) {
2347 // the window is on this workspace and is Withdrawn, so it is waiting to
2349 current_state
= NormalState
;
2352 if (net
->flags
& AttribOmnipresent
&& net
->attrib
& AttribOmnipresent
&&
2356 // if the window was on another workspace, it was going to be hidden. this
2357 // specifies that the window should be mapped since it is sticky.
2358 if (current_state
== WithdrawnState
) current_state
= NormalState
;
2361 if (net
->flags
& AttribMaxHoriz
|| net
->flags
& AttribMaxVert
) {
2362 int x
= net
->premax_x
, y
= net
->premax_y
;
2363 unsigned int w
= net
->premax_w
, h
= net
->premax_h
;
2364 flags
.maximized
= 0;
2367 if ((net
->flags
& AttribMaxHoriz
) &&
2368 (net
->flags
& AttribMaxVert
))
2369 m
= (net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
2370 else if (net
->flags
& AttribMaxVert
)
2371 m
= (net
->attrib
& AttribMaxVert
) ? 2 : 0;
2372 else if (net
->flags
& AttribMaxHoriz
)
2373 m
= (net
->attrib
& AttribMaxHoriz
) ? 3 : 0;
2377 blackbox_attrib
.premax_x
= x
;
2378 blackbox_attrib
.premax_y
= y
;
2379 blackbox_attrib
.premax_w
= w
;
2380 blackbox_attrib
.premax_h
= h
;
2383 if (net
->flags
& AttribDecoration
) {
2384 switch (net
->decoration
) {
2389 /* since tools only let you toggle this anyways, we'll just make that all
2390 it supports for now.
2401 // with the state set it will then be the map event's job to read the
2402 // window's state and behave accordingly
2409 * Positions the Rect r according the the client window position and
2412 void BlackboxWindow::applyGravity(Rect
&r
) {
2413 // apply horizontal window gravity
2414 switch (client
.win_gravity
) {
2416 case NorthWestGravity
:
2417 case SouthWestGravity
:
2419 r
.setX(client
.rect
.x());
2425 r
.setX(client
.rect
.x() - (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2428 case NorthEastGravity
:
2429 case SouthEastGravity
:
2431 r
.setX(client
.rect
.x() - frame
.margin
.left
- frame
.margin
.right
+ 2);
2436 r
.setX(client
.rect
.x() - frame
.margin
.left
);
2440 // apply vertical window gravity
2441 switch (client
.win_gravity
) {
2443 case NorthWestGravity
:
2444 case NorthEastGravity
:
2446 r
.setY(client
.rect
.y());
2452 r
.setY(client
.rect
.y() - (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2455 case SouthWestGravity
:
2456 case SouthEastGravity
:
2458 r
.setY(client
.rect
.y() - frame
.margin
.top
- frame
.margin
.bottom
+ 2);
2463 r
.setY(client
.rect
.y() - frame
.margin
.top
);
2470 * The reverse of the applyGravity function.
2472 * Positions the Rect r according to the frame window position and
2475 void BlackboxWindow::restoreGravity(Rect
&r
) {
2476 // restore horizontal window gravity
2477 switch (client
.win_gravity
) {
2479 case NorthWestGravity
:
2480 case SouthWestGravity
:
2482 r
.setX(frame
.rect
.x());
2488 r
.setX(frame
.rect
.x() + (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2491 case NorthEastGravity
:
2492 case SouthEastGravity
:
2494 r
.setX(frame
.rect
.x() + frame
.margin
.left
+ frame
.margin
.right
- 2);
2499 r
.setX(frame
.rect
.x() + frame
.margin
.left
);
2503 // restore vertical window gravity
2504 switch (client
.win_gravity
) {
2506 case NorthWestGravity
:
2507 case NorthEastGravity
:
2509 r
.setY(frame
.rect
.y());
2515 r
.setY(frame
.rect
.y() + (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2518 case SouthWestGravity
:
2519 case SouthEastGravity
:
2521 r
.setY(frame
.rect
.y() + frame
.margin
.top
+ frame
.margin
.bottom
- 2);
2526 r
.setY(frame
.rect
.y() + frame
.margin
.top
);
2532 void BlackboxWindow::redrawLabel(void) const {
2533 if (flags
.focused
) {
2535 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2536 frame
.label
, frame
.flabel
);
2538 XSetWindowBackground(blackbox
->getXDisplay(),
2539 frame
.label
, frame
.flabel_pixel
);
2542 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(),
2543 frame
.label
, frame
.ulabel
);
2545 XSetWindowBackground(blackbox
->getXDisplay(),
2546 frame
.label
, frame
.ulabel_pixel
);
2548 XClearWindow(blackbox
->getXDisplay(), frame
.label
);
2550 WindowStyle
*style
= screen
->getWindowStyle();
2552 int pos
= frame
.bevel_w
* 2;
2553 style
->doJustify(client
.title
.c_str(), pos
, frame
.label_w
, frame
.bevel_w
* 4);
2554 style
->font
->drawString(frame
.label
, pos
, 1,
2555 (flags
.focused
? style
->l_text_focus
:
2556 style
->l_text_unfocus
),
2561 void BlackboxWindow::redrawAllButtons(void) const {
2562 if (frame
.iconify_button
) redrawIconifyButton(False
);
2563 if (frame
.maximize_button
) redrawMaximizeButton(flags
.maximized
);
2564 if (frame
.close_button
) redrawCloseButton(False
);
2565 if (frame
.stick_button
) redrawStickyButton(flags
.stuck
);
2569 void BlackboxWindow::redrawButton(bool pressed
, Window win
,
2570 Pixmap fppix
, unsigned long fppixel
,
2571 Pixmap uppix
, unsigned long uppixel
,
2572 Pixmap fpix
, unsigned long fpixel
,
2573 Pixmap upix
, unsigned long upixel
) const {
2578 if (flags
.focused
) {
2586 if (flags
.focused
) {
2596 XSetWindowBackgroundPixmap(blackbox
->getXDisplay(), win
, p
);
2598 XSetWindowBackground(blackbox
->getXDisplay(), win
, pix
);
2602 void BlackboxWindow::redrawIconifyButton(bool pressed
) const {
2603 redrawButton(pressed
, frame
.iconify_button
,
2604 frame
.pfbutton
, frame
.pfbutton_pixel
,
2605 frame
.pubutton
, frame
.pubutton_pixel
,
2606 frame
.fbutton
, frame
.fbutton_pixel
,
2607 frame
.ubutton
, frame
.ubutton_pixel
);
2609 XClearWindow(blackbox
->getXDisplay(), frame
.iconify_button
);
2610 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2611 screen
->getWindowStyle()->b_pic_unfocus
);
2613 PixmapMask pm
= screen
->getWindowStyle()->icon_button
;
2615 if (screen
->getWindowStyle()->icon_button
.mask
!= None
) {
2616 XSetClipMask(blackbox
->getXDisplay(), pen
.gc(), pm
.mask
);
2617 XSetClipOrigin(blackbox
->getXDisplay(), pen
.gc(),
2618 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2);
2620 XFillRectangle(blackbox
->getXDisplay(), frame
.iconify_button
, pen
.gc(),
2621 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2,
2622 (frame
.button_w
+ pm
.w
)/2, (frame
.button_w
+ pm
.h
)/2);
2624 XSetClipMask(blackbox
->getXDisplay(), pen
.gc(), None
);
2625 XSetClipOrigin(blackbox
->getXDisplay(), pen
.gc(), 0, 0);
2627 XDrawRectangle(blackbox
->getXDisplay(), frame
.iconify_button
, pen
.gc(),
2628 2, (frame
.button_w
- 5), (frame
.button_w
- 5), 2);
2633 void BlackboxWindow::redrawMaximizeButton(bool pressed
) const {
2634 redrawButton(pressed
, frame
.maximize_button
,
2635 frame
.pfbutton
, frame
.pfbutton_pixel
,
2636 frame
.pubutton
, frame
.pubutton_pixel
,
2637 frame
.fbutton
, frame
.fbutton_pixel
,
2638 frame
.ubutton
, frame
.ubutton_pixel
);
2640 XClearWindow(blackbox
->getXDisplay(), frame
.maximize_button
);
2642 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2643 screen
->getWindowStyle()->b_pic_unfocus
);
2645 PixmapMask pm
= screen
->getWindowStyle()->max_button
;
2647 if (pm
.mask
!= None
) {
2648 XSetClipMask(blackbox
->getXDisplay(), pen
.gc(), pm
.mask
);
2649 XSetClipOrigin(blackbox
->getXDisplay(), pen
.gc(),
2650 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2);
2652 XFillRectangle(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2653 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2,
2654 (frame
.button_w
+ pm
.w
)/2, (frame
.button_w
+ pm
.h
)/2);
2656 XSetClipOrigin(blackbox
->getXDisplay(), pen
.gc(), 0, 0 );
2657 XSetClipMask( blackbox
->getXDisplay(), pen
.gc(), None
);
2659 XDrawRectangle(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2660 2, 2, (frame
.button_w
- 5), (frame
.button_w
- 5));
2661 XDrawLine(blackbox
->getXDisplay(), frame
.maximize_button
, pen
.gc(),
2662 2, 3, (frame
.button_w
- 3), 3);
2667 void BlackboxWindow::redrawCloseButton(bool pressed
) const {
2668 redrawButton(pressed
, frame
.close_button
,
2669 frame
.pfbutton
, frame
.pfbutton_pixel
,
2670 frame
.pubutton
, frame
.pubutton_pixel
,
2671 frame
.fbutton
, frame
.fbutton_pixel
,
2672 frame
.ubutton
, frame
.ubutton_pixel
);
2674 XClearWindow(blackbox
->getXDisplay(), frame
.close_button
);
2676 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2677 screen
->getWindowStyle()->b_pic_unfocus
);
2679 PixmapMask pm
= screen
->getWindowStyle()->close_button
;
2681 if (pm
.mask
!= None
) {
2682 XSetClipMask(blackbox
->getXDisplay(), pen
.gc(), pm
.mask
);
2683 XSetClipOrigin(blackbox
->getXDisplay(), pen
.gc(),
2684 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2);
2686 XFillRectangle(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2687 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2,
2688 (frame
.button_w
+ pm
.w
)/2, (frame
.button_w
+ pm
.h
)/2);
2691 XSetClipOrigin(blackbox
->getXDisplay(), pen
.gc(), 0, 0 );
2692 XSetClipMask( blackbox
->getXDisplay(), pen
.gc(), None
);
2694 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2695 2, 2, (frame
.button_w
- 3), (frame
.button_w
- 3));
2696 XDrawLine(blackbox
->getXDisplay(), frame
.close_button
, pen
.gc(),
2697 2, (frame
.button_w
- 3), (frame
.button_w
- 3), 2);
2701 void BlackboxWindow::redrawStickyButton(bool pressed
) const {
2702 redrawButton(pressed
, frame
.stick_button
,
2703 frame
.pfbutton
, frame
.pfbutton_pixel
,
2704 frame
.pubutton
, frame
.pubutton_pixel
,
2705 frame
.fbutton
, frame
.fbutton_pixel
,
2706 frame
.ubutton
, frame
.ubutton_pixel
);
2708 XClearWindow(blackbox
->getXDisplay(), frame
.stick_button
);
2710 BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2711 screen
->getWindowStyle()->b_pic_unfocus
);
2713 PixmapMask pm
= screen
->getWindowStyle()->stick_button
;
2715 if (pm
.mask
!= None
) {
2716 XSetClipMask(blackbox
->getXDisplay(), pen
.gc(), pm
.mask
);
2717 XSetClipOrigin(blackbox
->getXDisplay(), pen
.gc(),
2718 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2);
2720 XFillRectangle(blackbox
->getXDisplay(), frame
.stick_button
, pen
.gc(),
2721 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2,
2722 (frame
.button_w
+ pm
.w
)/2, (frame
.button_w
+ pm
.h
)/2);
2725 XSetClipOrigin(blackbox
->getXDisplay(), pen
.gc(), 0, 0 );
2726 XSetClipMask( blackbox
->getXDisplay(), pen
.gc(), None
);
2728 XFillRectangle(blackbox
->getXDisplay(), frame
.stick_button
, pen
.gc(),
2729 frame
.button_w
/2 - 1, frame
.button_w
/2 -1, 2, 2 );
2733 void BlackboxWindow::mapRequestEvent(const XMapRequestEvent
*re
) {
2734 if (re
->window
!= client
.window
)
2738 fprintf(stderr
, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2743 Even though the window wants to be shown, if it is not on the current
2744 workspace, then it isn't going to be shown right now.
2746 if (! flags
.stuck
&&
2747 blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID() &&
2748 blackbox_attrib
.workspace
< screen
->getWorkspaceCount())
2749 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2751 switch (current_state
) {
2756 case WithdrawnState
:
2765 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2767 if (! blackbox
->isStartup()) {
2768 XSync(blackbox
->getXDisplay(), False
); // make sure the frame is mapped
2769 if (screen
->doFocusNew() || (isTransient() && getTransientFor() &&
2770 getTransientFor()->isFocused())) {
2773 if (screen
->getPlacementPolicy() == BScreen::ClickMousePlacement
) {
2777 XQueryPointer(blackbox
->getXDisplay(), screen
->getRootWindow(),
2778 &r
, &c
, &rx
, &ry
, &x
, &y
, &m
);
2788 void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent
*ue
) {
2789 if (ue
->window
!= client
.window
)
2793 fprintf(stderr
, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2797 screen
->unmanageWindow(this, False
);
2801 void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent
*de
) {
2802 if (de
->window
!= client
.window
)
2806 fprintf(stderr
, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2810 screen
->unmanageWindow(this, False
);
2814 void BlackboxWindow::reparentNotifyEvent(const XReparentEvent
*re
) {
2815 if (re
->window
!= client
.window
|| re
->parent
== frame
.plate
)
2819 fprintf(stderr
, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2820 "0x%lx.\n", client
.window
, re
->parent
);
2825 XPutBackEvent(blackbox
->getXDisplay(), &ev
);
2826 screen
->unmanageWindow(this, True
);
2830 void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent
*pe
) {
2831 if (pe
->state
== PropertyDelete
|| ! validateClient())
2835 fprintf(stderr
, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n",
2841 case XA_WM_CLIENT_MACHINE
:
2845 case XA_WM_TRANSIENT_FOR
: {
2846 bool s
= flags
.stuck
;
2848 // determine if this is a transient window
2851 if (flags
.stuck
!= s
) stick();
2853 // adjust the window decorations based on transience
2854 if (isTransient()) {
2855 functions
&= ~Func_Maximize
;
2856 setAllowedActions();
2868 case XA_WM_ICON_NAME
:
2870 if (flags
.iconic
) screen
->propagateWindowName(this);
2873 case XAtom::net_wm_name
:
2877 if (decorations
& Decor_Titlebar
)
2880 screen
->propagateWindowName(this);
2883 case XA_WM_NORMAL_HINTS
: {
2886 if ((client
.normal_hint_flags
& PMinSize
) &&
2887 (client
.normal_hint_flags
& PMaxSize
)) {
2888 // the window now can/can't resize itself, so the buttons need to be
2891 if (client
.max_width
<= client
.min_width
&&
2892 client
.max_height
<= client
.min_height
) {
2893 functions
&= ~(Func_Resize
| Func_Maximize
);
2895 if (! isTransient())
2896 functions
|= Func_Maximize
;
2897 functions
|= Func_Resize
;
2900 setAllowedActions();
2904 Rect old_rect
= frame
.rect
;
2908 if (old_rect
!= frame
.rect
)
2915 if (pe
->atom
== xatom
->getAtom(XAtom::wm_protocols
)) {
2918 if ((decorations
& Decor_Close
) && (! frame
.close_button
)) {
2919 createCloseButton();
2920 if (decorations
& Decor_Titlebar
) {
2921 positionButtons(True
);
2922 XMapSubwindows(blackbox
->getXDisplay(), frame
.title
);
2925 } else if (pe
->atom
== xatom
->getAtom(XAtom::net_wm_strut
)) {
2934 void BlackboxWindow::exposeEvent(const XExposeEvent
*ee
) {
2936 fprintf(stderr
, "BlackboxWindow::exposeEvent() for 0x%lx\n", client
.window
);
2939 if (frame
.label
== ee
->window
&& (decorations
& Decor_Titlebar
))
2941 else if (frame
.close_button
== ee
->window
)
2942 redrawCloseButton(False
);
2943 else if (frame
.maximize_button
== ee
->window
)
2944 redrawMaximizeButton(flags
.maximized
);
2945 else if (frame
.iconify_button
== ee
->window
)
2946 redrawIconifyButton(False
);
2947 else if (frame
.stick_button
== ee
->window
)
2948 redrawStickyButton(flags
.stuck
);
2952 void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent
*cr
) {
2953 if (cr
->window
!= client
.window
|| flags
.iconic
)
2956 if (cr
->value_mask
& CWBorderWidth
)
2957 client
.old_bw
= cr
->border_width
;
2959 if (cr
->value_mask
& (CWX
| CWY
| CWWidth
| CWHeight
)) {
2960 frame
.changing
= frame
.rect
;
2962 if (cr
->value_mask
& (CWX
| CWY
)) {
2963 if (cr
->value_mask
& CWX
)
2964 client
.rect
.setX(cr
->x
);
2965 if (cr
->value_mask
& CWY
)
2966 client
.rect
.setY(cr
->y
);
2968 applyGravity(frame
.changing
);
2971 if (cr
->value_mask
& (CWWidth
| CWHeight
)) {
2972 if (cr
->value_mask
& CWWidth
)
2973 frame
.changing
.setWidth(cr
->width
+
2974 frame
.margin
.left
+ frame
.margin
.right
);
2976 if (cr
->value_mask
& CWHeight
)
2977 frame
.changing
.setHeight(cr
->height
+
2978 frame
.margin
.top
+ frame
.margin
.bottom
);
2981 if a position change has been specified, then that position will be
2982 used instead of determining a position based on the window's gravity.
2984 if (! (cr
->value_mask
& (CWX
| CWY
))) {
2986 switch (client
.win_gravity
) {
2987 case NorthEastGravity
:
2991 case SouthWestGravity
:
2993 corner
= BottomLeft
;
2995 case SouthEastGravity
:
2996 corner
= BottomRight
;
2998 default: // NorthWest, Static, etc
3005 configure(frame
.changing
.x(), frame
.changing
.y(),
3006 frame
.changing
.width(), frame
.changing
.height());
3009 if (cr
->value_mask
& CWStackMode
&& !isDesktop()) {
3010 switch (cr
->detail
) {
3013 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
3019 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3026 void BlackboxWindow::buttonPressEvent(const XButtonEvent
*be
) {
3028 fprintf(stderr
, "BlackboxWindow::buttonPressEvent() for 0x%lx\n",
3032 if (frame
.maximize_button
== be
->window
&& be
->button
<= 3) {
3033 redrawMaximizeButton(True
);
3034 } else if (be
->button
== 1 || (be
->button
== 3 && be
->state
== mod_mask
)) {
3035 if (! flags
.focused
)
3038 if (frame
.iconify_button
== be
->window
) {
3039 redrawIconifyButton(True
);
3040 } else if (frame
.close_button
== be
->window
) {
3041 redrawCloseButton(True
);
3042 } else if (frame
.stick_button
== be
->window
) {
3043 redrawStickyButton(True
);
3044 } else if (frame
.plate
== be
->window
) {
3045 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3047 XAllowEvents(blackbox
->getXDisplay(), ReplayPointer
, be
->time
);
3049 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
3050 if (((be
->time
- lastButtonPressTime
) <=
3051 blackbox
->getDoubleClickInterval()) ||
3052 (be
->state
== ControlMask
)) {
3053 lastButtonPressTime
= 0;
3056 lastButtonPressTime
= be
->time
;
3060 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3062 } else if (be
->button
== 2 && (be
->window
!= frame
.iconify_button
) &&
3063 (be
->window
!= frame
.close_button
) &&
3064 (be
->window
!= frame
.stick_button
)) {
3065 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
3067 } else if (be
->button
== 4) {
3068 if ((be
->window
== frame
.label
||
3069 be
->window
== frame
.title
||
3070 be
->window
== frame
.maximize_button
||
3071 be
->window
== frame
.iconify_button
||
3072 be
->window
== frame
.close_button
||
3073 be
->window
== frame
.stick_button
) &&
3077 } else if (be
->button
== 5) {
3078 if ((be
->window
== frame
.label
||
3079 be
->window
== frame
.title
||
3080 be
->window
== frame
.maximize_button
||
3081 be
->window
== frame
.iconify_button
||
3082 be
->window
== frame
.close_button
||
3083 be
->window
== frame
.stick_button
) &&
3090 void BlackboxWindow::buttonReleaseEvent(const XButtonEvent
*re
) {
3092 fprintf(stderr
, "BlackboxWindow::buttonReleaseEvent() for 0x%lx\n",
3096 if (re
->window
== frame
.maximize_button
&&
3097 re
->button
>= 1 && re
->button
<= 3) {
3098 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3099 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
3100 maximize(re
->button
);
3102 redrawMaximizeButton(flags
.maximized
);
3104 } else if (re
->window
== frame
.iconify_button
&& re
->button
== 1) {
3105 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3106 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
3109 redrawIconifyButton(False
);
3111 } else if (re
->window
== frame
.stick_button
&& re
->button
== 1) {
3112 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3113 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
3116 redrawStickyButton(False
);
3118 } else if (re
->window
== frame
.close_button
& re
->button
== 1) {
3119 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3120 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
)))
3122 redrawCloseButton(False
);
3123 } else if (flags
.moving
) {
3125 } else if (flags
.resizing
) {
3127 } else if (re
->window
== frame
.window
) {
3128 if (re
->button
== 2 && re
->state
== mod_mask
)
3129 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3135 void BlackboxWindow::beginMove(int x_root
, int y_root
) {
3136 if (! (functions
& Func_Move
)) return;
3138 assert(! (flags
.resizing
|| flags
.moving
));
3141 Only one window can be moved/resized at a time. If another window is already
3142 being moved or resized, then stop it before whating to work with this one.
3144 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3145 if (changing
&& changing
!= this) {
3146 if (changing
->flags
.moving
)
3147 changing
->endMove();
3148 else // if (changing->flags.resizing)
3149 changing
->endResize();
3152 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3153 PointerMotionMask
| ButtonReleaseMask
,
3154 GrabModeAsync
, GrabModeAsync
,
3155 None
, blackbox
->getMoveCursor(), CurrentTime
);
3157 flags
.moving
= True
;
3158 blackbox
->setChangingWindow(this);
3160 if (! screen
->doOpaqueMove()) {
3161 XGrabServer(blackbox
->getXDisplay());
3163 frame
.changing
= frame
.rect
;
3164 screen
->showPosition(frame
.changing
.x(), frame
.changing
.y());
3166 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3170 frame
.changing
.width() - 1,
3171 frame
.changing
.height() - 1);
3174 frame
.grab_x
= x_root
- frame
.rect
.x() - frame
.border_w
;
3175 frame
.grab_y
= y_root
- frame
.rect
.y() - frame
.border_w
;
3179 void BlackboxWindow::doMove(int x_root
, int y_root
) {
3180 assert(flags
.moving
);
3181 assert(blackbox
->getChangingWindow() == this);
3183 int dx
= x_root
- frame
.grab_x
, dy
= y_root
- frame
.grab_y
;
3184 dx
-= frame
.border_w
;
3185 dy
-= frame
.border_w
;
3187 doWindowSnapping(dx
, dy
);
3189 if (screen
->doOpaqueMove()) {
3190 if (screen
->doWorkspaceWarping())
3191 doWorkspaceWarping(x_root
, y_root
, dx
);
3193 configure(dx
, dy
, frame
.rect
.width(), frame
.rect
.height());
3195 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3199 frame
.changing
.width() - 1,
3200 frame
.changing
.height() - 1);
3202 if (screen
->doWorkspaceWarping())
3203 doWorkspaceWarping(x_root
, y_root
, dx
);
3205 frame
.changing
.setPos(dx
, dy
);
3207 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3211 frame
.changing
.width() - 1,
3212 frame
.changing
.height() - 1);
3215 screen
->showPosition(dx
, dy
);
3219 void BlackboxWindow::doWorkspaceWarping(int x_root
, int y_root
, int &dx
) {
3220 // workspace warping
3222 unsigned int dest
= screen
->getCurrentWorkspaceID();
3226 if (dest
> 0) dest
--;
3227 else dest
= screen
->getNumberOfWorkspaces() - 1;
3229 } else if (x_root
>= screen
->getRect().right()) {
3232 if (dest
< screen
->getNumberOfWorkspaces() - 1) dest
++;
3238 bool focus
= flags
.focused
; // had focus while moving?
3240 int dest_x
= x_root
;
3242 dest_x
+= screen
->getRect().width() - 1;
3243 dx
+= screen
->getRect().width() - 1;
3245 dest_x
-= screen
->getRect().width() - 1;
3246 dx
-= screen
->getRect().width() - 1;
3250 screen
->reassociateWindow(this, dest
, False
);
3251 screen
->changeWorkspaceID(dest
);
3253 if (screen
->doOpaqueMove())
3254 XGrabServer(blackbox
->getXDisplay());
3256 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3257 XWarpPointer(blackbox
->getXDisplay(), None
,
3258 screen
->getRootWindow(), 0, 0, 0, 0,
3260 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3261 PointerMotionMask
| ButtonReleaseMask
,
3262 GrabModeAsync
, GrabModeAsync
,
3263 None
, blackbox
->getMoveCursor(), CurrentTime
);
3265 if (screen
->doOpaqueMove())
3266 XUngrabServer(blackbox
->getXDisplay());
3274 void BlackboxWindow::doWindowSnapping(int &dx
, int &dy
) {
3275 // how much resistance to edges to provide
3276 const int resistance_size
= screen
->getResistanceSize();
3278 // how far away to snap
3279 const int snap_distance
= screen
->getSnapThreshold();
3281 // how to snap windows
3282 const int snap_to_windows
= screen
->getWindowToWindowSnap();
3283 const int snap_to_edges
= screen
->getWindowToEdgeSnap();
3284 // the amount of space away from the edge to provide resistance/snap
3285 const int snap_offset
= screen
->getSnapOffset();
3287 // find the geomeetery where the moving window currently is
3288 const Rect
&moving
= screen
->doOpaqueMove() ? frame
.rect
: frame
.changing
;
3291 const int wleft
= dx
,
3292 wright
= dx
+ frame
.rect
.width() - 1,
3294 wbottom
= dy
+ frame
.rect
.height() - 1;
3296 if (snap_to_windows
) {
3299 Workspace
*w
= screen
->getWorkspace(getWorkspaceNumber());
3302 // add windows on the workspace to the rect list
3303 const BlackboxWindowList
& stack_list
= w
->getStackingList();
3304 BlackboxWindowList::const_iterator st_it
, st_end
= stack_list
.end();
3305 for (st_it
= stack_list
.begin(); st_it
!= st_end
; ++st_it
)
3306 if (*st_it
!= this) // don't snap to ourself
3307 rectlist
.push_back( (*st_it
)->frameRect() );
3309 RectList::const_iterator it
, end
= rectlist
.end();
3310 for (it
= rectlist
.begin(); it
!= end
; ++it
) {
3311 bool snapped
= False
;
3312 const Rect
&winrect
= *it
;
3314 offsetrect
.setCoords(winrect
.left() - snap_offset
,
3315 winrect
.top() - snap_offset
,
3316 winrect
.right() + snap_offset
,
3317 winrect
.bottom() + snap_offset
);
3319 if (snap_to_windows
== BScreen::WindowResistance
)
3320 // if the window is already over top of this snap target, then
3321 // resistance is futile, so just ignore it
3322 if (winrect
.intersects(moving
))
3325 int dleft
, dright
, dtop
, dbottom
;
3327 // if the windows are in the same plane vertically
3328 if (wtop
>= (signed)(winrect
.y() - frame
.rect
.height() + 1) &&
3329 wtop
< (signed)(winrect
.y() + winrect
.height() - 1)) {
3331 if (snap_to_windows
== BScreen::WindowResistance
) {
3332 dleft
= wright
- offsetrect
.left();
3333 dright
= offsetrect
.right() - wleft
;
3335 // snap left of other window?
3336 if (dleft
>= 0 && dleft
< resistance_size
&&
3337 dleft
< (wright
- wleft
)) {
3338 dx
= offsetrect
.left() - frame
.rect
.width();
3341 // snap right of other window?
3342 else if (dright
>= 0 && dright
< resistance_size
&&
3343 dright
< (wright
- wleft
)) {
3344 dx
= offsetrect
.right() + 1;
3347 } else { // BScreen::WindowSnap
3348 dleft
= abs(wright
- offsetrect
.left());
3349 dright
= abs(wleft
- offsetrect
.right());
3351 // snap left of other window?
3352 if (dleft
< snap_distance
&& dleft
<= dright
) {
3353 dx
= offsetrect
.left() - frame
.rect
.width();
3356 // snap right of other window?
3357 else if (dright
< snap_distance
) {
3358 dx
= offsetrect
.right() + 1;
3364 if (screen
->getWindowCornerSnap()) {
3365 // try corner-snap to its other sides
3366 if (snap_to_windows
== BScreen::WindowResistance
) {
3367 dtop
= winrect
.top() - wtop
;
3368 dbottom
= wbottom
- winrect
.bottom();
3369 if (dtop
> 0 && dtop
< resistance_size
) {
3370 // if we're already past the top edge, then don't provide
3372 if (moving
.top() >= winrect
.top())
3374 } else if (dbottom
> 0 && dbottom
< resistance_size
) {
3375 // if we're already past the bottom edge, then don't provide
3377 if (moving
.bottom() <= winrect
.bottom())
3378 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
3380 } else { // BScreen::WindowSnap
3381 dtop
= abs(wtop
- winrect
.top());
3382 dbottom
= abs(wbottom
- winrect
.bottom());
3383 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3385 else if (dbottom
< snap_distance
)
3386 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
3394 // if the windows are on the same plane horizontally
3395 if (wleft
>= (signed)(winrect
.x() - frame
.rect
.width() + 1) &&
3396 wleft
< (signed)(winrect
.x() + winrect
.width() - 1)) {
3398 if (snap_to_windows
== BScreen::WindowResistance
) {
3399 dtop
= wbottom
- offsetrect
.top();
3400 dbottom
= offsetrect
.bottom() - wtop
;
3402 // snap top of other window?
3403 if (dtop
>= 0 && dtop
< resistance_size
&& dtop
< (wbottom
- wtop
)) {
3404 dy
= offsetrect
.top() - frame
.rect
.height();
3407 // snap bottom of other window?
3408 else if (dbottom
>= 0 && dbottom
< resistance_size
&&
3409 dbottom
< (wbottom
- wtop
)) {
3410 dy
= offsetrect
.bottom() + 1;
3413 } else { // BScreen::WindowSnap
3414 dtop
= abs(wbottom
- offsetrect
.top());
3415 dbottom
= abs(wtop
- offsetrect
.bottom());
3417 // snap top of other window?
3418 if (dtop
< snap_distance
&& dtop
<= dbottom
) {
3419 dy
= offsetrect
.top() - frame
.rect
.height();
3422 // snap bottom of other window?
3423 else if (dbottom
< snap_distance
) {
3424 dy
= offsetrect
.bottom() + 1;
3431 if (screen
->getWindowCornerSnap()) {
3432 // try corner-snap to its other sides
3433 if (snap_to_windows
== BScreen::WindowResistance
) {
3434 dleft
= winrect
.left() - wleft
;
3435 dright
= wright
- winrect
.right();
3436 if (dleft
> 0 && dleft
< resistance_size
) {
3437 // if we're already past the left edge, then don't provide
3439 if (moving
.left() >= winrect
.left())
3440 dx
= winrect
.left();
3441 } else if (dright
> 0 && dright
< resistance_size
) {
3442 // if we're already past the right edge, then don't provide
3444 if (moving
.right() <= winrect
.right())
3445 dx
= winrect
.right() - frame
.rect
.width() + 1;
3447 } else { // BScreen::WindowSnap
3448 dleft
= abs(wleft
- winrect
.left());
3449 dright
= abs(wright
- winrect
.right());
3450 if (dleft
< snap_distance
&& dleft
<= dright
)
3451 dx
= winrect
.left();
3452 else if (dright
< snap_distance
)
3453 dx
= winrect
.right() - frame
.rect
.width() + 1;
3463 if (snap_to_edges
) {
3466 // snap to the screen edges (and screen boundaries for xinerama)
3468 if (screen
->isXineramaActive() && blackbox
->doXineramaSnapping()) {
3469 rectlist
.insert(rectlist
.begin(),
3470 screen
->getXineramaAreas().begin(),
3471 screen
->getXineramaAreas().end());
3474 rectlist
.push_back(screen
->getRect());
3476 RectList::const_iterator it
, end
= rectlist
.end();
3477 for (it
= rectlist
.begin(); it
!= end
; ++it
) {
3478 const Rect
&srect
= *it
;
3480 offsetrect
.setCoords(srect
.left() + snap_offset
,
3481 srect
.top() + snap_offset
,
3482 srect
.right() - snap_offset
,
3483 srect
.bottom() - snap_offset
);
3485 if (snap_to_edges
== BScreen::WindowResistance
) {
3486 // if we're not in the rectangle then don't snap to it.
3487 if (! srect
.contains(moving
))
3489 } else { // BScreen::WindowSnap
3490 // if we're not in the rectangle then don't snap to it.
3491 if (! srect
.intersects(Rect(wleft
, wtop
, frame
.rect
.width(),
3492 frame
.rect
.height())))
3496 if (snap_to_edges
== BScreen::WindowResistance
) {
3497 int dleft
= offsetrect
.left() - wleft
,
3498 dright
= wright
- offsetrect
.right(),
3499 dtop
= offsetrect
.top() - wtop
,
3500 dbottom
= wbottom
- offsetrect
.bottom();
3503 if (dleft
> 0 && dleft
< resistance_size
)
3504 dx
= offsetrect
.left();
3506 else if (dright
> 0 && dright
< resistance_size
)
3507 dx
= offsetrect
.right() - frame
.rect
.width() + 1;
3510 if (dtop
> 0 && dtop
< resistance_size
)
3511 dy
= offsetrect
.top();
3513 else if (dbottom
> 0 && dbottom
< resistance_size
)
3514 dy
= offsetrect
.bottom() - frame
.rect
.height() + 1;
3515 } else { // BScreen::WindowSnap
3516 int dleft
= abs(wleft
- offsetrect
.left()),
3517 dright
= abs(wright
- offsetrect
.right()),
3518 dtop
= abs(wtop
- offsetrect
.top()),
3519 dbottom
= abs(wbottom
- offsetrect
.bottom());
3522 if (dleft
< snap_distance
&& dleft
<= dright
)
3523 dx
= offsetrect
.left();
3525 else if (dright
< snap_distance
)
3526 dx
= offsetrect
.right() - frame
.rect
.width() + 1;
3529 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3530 dy
= offsetrect
.top();
3532 else if (dbottom
< snap_distance
)
3533 dy
= offsetrect
.bottom() - frame
.rect
.height() + 1;
3540 void BlackboxWindow::endMove(void) {
3541 assert(flags
.moving
);
3542 assert(blackbox
->getChangingWindow() == this);
3544 flags
.moving
= False
;
3545 blackbox
->setChangingWindow(0);
3547 if (! screen
->doOpaqueMove()) {
3548 /* when drawing the rubber band, we need to make sure we only draw inside
3549 * the frame... frame.changing_* contain the new coords for the window,
3550 * so we need to subtract 1 from changing_w/changing_h every where we
3551 * draw the rubber band (for both moving and resizing)
3553 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3554 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3555 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3556 XUngrabServer(blackbox
->getXDisplay());
3558 configure(frame
.changing
.x(), frame
.changing
.y(),
3559 frame
.changing
.width(), frame
.changing
.height());
3561 configure(frame
.rect
.x(), frame
.rect
.y(),
3562 frame
.rect
.width(), frame
.rect
.height());
3564 screen
->hideGeometry();
3566 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3568 // if there are any left over motions from the move, drop them now
3569 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3571 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3576 void BlackboxWindow::beginResize(int x_root
, int y_root
, Corner dir
) {
3577 if (! (functions
& Func_Resize
)) return;
3579 assert(! (flags
.resizing
|| flags
.moving
));
3582 Only one window can be moved/resized at a time. If another window is
3583 already being moved or resized, then stop it before whating to work with
3586 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3587 if (changing
&& changing
!= this) {
3588 if (changing
->flags
.moving
)
3589 changing
->endMove();
3590 else // if (changing->flags.resizing)
3591 changing
->endResize();
3599 switch (resize_dir
) {
3602 cursor
= blackbox
->getLowerLeftAngleCursor();
3607 cursor
= blackbox
->getLowerRightAngleCursor();
3611 anchor
= BottomRight
;
3612 cursor
= blackbox
->getUpperLeftAngleCursor();
3616 anchor
= BottomLeft
;
3617 cursor
= blackbox
->getUpperRightAngleCursor();
3621 assert(false); // unhandled Corner
3622 return; // unreachable, for the compiler
3625 XGrabServer(blackbox
->getXDisplay());
3626 XGrabPointer(blackbox
->getXDisplay(), frame
.window
, False
,
3627 PointerMotionMask
| ButtonReleaseMask
,
3628 GrabModeAsync
, GrabModeAsync
, None
, cursor
, CurrentTime
);
3630 flags
.resizing
= True
;
3631 blackbox
->setChangingWindow(this);
3633 unsigned int gw
, gh
;
3634 frame
.changing
= frame
.rect
;
3636 constrain(anchor
, &gw
, &gh
);
3638 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3639 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3640 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3642 screen
->showGeometry(gw
, gh
);
3644 frame
.grab_x
= x_root
;
3645 frame
.grab_y
= y_root
;
3649 void BlackboxWindow::doResize(int x_root
, int y_root
) {
3650 assert(flags
.resizing
);
3651 assert(blackbox
->getChangingWindow() == this);
3653 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3654 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3655 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3657 unsigned int gw
, gh
;
3659 int dx
, dy
; // the amount of change in the size of the window
3661 switch (resize_dir
) {
3664 dx
= - (x_root
- frame
.grab_x
);
3665 dy
= + (y_root
- frame
.grab_y
);
3669 dx
= + (x_root
- frame
.grab_x
);
3670 dy
= + (y_root
- frame
.grab_y
);
3673 anchor
= BottomRight
;
3674 dx
= - (x_root
- frame
.grab_x
);
3675 dy
= - (y_root
- frame
.grab_y
);
3678 anchor
= BottomLeft
;
3679 dx
= + (x_root
- frame
.grab_x
);
3680 dy
= - (y_root
- frame
.grab_y
);
3684 assert(false); // unhandled Corner
3685 return; // unreachable, for the compiler
3688 // make sure the user cant resize the window smaller than 0, which makes it
3689 // wrap around and become huge
3690 if (dx
< -(signed)client
.rect
.width()) dx
= -(signed)client
.rect
.width();
3691 if (dy
< -(signed)client
.rect
.height()) dy
= -(signed)client
.rect
.height();
3693 frame
.changing
.setSize(frame
.rect
.width() + dx
, frame
.rect
.height() + dy
);
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
);
3705 void BlackboxWindow::endResize(void) {
3706 assert(flags
.resizing
);
3707 assert(blackbox
->getChangingWindow() == this);
3709 XDrawRectangle(blackbox
->getXDisplay(), screen
->getRootWindow(),
3710 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3711 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3712 XUngrabServer(blackbox
->getXDisplay());
3714 // unset maximized state after resized when fully maximized
3715 if (flags
.maximized
== 1)
3718 flags
.resizing
= False
;
3719 blackbox
->setChangingWindow(0);
3721 configure(frame
.changing
.x(), frame
.changing
.y(),
3722 frame
.changing
.width(), frame
.changing
.height());
3723 screen
->hideGeometry();
3725 XUngrabPointer(blackbox
->getXDisplay(), CurrentTime
);
3727 // if there are any left over motions from the resize, drop them now
3728 XSync(blackbox
->getXDisplay(), false); // make sure we don't miss any
3730 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), frame
.window
,
3735 void BlackboxWindow::motionNotifyEvent(const XMotionEvent
*me
) {
3737 fprintf(stderr
, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n",
3742 doMove(me
->x_root
, me
->y_root
);
3743 } else if (flags
.resizing
) {
3744 doResize(me
->x_root
, me
->y_root
);
3746 if ((functions
& Func_Move
) &&
3747 (me
->state
& Button1Mask
) &&
3748 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3749 frame
.handle
== me
->window
|| frame
.window
== me
->window
)) {
3750 beginMove(me
->x_root
, me
->y_root
);
3751 } else if ((functions
& Func_Resize
) &&
3752 ((me
->state
& Button1Mask
) &&
3753 (me
->window
== frame
.right_grip
||
3754 me
->window
== frame
.left_grip
)) ||
3755 ((me
->state
& Button3Mask
) && (me
->state
& mod_mask
) &&
3756 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3757 frame
.handle
== me
->window
|| frame
.window
== me
->window
||
3758 frame
.right_grip
== me
->window
||
3759 frame
.left_grip
== me
->window
))) {
3760 unsigned int zones
= screen
->getResizeZones();
3763 if (me
->window
== frame
.left_grip
) {
3764 corner
= BottomLeft
;
3765 } else if (me
->window
== frame
.right_grip
|| zones
== 1) {
3766 corner
= BottomRight
;
3769 bool left
= (me
->x_root
- frame
.rect
.x() <=
3770 static_cast<signed>(frame
.rect
.width() / 2));
3773 else // (zones == 4)
3774 top
= (me
->y_root
- frame
.rect
.y() <=
3775 static_cast<signed>(frame
.rect
.height() / 2));
3776 corner
= (top
? (left
? TopLeft
: TopRight
) :
3777 (left
? BottomLeft
: BottomRight
));
3780 beginResize(me
->x_root
, me
->y_root
, corner
);
3786 void BlackboxWindow::enterNotifyEvent(const XCrossingEvent
* ce
) {
3787 if (! (screen
->isSloppyFocus() && isVisible() && isNormal()))
3791 bool leave
= False
, inferior
= False
;
3793 while (XCheckTypedWindowEvent(blackbox
->getXDisplay(), ce
->window
,
3795 if (e
.type
== LeaveNotify
&& e
.xcrossing
.mode
== NotifyNormal
) {
3797 inferior
= (e
.xcrossing
.detail
== NotifyInferior
);
3801 if (! leave
|| inferior
) {
3802 if (! isFocused()) {
3803 bool success
= setInputFocus();
3804 if (success
) // if focus succeeded install the colormap
3805 installColormap(True
); // XXX: shouldnt we honour no install?
3808 We only auto-raise when the window wasn't focused because otherwise
3809 we run into problems with gtk+ drop-down lists. The window ends up
3810 raising over the list.
3812 if (screen
->doAutoRaise())
3819 void BlackboxWindow::leaveNotifyEvent(const XCrossingEvent
*) {
3820 if (! (screen
->isSloppyFocus() && screen
->doAutoRaise() && isNormal()))
3823 installColormap(False
);
3825 if (timer
->isTiming())
3831 void BlackboxWindow::shapeEvent(XShapeEvent
*e
) {
3832 if (blackbox
->hasShapeExtensions()) {
3833 if (! e
->shaped
&& flags
.shaped
) {
3835 flags
.shaped
= False
;
3836 } else if (e
->shaped
) {
3838 flags
.shaped
= True
;
3845 bool BlackboxWindow::validateClient(void) const {
3846 XSync(blackbox
->getXDisplay(), False
);
3849 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3850 DestroyNotify
, &e
) ||
3851 XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3853 XPutBackEvent(blackbox
->getXDisplay(), &e
);
3862 void BlackboxWindow::restore(bool remap
) {
3863 XChangeSaveSet(blackbox
->getXDisplay(), client
.window
, SetModeDelete
);
3864 XSelectInput(blackbox
->getXDisplay(), client
.window
, NoEventMask
);
3865 XSelectInput(blackbox
->getXDisplay(), frame
.plate
, NoEventMask
);
3867 // do not leave a shaded window as an icon unless it was an icon
3868 if (flags
.shaded
&& ! flags
.iconic
)
3869 setState(NormalState
);
3871 // erase the netwm stuff that we read when a window maps, so that it
3872 // doesn't persist between mappings.
3873 // (these are the ones read in getNetWMFlags().)
3874 xatom
->eraseValue(client
.window
, XAtom::net_wm_desktop
);
3875 xatom
->eraseValue(client
.window
, XAtom::net_wm_state
);
3877 restoreGravity(client
.rect
);
3879 XUnmapWindow(blackbox
->getXDisplay(), frame
.window
);
3880 XUnmapWindow(blackbox
->getXDisplay(), client
.window
);
3882 XSetWindowBorderWidth(blackbox
->getXDisplay(), client
.window
, client
.old_bw
);
3885 if (XCheckTypedWindowEvent(blackbox
->getXDisplay(), client
.window
,
3886 ReparentNotify
, &ev
)) {
3889 // according to the ICCCM - if the client doesn't reparent to
3890 // root, then we have to do it for them
3891 XReparentWindow(blackbox
->getXDisplay(), client
.window
,
3892 screen
->getRootWindow(),
3893 client
.rect
.x(), client
.rect
.y());
3896 if (remap
) XMapWindow(blackbox
->getXDisplay(), client
.window
);
3900 // timer for autoraise
3901 void BlackboxWindow::timeout(void) {
3902 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3906 void BlackboxWindow::changeBlackboxHints(const BlackboxHints
*net
) {
3907 if ((net
->flags
& AttribShaded
) &&
3908 ((blackbox_attrib
.attrib
& AttribShaded
) !=
3909 (net
->attrib
& AttribShaded
)))
3912 if (flags
.visible
&& // watch out for requests when we can not be seen
3913 (net
->flags
& (AttribMaxVert
| AttribMaxHoriz
)) &&
3914 ((blackbox_attrib
.attrib
& (AttribMaxVert
| AttribMaxHoriz
)) !=
3915 (net
->attrib
& (AttribMaxVert
| AttribMaxHoriz
)))) {
3916 if (flags
.maximized
) {
3921 if ((net
->flags
& AttribMaxHoriz
) && (net
->flags
& AttribMaxVert
))
3922 button
= ((net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0);
3923 else if (net
->flags
& AttribMaxVert
)
3924 button
= ((net
->attrib
& AttribMaxVert
) ? 2 : 0);
3925 else if (net
->flags
& AttribMaxHoriz
)
3926 button
= ((net
->attrib
& AttribMaxHoriz
) ? 3 : 0);
3932 if ((net
->flags
& AttribOmnipresent
) &&
3933 ((blackbox_attrib
.attrib
& AttribOmnipresent
) !=
3934 (net
->attrib
& AttribOmnipresent
)))
3937 if ((net
->flags
& AttribWorkspace
) &&
3938 (blackbox_attrib
.workspace
!= net
->workspace
)) {
3939 screen
->reassociateWindow(this, net
->workspace
, True
);
3941 if (screen
->getCurrentWorkspaceID() != net
->workspace
) {
3945 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3949 if (net
->flags
& AttribDecoration
) {
3950 switch (net
->decoration
) {
3967 * Set the sizes of all components of the window frame
3968 * (the window decorations).
3969 * These values are based upon the current style settings and the client
3970 * window's dimensions.
3972 void BlackboxWindow::upsize(void) {
3973 frame
.bevel_w
= screen
->getBevelWidth();
3975 if (decorations
& Decor_Border
) {
3976 frame
.border_w
= screen
->getBorderWidth();
3977 if (! isTransient())
3978 frame
.mwm_border_w
= screen
->getFrameWidth();
3980 frame
.mwm_border_w
= 0;
3982 frame
.mwm_border_w
= frame
.border_w
= 0;
3985 if (decorations
& Decor_Titlebar
) {
3986 // the height of the titlebar is based upon the height of the font being
3987 // used to display the window's title
3988 WindowStyle
*style
= screen
->getWindowStyle();
3989 frame
.title_h
= style
->font
->height() + (frame
.bevel_w
* 2) + 2;
3991 frame
.label_h
= frame
.title_h
- (frame
.bevel_w
* 2);
3992 frame
.button_w
= (frame
.label_h
- 2);
3994 // set the top frame margin
3995 frame
.margin
.top
= frame
.border_w
+ frame
.title_h
+
3996 frame
.border_w
+ frame
.mwm_border_w
;
4002 // set the top frame margin
4003 frame
.margin
.top
= frame
.border_w
+ frame
.mwm_border_w
;
4006 // set the left/right frame margin
4007 frame
.margin
.left
= frame
.margin
.right
= frame
.border_w
+ frame
.mwm_border_w
;
4009 if (decorations
& Decor_Handle
) {
4010 frame
.grip_w
= frame
.button_w
* 2;
4011 frame
.handle_h
= screen
->getHandleWidth();
4013 // set the bottom frame margin
4014 frame
.margin
.bottom
= frame
.border_w
+ frame
.handle_h
+
4015 frame
.border_w
+ frame
.mwm_border_w
;
4020 // set the bottom frame margin
4021 frame
.margin
.bottom
= frame
.border_w
+ frame
.mwm_border_w
;
4025 We first get the normal dimensions and use this to define the inside_w/h
4026 then we modify the height if shading is in effect.
4027 If the shade state is not considered then frame.rect gets reset to the
4028 normal window size on a reconfigure() call resulting in improper
4029 dimensions appearing in move/resize and other events.
4032 height
= client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
,
4033 width
= client
.rect
.width() + frame
.margin
.left
+ frame
.margin
.right
;
4035 frame
.inside_w
= width
- (frame
.border_w
* 2);
4036 frame
.inside_h
= height
- (frame
.border_w
* 2);
4039 height
= frame
.title_h
+ (frame
.border_w
* 2);
4040 frame
.rect
.setSize(width
, height
);
4045 * Calculate the size of the client window and constrain it to the
4046 * size specified by the size hints of the client window.
4048 * The logical width and height are placed into pw and ph, if they
4049 * are non-zero. Logical size refers to the users perception of
4050 * the window size (for example an xterm resizes in cells, not in pixels).
4051 * pw and ph are then used to display the geometry during window moves, resize,
4054 * The physical geometry is placed into frame.changing_{x,y,width,height}.
4055 * Physical geometry refers to the geometry of the window in pixels.
4057 void BlackboxWindow::constrain(Corner anchor
,
4058 unsigned int *pw
, unsigned int *ph
) {
4059 // frame.changing represents the requested frame size, we need to
4060 // strip the frame margin off and constrain the client size
4061 frame
.changing
.setCoords(frame
.changing
.left() + frame
.margin
.left
,
4062 frame
.changing
.top() + frame
.margin
.top
,
4063 frame
.changing
.right() - frame
.margin
.right
,
4064 frame
.changing
.bottom() - frame
.margin
.bottom
);
4066 unsigned int dw
= frame
.changing
.width(), dh
= frame
.changing
.height(),
4067 base_width
= (client
.base_width
) ? client
.base_width
: client
.min_width
,
4068 base_height
= (client
.base_height
) ? client
.base_height
:
4071 // constrain, but only if the min/max are being used. if they aren't, then
4072 // this resize is going to be from a ConfigureRequest because the window
4073 // isn't allowed to be resized by the user. And in that case, we don't want
4074 // to limit what the app can do
4075 if (client
.max_width
> client
.min_width
||
4076 client
.max_height
> client
.min_height
) {
4077 if (dw
< client
.min_width
) dw
= client
.min_width
;
4078 if (dh
< client
.min_height
) dh
= client
.min_height
;
4079 if (dw
> client
.max_width
) dw
= client
.max_width
;
4080 if (dh
> client
.max_height
) dh
= client
.max_height
;
4083 if (client
.width_inc
> 1) {
4085 dw
/= client
.width_inc
;
4087 if (client
.height_inc
> 1) {
4089 dh
/= client
.height_inc
;
4098 if (client
.width_inc
> 1) {
4099 dw
*= client
.width_inc
;
4102 if (client
.height_inc
> 1) {
4103 dh
*= client
.height_inc
;
4107 frame
.changing
.setSize(dw
, dh
);
4109 // add the frame margin back onto frame.changing
4110 frame
.changing
.setCoords(frame
.changing
.left() - frame
.margin
.left
,
4111 frame
.changing
.top() - frame
.margin
.top
,
4112 frame
.changing
.right() + frame
.margin
.right
,
4113 frame
.changing
.bottom() + frame
.margin
.bottom
);
4115 // move frame.changing to the specified anchor
4123 dx
= frame
.rect
.right() - frame
.changing
.right();
4127 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
4131 dx
= frame
.rect
.right() - frame
.changing
.right();
4132 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
4136 assert(false); // unhandled corner
4138 frame
.changing
.setPos(frame
.changing
.x() + dx
, frame
.changing
.y() + dy
);
4142 void WindowStyle::doJustify(const std::string
&text
, int &start_pos
,
4143 unsigned int max_length
,
4144 unsigned int modifier
) const {
4145 size_t text_len
= text
.size();
4146 unsigned int length
;
4149 length
= font
->measureString(string(text
, 0, text_len
)) + modifier
;
4150 } while (length
> max_length
&& text_len
-- > 0);
4154 start_pos
+= max_length
- length
;
4158 start_pos
+= (max_length
- length
) / 2;
4168 BWindowGroup::BWindowGroup(Blackbox
*b
, Window _group
)
4169 : blackbox(b
), group(_group
) {
4170 XWindowAttributes wattrib
;
4171 if (! XGetWindowAttributes(blackbox
->getXDisplay(), group
, &wattrib
)) {
4172 // group window doesn't seem to exist anymore
4177 XSelectInput(blackbox
->getXDisplay(), group
,
4178 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
4180 blackbox
->saveGroupSearch(group
, this);
4184 BWindowGroup::~BWindowGroup(void) {
4185 blackbox
->removeGroupSearch(group
);
4190 BWindowGroup::find(BScreen
*screen
, bool allow_transients
) const {
4191 BlackboxWindow
*ret
= blackbox
->getFocusedWindow();
4193 // does the focus window match (or any transient_fors)?
4194 for (; ret
; ret
= ret
->getTransientFor()) {
4195 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
&&
4196 (! ret
->isTransient() || allow_transients
))
4200 if (ret
) return ret
;
4202 // the focus window didn't match, look in the group's window list
4203 BlackboxWindowList::const_iterator it
, end
= windowList
.end();
4204 for (it
= windowList
.begin(); it
!= end
; ++it
) {
4206 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
&&
4207 (! ret
->isTransient() || allow_transients
))