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"
41 * Initializes the class with default values/the window's set initial values.
43 BlackboxWindow::BlackboxWindow(Blackbox
*b
, Window w
, BScreen
*s
) {
44 // fprintf(stderr, "BlackboxWindow size: %d bytes\n",
45 // sizeof(BlackboxWindow));
48 fprintf(stderr
, "BlackboxWindow::BlackboxWindow(): creating 0x%lx\n", w
);
52 set timer to zero... it is initialized properly later, so we check
53 if timer is zero in the destructor, and assume that the window is not
54 fully constructed if timer is zero...
60 xatom
= blackbox
->getXAtom();
62 if (! validateClient()) {
67 // fetch client size and placement
68 XWindowAttributes wattrib
;
69 if (! XGetWindowAttributes(otk::OBDisplay::display
,
70 client
.window
, &wattrib
) ||
71 ! wattrib
.screen
|| wattrib
.override_redirect
) {
74 "BlackboxWindow::BlackboxWindow(): XGetWindowAttributes failed\n");
81 // set the eventmask early in the game so that we make sure we get
82 // all the events we are interested in
83 XSetWindowAttributes attrib_set
;
84 attrib_set
.event_mask
= PropertyChangeMask
| FocusChangeMask
|
86 attrib_set
.do_not_propagate_mask
= ButtonPressMask
| ButtonReleaseMask
|
88 XChangeWindowAttributes(otk::OBDisplay::display
, client
.window
,
89 CWEventMask
|CWDontPropagate
, &attrib_set
);
91 flags
.moving
= flags
.resizing
= flags
.shaded
= flags
.visible
=
92 flags
.iconic
= flags
.focused
= flags
.stuck
= flags
.modal
=
93 flags
.send_focus_message
= flags
.shaped
= flags
.skip_taskbar
=
94 flags
.skip_pager
= flags
.fullscreen
= False
;
97 blackbox_attrib
.workspace
= window_number
= BSENTINEL
;
99 blackbox_attrib
.flags
= blackbox_attrib
.attrib
= blackbox_attrib
.stack
= 0l;
100 blackbox_attrib
.decoration
= DecorNormal
;
101 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
102 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
105 frame
.window
= frame
.plate
= frame
.title
= frame
.handle
= None
;
106 frame
.close_button
= frame
.iconify_button
= frame
.maximize_button
=
107 frame
.stick_button
= None
;
108 frame
.right_grip
= frame
.left_grip
= None
;
110 frame
.ulabel_pixel
= frame
.flabel_pixel
= frame
.utitle_pixel
=
111 frame
.ftitle_pixel
= frame
.uhandle_pixel
= frame
.fhandle_pixel
=
112 frame
.ubutton_pixel
= frame
.fbutton_pixel
= frame
.uborder_pixel
=
113 frame
.fborder_pixel
= frame
.ugrip_pixel
= frame
.fgrip_pixel
= 0;
114 frame
.utitle
= frame
.ftitle
= frame
.uhandle
= frame
.fhandle
= None
;
115 frame
.ulabel
= frame
.flabel
= frame
.ubutton
= frame
.fbutton
= None
;
116 frame
.ugrip
= frame
.fgrip
= None
;
118 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
119 mwm_decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
120 Decor_Iconify
| Decor_Maximize
;
122 client
.normal_hint_flags
= 0;
123 client
.window_group
= None
;
124 client
.transient_for
= 0;
126 current_state
= NormalState
;
129 set the initial size and location of client window (relative to the
130 _root window_). This position is the reference point used with the
131 window's gravity to find the window's initial position.
133 client
.rect
.setRect(wattrib
.x
, wattrib
.y
, wattrib
.width
, wattrib
.height
);
134 client
.old_bw
= wattrib
.border_width
;
136 lastButtonPressTime
= 0;
138 timer
= new BTimer(blackbox
, this);
139 timer
->setTimeout(blackbox
->getAutoRaiseDelay());
141 // get size, aspect, minimum/maximum size and other hints set by the
144 if (! getBlackboxHints())
151 frame
.window
= createToplevelWindow();
153 blackbox
->saveWindowSearch(frame
.window
, this);
155 frame
.plate
= createChildWindow(frame
.window
, ExposureMask
);
156 blackbox
->saveWindowSearch(frame
.plate
, this);
158 // determine if this is a transient window
161 // determine the window's type, so we can decide its decorations and
162 // functionality, or if we should not manage it at all
163 if (getWindowType()) {
164 // adjust the window decorations/behavior based on the window type
165 switch (window_type
) {
169 blackbox_attrib
.workspace
= 0; // we do need to belong to a workspace
170 flags
.stuck
= True
; // we show up on all workspaces
172 // none of these windows are manipulated by the window manager
178 // these windows get less functionality
179 functions
&= ~(Func_Maximize
| Func_Resize
| Func_Iconify
);
183 // dialogs cannot be maximized
184 functions
&= ~Func_Maximize
;
188 // normal windows retain all of the possible decorations and
196 // further adjeust the window's decorations/behavior based on window sizes
197 if ((client
.normal_hint_flags
& PMinSize
) &&
198 (client
.normal_hint_flags
& PMaxSize
) &&
199 client
.max_width
<= client
.min_width
&&
200 client
.max_height
<= client
.min_height
) {
201 functions
&= ~(Func_Resize
| Func_Maximize
);
208 if (decorations
& Decor_Titlebar
)
211 if (decorations
& Decor_Handle
)
214 // apply the size and gravity hint to the frame
218 bool place_window
= True
;
219 if (blackbox
->state() == Openbox::State_Starting
|| isTransient() ||
220 client
.normal_hint_flags
& (PPosition
|USPosition
)) {
221 applyGravity(frame
.rect
);
223 if (blackbox
->state() == Openbox::State_Starting
||
224 client
.rect
.intersects(screen
->getRect()))
225 place_window
= False
;
228 // add the window's strut. note this is done *after* placing the window.
229 screen
->addStrut(&client
.strut
);
233 the server needs to be grabbed here to prevent client's from sending
234 events while we are in the process of configuring their window.
235 We hold the grab until after we are done moving the window around.
238 XGrabServer(otk::OBDisplay::display
);
240 associateClientWindow();
242 blackbox
->saveWindowSearch(client
.window
, this);
244 if (blackbox_attrib
.workspace
>= screen
->getWorkspaceCount())
245 screen
->getCurrentWorkspace()->addWindow(this, place_window
);
247 screen
->getWorkspace(blackbox_attrib
.workspace
)->
248 addWindow(this, place_window
);
250 if (! place_window
) {
251 // don't need to call configure if we are letting the workspace
253 configure(frame
.rect
.x(), frame
.rect
.y(),
254 frame
.rect
.width(), frame
.rect
.height());
260 XUngrabServer(otk::OBDisplay::display
);
263 if (blackbox
->hasShapeExtensions() && flags
.shaped
)
267 // now that we know where to put the window and what it should look like
268 // we apply the decorations
273 XMapSubwindows(otk::OBDisplay::display
, frame
.window
);
275 // this ensures the title, buttons, and other decor are properly displayed
278 // preserve the window's initial state on first map, and its current state
280 unsigned long initial_state
= current_state
;
282 current_state
= initial_state
;
284 // get sticky state from our parent window if we've got one
285 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
286 client
.transient_for
->isStuck() != flags
.stuck
)
290 flags
.shaded
= False
;
291 initial_state
= current_state
;
295 At this point in the life of a window, current_state should only be set
296 to IconicState if the window was an *icon*, not if it was shaded.
298 if (initial_state
!= IconicState
)
299 current_state
= NormalState
;
307 if (flags
.maximized
&& (functions
& Func_Maximize
))
312 BlackboxWindow::~BlackboxWindow(void) {
314 fprintf(stderr
, "BlackboxWindow::~BlackboxWindow: destroying 0x%lx\n",
318 if (! timer
) // window not managed...
324 screen
->removeStrut(&client
.strut
);
325 screen
->updateAvailableArea();
327 // We don't need to worry about resizing because resizing always grabs the X
328 // server. This should only ever happen if using opaque moving.
334 if (client
.window_group
) {
335 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
336 if (group
) group
->removeWindow(this);
339 // remove ourselves from our transient_for
341 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul)
342 client
.transient_for
->client
.transientList
.remove(this);
343 client
.transient_for
= (BlackboxWindow
*) 0;
346 if (client
.transientList
.size() > 0) {
347 // reset transient_for for all transients
348 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
349 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
350 (*it
)->client
.transient_for
= (BlackboxWindow
*) 0;
360 blackbox
->removeWindowSearch(frame
.plate
);
361 XDestroyWindow(otk::OBDisplay::display
, frame
.plate
);
365 blackbox
->removeWindowSearch(frame
.window
);
366 XDestroyWindow(otk::OBDisplay::display
, frame
.window
);
369 blackbox
->removeWindowSearch(client
.window
);
373 void BlackboxWindow::enableDecor(bool enable
) {
374 blackbox_attrib
.flags
|= AttribDecoration
;
375 blackbox_attrib
.decoration
= enable
? DecorNormal
: DecorNone
;
378 // we can not be shaded if we lack a titlebar
379 if (! (decorations
& Decor_Titlebar
) && flags
.shaded
)
382 if (flags
.visible
&& frame
.window
) {
383 XMapSubwindows(otk::OBDisplay::display
, frame
.window
);
384 XMapWindow(otk::OBDisplay::display
, frame
.window
);
388 setState(current_state
);
392 void BlackboxWindow::setupDecor() {
393 if (blackbox_attrib
.decoration
!= DecorNone
) {
394 // start with everything on
395 decorations
= Decor_Close
|
396 (mwm_decorations
& Decor_Titlebar
? Decor_Titlebar
: 0) |
397 (mwm_decorations
& Decor_Border
? Decor_Border
: 0) |
398 (mwm_decorations
& Decor_Handle
? Decor_Handle
: 0) |
399 (mwm_decorations
& Decor_Iconify
? Decor_Iconify
: 0) |
400 (mwm_decorations
& Decor_Maximize
? Decor_Maximize
: 0);
402 if (! (functions
& Func_Close
)) decorations
&= ~Decor_Close
;
403 if (! (functions
& Func_Maximize
)) decorations
&= ~Decor_Maximize
;
404 if (! (functions
& Func_Iconify
)) decorations
&= ~Decor_Iconify
;
405 if (! (functions
& Func_Resize
)) decorations
&= ~Decor_Handle
;
407 switch (window_type
) {
412 // none of these windows are decorated by the window manager at all
418 decorations
&= ~(Decor_Border
);
422 decorations
&= ~Decor_Handle
;
434 * Creates a new top level window, with a given location, size, and border
436 * Returns: the newly created window
438 Window
BlackboxWindow::createToplevelWindow(void) {
439 XSetWindowAttributes attrib_create
;
440 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
| CWColormap
|
441 CWOverrideRedirect
| CWEventMask
;
443 attrib_create
.background_pixmap
= None
;
444 attrib_create
.colormap
= screen
->getColormap();
445 attrib_create
.override_redirect
= True
;
446 attrib_create
.event_mask
= EnterWindowMask
| LeaveWindowMask
|
449 We catch button presses because other wise they get passed down to the
450 root window, which will then cause root menus to show when you click the
454 return XCreateWindow(otk::OBDisplay::display
, screen
->getRootWindow(),
455 0, 0, 1, 1, frame
.border_w
, screen
->getDepth(),
456 InputOutput
, screen
->getVisual(), create_mask
,
462 * Creates a child window, and optionally associates a given cursor with
465 Window
BlackboxWindow::createChildWindow(Window parent
,
466 unsigned long event_mask
,
468 XSetWindowAttributes attrib_create
;
469 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
|
472 attrib_create
.background_pixmap
= None
;
473 attrib_create
.event_mask
= event_mask
;
476 create_mask
|= CWCursor
;
477 attrib_create
.cursor
= cursor
;
480 return XCreateWindow(otk::OBDisplay::display
, parent
, 0, 0, 1, 1, 0,
481 screen
->getDepth(), InputOutput
, screen
->getVisual(),
482 create_mask
, &attrib_create
);
486 void BlackboxWindow::associateClientWindow(void) {
487 XSetWindowBorderWidth(otk::OBDisplay::display
, client
.window
, 0);
491 XChangeSaveSet(otk::OBDisplay::display
, client
.window
, SetModeInsert
);
493 XSelectInput(otk::OBDisplay::display
, frame
.plate
, SubstructureRedirectMask
);
496 note we used to grab around this call to XReparentWindow however the
497 server is now grabbed before this method is called
499 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
501 XSelectInput(otk::OBDisplay::display
, client
.window
,
502 event_mask
& ~StructureNotifyMask
);
503 XReparentWindow(otk::OBDisplay::display
, client
.window
, frame
.plate
, 0, 0);
504 XSelectInput(otk::OBDisplay::display
, client
.window
, event_mask
);
506 XRaiseWindow(otk::OBDisplay::display
, frame
.plate
);
507 XMapSubwindows(otk::OBDisplay::display
, frame
.plate
);
510 if (blackbox
->hasShapeExtensions()) {
511 XShapeSelectInput(otk::OBDisplay::display
, client
.window
,
518 XShapeQueryExtents(otk::OBDisplay::display
, client
.window
, &shaped
,
519 &foo
, &foo
, &ufoo
, &ufoo
, &foo
, &foo
, &foo
,
521 flags
.shaped
= shaped
;
527 void BlackboxWindow::decorate(void) {
528 otk::BTexture
* texture
;
530 texture
= &(screen
->getWindowStyle()->b_focus
);
531 frame
.fbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
534 frame
.fbutton_pixel
= texture
->color().pixel();
536 texture
= &(screen
->getWindowStyle()->b_unfocus
);
537 frame
.ubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
540 frame
.ubutton_pixel
= texture
->color().pixel();
542 unsigned char needsPressed
= 0;
544 texture
= &(screen
->getWindowStyle()->b_pressed_focus
);
546 if (texture
->texture() != otk::BTexture::NoTexture
) {
547 frame
.pfbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
549 if (! frame
.pfbutton
)
550 frame
.pfbutton_pixel
= texture
->color().pixel();
555 texture
= &(screen
->getWindowStyle()->b_pressed_unfocus
);
557 if (texture
->texture() != otk::BTexture::NoTexture
) {
558 frame
.pubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
560 if (! frame
.pubutton
)
561 frame
.pubutton
= texture
->color().pixel();
566 // if we either pressed unfocused, or pressed focused were undefined,
567 // make them inherit from the old resource. It's a hack for sure, but
568 // it allows for some backwards and forwards compatibility.
570 texture
= &(screen
->getWindowStyle()->b_pressed
);
572 if (needsPressed
& 0x1) {
573 frame
.pfbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
575 if (! frame
.pfbutton
)
576 frame
.pfbutton_pixel
= texture
->color().pixel();
578 if (needsPressed
& 0x2) {
579 frame
.pubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
581 if (! frame
.pubutton
)
582 frame
.pubutton
= texture
->color().pixel();
587 if (decorations
& Decor_Titlebar
) {
588 texture
= &(screen
->getWindowStyle()->t_focus
);
589 frame
.ftitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
592 frame
.ftitle_pixel
= texture
->color().pixel();
594 texture
= &(screen
->getWindowStyle()->t_unfocus
);
595 frame
.utitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
598 frame
.utitle_pixel
= texture
->color().pixel();
600 XSetWindowBorder(otk::OBDisplay::display
, frame
.title
,
601 screen
->getBorderColor()->pixel());
606 if (decorations
& Decor_Border
) {
607 frame
.fborder_pixel
= screen
->getWindowStyle()->f_focus
.color().pixel();
608 frame
.uborder_pixel
= screen
->getWindowStyle()->f_unfocus
.color().pixel();
611 if (decorations
& Decor_Handle
) {
612 texture
= &(screen
->getWindowStyle()->h_focus
);
613 frame
.fhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
616 frame
.fhandle_pixel
= texture
->color().pixel();
618 texture
= &(screen
->getWindowStyle()->h_unfocus
);
619 frame
.uhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
622 frame
.uhandle_pixel
= texture
->color().pixel();
624 texture
= &(screen
->getWindowStyle()->g_focus
);
625 frame
.fgrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.fgrip
);
627 frame
.fgrip_pixel
= texture
->color().pixel();
629 texture
= &(screen
->getWindowStyle()->g_unfocus
);
630 frame
.ugrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.ugrip
);
632 frame
.ugrip_pixel
= texture
->color().pixel();
634 XSetWindowBorder(otk::OBDisplay::display
, frame
.handle
,
635 screen
->getBorderColor()->pixel());
636 XSetWindowBorder(otk::OBDisplay::display
, frame
.left_grip
,
637 screen
->getBorderColor()->pixel());
638 XSetWindowBorder(otk::OBDisplay::display
, frame
.right_grip
,
639 screen
->getBorderColor()->pixel());
642 XSetWindowBorder(otk::OBDisplay::display
, frame
.window
,
643 screen
->getBorderColor()->pixel());
647 void BlackboxWindow::decorateLabel(void) {
648 otk::BTexture
*texture
;
650 texture
= &(screen
->getWindowStyle()->l_focus
);
651 frame
.flabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.flabel
);
653 frame
.flabel_pixel
= texture
->color().pixel();
655 texture
= &(screen
->getWindowStyle()->l_unfocus
);
656 frame
.ulabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.ulabel
);
658 frame
.ulabel_pixel
= texture
->color().pixel();
662 void BlackboxWindow::createHandle(void) {
663 frame
.handle
= createChildWindow(frame
.window
,
664 ButtonPressMask
| ButtonReleaseMask
|
665 ButtonMotionMask
| ExposureMask
);
666 blackbox
->saveWindowSearch(frame
.handle
, this);
669 createChildWindow(frame
.handle
,
670 ButtonPressMask
| ButtonReleaseMask
|
671 ButtonMotionMask
| ExposureMask
,
672 blackbox
->getLowerLeftAngleCursor());
673 blackbox
->saveWindowSearch(frame
.left_grip
, this);
676 createChildWindow(frame
.handle
,
677 ButtonPressMask
| ButtonReleaseMask
|
678 ButtonMotionMask
| ExposureMask
,
679 blackbox
->getLowerRightAngleCursor());
680 blackbox
->saveWindowSearch(frame
.right_grip
, this);
684 void BlackboxWindow::destroyHandle(void) {
686 screen
->getImageControl()->removeImage(frame
.fhandle
);
689 screen
->getImageControl()->removeImage(frame
.uhandle
);
692 screen
->getImageControl()->removeImage(frame
.fgrip
);
695 screen
->getImageControl()->removeImage(frame
.ugrip
);
697 blackbox
->removeWindowSearch(frame
.left_grip
);
698 blackbox
->removeWindowSearch(frame
.right_grip
);
700 XDestroyWindow(otk::OBDisplay::display
, frame
.left_grip
);
701 XDestroyWindow(otk::OBDisplay::display
, frame
.right_grip
);
702 frame
.left_grip
= frame
.right_grip
= None
;
704 blackbox
->removeWindowSearch(frame
.handle
);
705 XDestroyWindow(otk::OBDisplay::display
, frame
.handle
);
710 void BlackboxWindow::createTitlebar(void) {
711 frame
.title
= createChildWindow(frame
.window
,
712 ButtonPressMask
| ButtonReleaseMask
|
713 ButtonMotionMask
| ExposureMask
);
714 frame
.label
= createChildWindow(frame
.title
,
715 ButtonPressMask
| ButtonReleaseMask
|
716 ButtonMotionMask
| ExposureMask
);
717 blackbox
->saveWindowSearch(frame
.title
, this);
718 blackbox
->saveWindowSearch(frame
.label
, this);
720 if (decorations
& Decor_Iconify
) createIconifyButton();
721 if (decorations
& Decor_Maximize
) createMaximizeButton();
722 if (decorations
& Decor_Close
) createCloseButton();
726 void BlackboxWindow::destroyTitlebar(void) {
727 if (frame
.close_button
)
728 destroyCloseButton();
730 if (frame
.iconify_button
)
731 destroyIconifyButton();
733 if (frame
.maximize_button
)
734 destroyMaximizeButton();
736 if (frame
.stick_button
)
737 destroyStickyButton();
740 screen
->getImageControl()->removeImage(frame
.ftitle
);
743 screen
->getImageControl()->removeImage(frame
.utitle
);
746 screen
->getImageControl()->removeImage(frame
.flabel
);
749 screen
->getImageControl()->removeImage(frame
.ulabel
);
752 screen
->getImageControl()->removeImage(frame
.fbutton
);
755 screen
->getImageControl()->removeImage(frame
.ubutton
);
757 blackbox
->removeWindowSearch(frame
.title
);
758 blackbox
->removeWindowSearch(frame
.label
);
760 XDestroyWindow(otk::OBDisplay::display
, frame
.label
);
761 XDestroyWindow(otk::OBDisplay::display
, frame
.title
);
762 frame
.title
= frame
.label
= None
;
766 void BlackboxWindow::createCloseButton(void) {
767 if (frame
.title
!= None
) {
768 frame
.close_button
= createChildWindow(frame
.title
,
771 ButtonMotionMask
| ExposureMask
);
772 blackbox
->saveWindowSearch(frame
.close_button
, this);
777 void BlackboxWindow::destroyCloseButton(void) {
778 blackbox
->removeWindowSearch(frame
.close_button
);
779 XDestroyWindow(otk::OBDisplay::display
, frame
.close_button
);
780 frame
.close_button
= None
;
784 void BlackboxWindow::createIconifyButton(void) {
785 if (frame
.title
!= None
) {
786 frame
.iconify_button
= createChildWindow(frame
.title
,
789 ButtonMotionMask
| ExposureMask
);
790 blackbox
->saveWindowSearch(frame
.iconify_button
, this);
795 void BlackboxWindow::destroyIconifyButton(void) {
796 blackbox
->removeWindowSearch(frame
.iconify_button
);
797 XDestroyWindow(otk::OBDisplay::display
, frame
.iconify_button
);
798 frame
.iconify_button
= None
;
802 void BlackboxWindow::createMaximizeButton(void) {
803 if (frame
.title
!= None
) {
804 frame
.maximize_button
= createChildWindow(frame
.title
,
807 ButtonMotionMask
| ExposureMask
);
808 blackbox
->saveWindowSearch(frame
.maximize_button
, this);
813 void BlackboxWindow::destroyMaximizeButton(void) {
814 blackbox
->removeWindowSearch(frame
.maximize_button
);
815 XDestroyWindow(otk::OBDisplay::display
, frame
.maximize_button
);
816 frame
.maximize_button
= None
;
819 void BlackboxWindow::createStickyButton(void) {
820 if (frame
.title
!= None
) {
821 frame
.stick_button
= createChildWindow(frame
.title
,
824 ButtonMotionMask
| ExposureMask
);
825 blackbox
->saveWindowSearch(frame
.stick_button
, this);
829 void BlackboxWindow::destroyStickyButton(void) {
830 blackbox
->removeWindowSearch(frame
.stick_button
);
831 XDestroyWindow(otk::OBDisplay::display
, frame
.stick_button
);
832 frame
.stick_button
= None
;
835 void BlackboxWindow::positionButtons(bool redecorate_label
) {
836 string layout
= blackbox
->getTitlebarLayout();
839 bool hasclose
, hasiconify
, hasmaximize
, haslabel
, hasstick
;
840 hasclose
= hasiconify
= hasmaximize
= haslabel
= hasstick
= false;
842 string::const_iterator it
, end
;
843 for (it
= layout
.begin(), end
= layout
.end(); it
!= end
; ++it
) {
846 if (! hasclose
&& (decorations
& Decor_Close
)) {
852 if (! hasiconify
&& (decorations
& Decor_Iconify
)) {
864 if (! hasmaximize
&& (decorations
& Decor_Maximize
)) {
878 if (! hasclose
&& frame
.close_button
)
879 destroyCloseButton();
880 if (! hasiconify
&& frame
.iconify_button
)
881 destroyIconifyButton();
882 if (! hasmaximize
&& frame
.maximize_button
)
883 destroyMaximizeButton();
884 if (! hasstick
&& frame
.stick_button
)
885 destroyStickyButton();
887 parsed
+= 'L'; // require that the label be in the layout
889 const unsigned int bsep
= frame
.bevel_w
+ 1; // separation between elements
890 const unsigned int by
= frame
.bevel_w
+ 1;
891 const unsigned int ty
= frame
.bevel_w
;
893 frame
.label_w
= frame
.inside_w
- bsep
* 2 -
894 (frame
.button_w
+ bsep
) * (parsed
.size() - 1);
896 unsigned int x
= bsep
;
897 for (it
= parsed
.begin(), end
= parsed
.end(); it
!= end
; ++it
) {
900 if (! frame
.close_button
) createCloseButton();
901 XMoveResizeWindow(otk::OBDisplay::display
, frame
.close_button
, x
, by
,
902 frame
.button_w
, frame
.button_w
);
903 x
+= frame
.button_w
+ bsep
;
906 if (! frame
.iconify_button
) createIconifyButton();
907 XMoveResizeWindow(otk::OBDisplay::display
, frame
.iconify_button
, x
, by
,
908 frame
.button_w
, frame
.button_w
);
909 x
+= frame
.button_w
+ bsep
;
912 if (! frame
.stick_button
) createStickyButton();
913 XMoveResizeWindow(otk::OBDisplay::display
, frame
.stick_button
, x
, by
,
914 frame
.button_w
, frame
.button_w
);
915 x
+= frame
.button_w
+ bsep
;
918 if (! frame
.maximize_button
) createMaximizeButton();
919 XMoveResizeWindow(otk::OBDisplay::display
, frame
.maximize_button
, x
, by
,
920 frame
.button_w
, frame
.button_w
);
921 x
+= frame
.button_w
+ bsep
;
924 XMoveResizeWindow(otk::OBDisplay::display
, frame
.label
, x
, ty
,
925 frame
.label_w
, frame
.label_h
);
926 x
+= frame
.label_w
+ bsep
;
931 if (redecorate_label
) decorateLabel();
937 void BlackboxWindow::reconfigure(void) {
938 restoreGravity(client
.rect
);
940 applyGravity(frame
.rect
);
950 void BlackboxWindow::grabButtons(void) {
951 mod_mask
= blackbox
->getMouseModMask();
953 if (! screen
->isSloppyFocus() || screen
->doClickRaise())
954 // grab button 1 for changing focus/raising
955 otk::OBDisplay::grabButton(Button1
, 0, frame
.plate
, True
, ButtonPressMask
,
956 GrabModeSync
, GrabModeSync
, frame
.plate
, None
,
957 screen
->allowScrollLock());
959 if (functions
& Func_Move
)
960 otk::OBDisplay::grabButton(Button1
, mod_mask
, frame
.window
, True
,
961 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
962 GrabModeAsync
, frame
.window
, None
,
963 screen
->allowScrollLock());
964 if (functions
& Func_Resize
)
965 otk::OBDisplay::grabButton(Button3
, mod_mask
, frame
.window
, True
,
966 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
967 GrabModeAsync
, frame
.window
, None
,
968 screen
->allowScrollLock());
969 // alt+middle lowers the window
970 otk::OBDisplay::grabButton(Button2
, mod_mask
, frame
.window
, True
,
971 ButtonReleaseMask
, GrabModeAsync
, GrabModeAsync
,
972 frame
.window
, None
, screen
->allowScrollLock());
976 void BlackboxWindow::ungrabButtons(void) {
977 otk::OBDisplay::ungrabButton(Button1
, 0, frame
.plate
);
978 otk::OBDisplay::ungrabButton(Button1
, mod_mask
, frame
.window
);
979 otk::OBDisplay::ungrabButton(Button2
, mod_mask
, frame
.window
);
980 otk::OBDisplay::ungrabButton(Button3
, mod_mask
, frame
.window
);
984 void BlackboxWindow::positionWindows(void) {
985 XMoveResizeWindow(otk::OBDisplay::display
, frame
.window
,
986 frame
.rect
.x(), frame
.rect
.y(), frame
.inside_w
,
987 (flags
.shaded
) ? frame
.title_h
: frame
.inside_h
);
988 XSetWindowBorderWidth(otk::OBDisplay::display
, frame
.window
,
990 XSetWindowBorderWidth(otk::OBDisplay::display
, frame
.plate
,
992 XMoveResizeWindow(otk::OBDisplay::display
, frame
.plate
,
993 frame
.margin
.left
- frame
.mwm_border_w
- frame
.border_w
,
994 frame
.margin
.top
- frame
.mwm_border_w
- frame
.border_w
,
995 client
.rect
.width(), client
.rect
.height());
996 XMoveResizeWindow(otk::OBDisplay::display
, client
.window
,
997 0, 0, client
.rect
.width(), client
.rect
.height());
998 // ensure client.rect contains the real location
999 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1000 frame
.rect
.top() + frame
.margin
.top
);
1002 if (decorations
& Decor_Titlebar
) {
1003 if (frame
.title
== None
) createTitlebar();
1005 XSetWindowBorderWidth(otk::OBDisplay::display
, frame
.title
,
1007 XMoveResizeWindow(otk::OBDisplay::display
, frame
.title
, -frame
.border_w
,
1008 -frame
.border_w
, frame
.inside_w
, frame
.title_h
);
1011 XMapSubwindows(otk::OBDisplay::display
, frame
.title
);
1012 XMapWindow(otk::OBDisplay::display
, frame
.title
);
1013 } else if (frame
.title
) {
1016 if (decorations
& Decor_Handle
) {
1017 if (frame
.handle
== None
) createHandle();
1018 XSetWindowBorderWidth(otk::OBDisplay::display
, frame
.handle
,
1020 XSetWindowBorderWidth(otk::OBDisplay::display
, frame
.left_grip
,
1022 XSetWindowBorderWidth(otk::OBDisplay::display
, frame
.right_grip
,
1025 // use client.rect here so the value is correct even if shaded
1026 XMoveResizeWindow(otk::OBDisplay::display
, frame
.handle
,
1028 client
.rect
.height() + frame
.margin
.top
+
1029 frame
.mwm_border_w
- frame
.border_w
,
1030 frame
.inside_w
, frame
.handle_h
);
1031 XMoveResizeWindow(otk::OBDisplay::display
, frame
.left_grip
,
1032 -frame
.border_w
, -frame
.border_w
,
1033 frame
.grip_w
, frame
.handle_h
);
1034 XMoveResizeWindow(otk::OBDisplay::display
, frame
.right_grip
,
1035 frame
.inside_w
- frame
.grip_w
- frame
.border_w
,
1036 -frame
.border_w
, frame
.grip_w
, frame
.handle_h
);
1038 XMapSubwindows(otk::OBDisplay::display
, frame
.handle
);
1039 XMapWindow(otk::OBDisplay::display
, frame
.handle
);
1040 } else if (frame
.handle
) {
1043 XSync(otk::OBDisplay::display
, False
);
1047 void BlackboxWindow::updateStrut(void) {
1048 unsigned long num
= 4;
1049 unsigned long *data
;
1050 if (! xatom
->getValue(client
.window
, XAtom::net_wm_strut
, XAtom::cardinal
,
1055 client
.strut
.left
= data
[0];
1056 client
.strut
.right
= data
[1];
1057 client
.strut
.top
= data
[2];
1058 client
.strut
.bottom
= data
[3];
1060 screen
->updateAvailableArea();
1067 bool BlackboxWindow::getWindowType(void) {
1068 window_type
= (WindowType
) -1;
1071 unsigned long num
= (unsigned) -1;
1072 if (xatom
->getValue(client
.window
, XAtom::net_wm_window_type
, XAtom::atom
,
1074 for (unsigned long i
= 0; i
< num
; ++i
) {
1075 if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_desktop
))
1076 window_type
= Type_Desktop
;
1077 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_dock
))
1078 window_type
= Type_Dock
;
1079 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_toolbar
))
1080 window_type
= Type_Toolbar
;
1081 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_menu
))
1082 window_type
= Type_Menu
;
1083 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_utility
))
1084 window_type
= Type_Utility
;
1085 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_splash
))
1086 window_type
= Type_Splash
;
1087 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_dialog
))
1088 window_type
= Type_Dialog
;
1089 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_normal
))
1090 window_type
= Type_Normal
;
1092 xatom
->getAtom(XAtom::kde_net_wm_window_type_override
))
1093 mwm_decorations
= 0; // prevent this window from getting any decor
1098 if (window_type
== (WindowType
) -1) {
1100 * the window type hint was not set, which means we either classify ourself
1101 * as a normal window or a dialog, depending on if we are a transient.
1104 window_type
= Type_Dialog
;
1106 window_type
= Type_Normal
;
1115 void BlackboxWindow::getWMName(void) {
1116 if (xatom
->getValue(client
.window
, XAtom::net_wm_name
,
1117 XAtom::utf8
, client
.title
) &&
1118 !client
.title
.empty()) {
1119 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
1122 //fall through to using WM_NAME
1123 if (xatom
->getValue(client
.window
, XAtom::wm_name
, XAtom::ansi
, client
.title
)
1124 && !client
.title
.empty()) {
1125 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
1128 // fall back to an internal default
1129 client
.title
= "Unnamed";
1130 xatom
->setValue(client
.window
, XAtom::net_wm_visible_name
, XAtom::utf8
,
1133 #ifdef DEBUG_WITH_ID
1134 // the 16 is the 8 chars of the debug text plus the number
1135 char *tmp
= new char[client
.title
.length() + 16];
1136 sprintf(tmp
, "%s; id: 0x%lx", client
.title
.c_str(), client
.window
);
1143 void BlackboxWindow::getWMIconName(void) {
1144 if (xatom
->getValue(client
.window
, XAtom::net_wm_icon_name
,
1145 XAtom::utf8
, client
.icon_title
) &&
1146 !client
.icon_title
.empty()) {
1147 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1150 //fall through to using WM_ICON_NAME
1151 if (xatom
->getValue(client
.window
, XAtom::wm_icon_name
, XAtom::ansi
,
1152 client
.icon_title
) &&
1153 !client
.icon_title
.empty()) {
1154 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1157 // fall back to using the main name
1158 client
.icon_title
= client
.title
;
1159 xatom
->setValue(client
.window
, XAtom::net_wm_visible_icon_name
, XAtom::utf8
,
1165 * Retrieve which WM Protocols are supported by the client window.
1166 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
1167 * window's decorations and allow the close behavior.
1168 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
1171 void BlackboxWindow::getWMProtocols(void) {
1175 if (XGetWMProtocols(otk::OBDisplay::display
, client
.window
,
1176 &proto
, &num_return
)) {
1177 for (int i
= 0; i
< num_return
; ++i
) {
1178 if (proto
[i
] == xatom
->getAtom(XAtom::wm_delete_window
)) {
1179 decorations
|= Decor_Close
;
1180 functions
|= Func_Close
;
1181 } else if (proto
[i
] == xatom
->getAtom(XAtom::wm_take_focus
))
1182 flags
.send_focus_message
= True
;
1191 * Gets the value of the WM_HINTS property.
1192 * If the property is not set, then use a set of default values.
1194 void BlackboxWindow::getWMHints(void) {
1195 focus_mode
= F_Passive
;
1197 // remove from current window group
1198 if (client
.window_group
) {
1199 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1200 if (group
) group
->removeWindow(this);
1202 client
.window_group
= None
;
1204 XWMHints
*wmhint
= XGetWMHints(otk::OBDisplay::display
, client
.window
);
1209 if (wmhint
->flags
& InputHint
) {
1210 if (wmhint
->input
== True
) {
1211 if (flags
.send_focus_message
)
1212 focus_mode
= F_LocallyActive
;
1214 if (flags
.send_focus_message
)
1215 focus_mode
= F_GloballyActive
;
1217 focus_mode
= F_NoInput
;
1221 if (wmhint
->flags
& StateHint
)
1222 current_state
= wmhint
->initial_state
;
1224 if (wmhint
->flags
& WindowGroupHint
) {
1225 client
.window_group
= wmhint
->window_group
;
1227 // add window to the appropriate group
1228 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1229 if (! group
) { // no group found, create it!
1230 new BWindowGroup(blackbox
, client
.window_group
);
1231 group
= blackbox
->searchGroup(client
.window_group
);
1234 group
->addWindow(this);
1242 * Gets the value of the WM_NORMAL_HINTS property.
1243 * If the property is not set, then use a set of default values.
1245 void BlackboxWindow::getWMNormalHints(void) {
1247 XSizeHints sizehint
;
1249 client
.min_width
= client
.min_height
=
1250 client
.width_inc
= client
.height_inc
= 1;
1251 client
.base_width
= client
.base_height
= 0;
1252 client
.win_gravity
= NorthWestGravity
;
1254 client
.min_aspect_x
= client
.min_aspect_y
=
1255 client
.max_aspect_x
= client
.max_aspect_y
= 1;
1258 // don't limit the size of a window, the default max width is the biggest
1260 client
.max_width
= (unsigned) -1;
1261 client
.max_height
= (unsigned) -1;
1264 if (! XGetWMNormalHints(otk::OBDisplay::display
, client
.window
,
1265 &sizehint
, &icccm_mask
))
1268 client
.normal_hint_flags
= sizehint
.flags
;
1270 if (sizehint
.flags
& PMinSize
) {
1271 if (sizehint
.min_width
>= 0)
1272 client
.min_width
= sizehint
.min_width
;
1273 if (sizehint
.min_height
>= 0)
1274 client
.min_height
= sizehint
.min_height
;
1277 if (sizehint
.flags
& PMaxSize
) {
1278 if (sizehint
.max_width
> static_cast<signed>(client
.min_width
))
1279 client
.max_width
= sizehint
.max_width
;
1281 client
.max_width
= client
.min_width
;
1283 if (sizehint
.max_height
> static_cast<signed>(client
.min_height
))
1284 client
.max_height
= sizehint
.max_height
;
1286 client
.max_height
= client
.min_height
;
1289 if (sizehint
.flags
& PResizeInc
) {
1290 client
.width_inc
= sizehint
.width_inc
;
1291 client
.height_inc
= sizehint
.height_inc
;
1294 #if 0 // we do not support this at the moment
1295 if (sizehint
.flags
& PAspect
) {
1296 client
.min_aspect_x
= sizehint
.min_aspect
.x
;
1297 client
.min_aspect_y
= sizehint
.min_aspect
.y
;
1298 client
.max_aspect_x
= sizehint
.max_aspect
.x
;
1299 client
.max_aspect_y
= sizehint
.max_aspect
.y
;
1303 if (sizehint
.flags
& PBaseSize
) {
1304 client
.base_width
= sizehint
.base_width
;
1305 client
.base_height
= sizehint
.base_height
;
1308 if (sizehint
.flags
& PWinGravity
)
1309 client
.win_gravity
= sizehint
.win_gravity
;
1314 * Gets the NETWM hints for the class' contained window.
1316 void BlackboxWindow::getNetWMHints(void) {
1317 unsigned long workspace
;
1319 if (xatom
->getValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1321 if (workspace
== 0xffffffff)
1324 blackbox_attrib
.workspace
= workspace
;
1327 unsigned long *state
;
1328 unsigned long num
= (unsigned) -1;
1329 if (xatom
->getValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
1333 for (unsigned long i
= 0; i
< num
; ++i
) {
1334 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
))
1336 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_shaded
))
1337 flags
.shaded
= True
;
1338 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
))
1339 flags
.skip_taskbar
= True
;
1340 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_pager
))
1341 flags
.skip_pager
= True
;
1342 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_fullscreen
))
1343 flags
.fullscreen
= True
;
1344 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_hidden
))
1345 setState(IconicState
);
1346 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_vert
))
1348 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_horz
))
1352 flags
.maximized
= 1;
1354 flags
.maximized
= 2;
1356 flags
.maximized
= 3;
1364 * Gets the MWM hints for the class' contained window.
1365 * This is used while initializing the window to its first state, and not
1367 * Returns: true if the MWM hints are successfully retreived and applied;
1368 * false if they are not.
1370 void BlackboxWindow::getMWMHints(void) {
1374 num
= PropMwmHintsElements
;
1375 if (! xatom
->getValue(client
.window
, XAtom::motif_wm_hints
,
1376 XAtom::motif_wm_hints
, num
,
1377 (unsigned long **)&mwm_hint
))
1379 if (num
< PropMwmHintsElements
) {
1384 if (mwm_hint
->flags
& MwmHintsDecorations
) {
1385 if (mwm_hint
->decorations
& MwmDecorAll
) {
1386 mwm_decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
1387 Decor_Iconify
| Decor_Maximize
;
1389 mwm_decorations
= 0;
1391 if (mwm_hint
->decorations
& MwmDecorBorder
)
1392 mwm_decorations
|= Decor_Border
;
1393 if (mwm_hint
->decorations
& MwmDecorHandle
)
1394 mwm_decorations
|= Decor_Handle
;
1395 if (mwm_hint
->decorations
& MwmDecorTitle
)
1396 mwm_decorations
|= Decor_Titlebar
;
1397 if (mwm_hint
->decorations
& MwmDecorIconify
)
1398 mwm_decorations
|= Decor_Iconify
;
1399 if (mwm_hint
->decorations
& MwmDecorMaximize
)
1400 mwm_decorations
|= Decor_Maximize
;
1404 if (mwm_hint
->flags
& MwmHintsFunctions
) {
1405 if (mwm_hint
->functions
& MwmFuncAll
) {
1406 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
|
1411 if (mwm_hint
->functions
& MwmFuncResize
)
1412 functions
|= Func_Resize
;
1413 if (mwm_hint
->functions
& MwmFuncMove
)
1414 functions
|= Func_Move
;
1415 if (mwm_hint
->functions
& MwmFuncIconify
)
1416 functions
|= Func_Iconify
;
1417 if (mwm_hint
->functions
& MwmFuncMaximize
)
1418 functions
|= Func_Maximize
;
1419 if (mwm_hint
->functions
& MwmFuncClose
)
1420 functions
|= Func_Close
;
1428 * Gets the blackbox hints from the class' contained window.
1429 * This is used while initializing the window to its first state, and not
1431 * Returns: true if the hints are successfully retreived and applied; false if
1434 bool BlackboxWindow::getBlackboxHints(void) {
1436 BlackboxHints
*blackbox_hint
;
1438 num
= PropBlackboxHintsElements
;
1439 if (! xatom
->getValue(client
.window
, XAtom::blackbox_hints
,
1440 XAtom::blackbox_hints
, num
,
1441 (unsigned long **)&blackbox_hint
))
1443 if (num
< PropBlackboxHintsElements
) {
1444 delete [] blackbox_hint
;
1448 if (blackbox_hint
->flags
& AttribShaded
)
1449 flags
.shaded
= (blackbox_hint
->attrib
& AttribShaded
);
1451 if ((blackbox_hint
->flags
& AttribMaxHoriz
) &&
1452 (blackbox_hint
->flags
& AttribMaxVert
))
1453 flags
.maximized
= (blackbox_hint
->attrib
&
1454 (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1455 else if (blackbox_hint
->flags
& AttribMaxVert
)
1456 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxVert
) ? 2 : 0;
1457 else if (blackbox_hint
->flags
& AttribMaxHoriz
)
1458 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1460 if (blackbox_hint
->flags
& AttribOmnipresent
)
1461 flags
.stuck
= (blackbox_hint
->attrib
& AttribOmnipresent
);
1463 if (blackbox_hint
->flags
& AttribWorkspace
)
1464 blackbox_attrib
.workspace
= blackbox_hint
->workspace
;
1466 // if (blackbox_hint->flags & AttribStack)
1467 // don't yet have always on top/bottom for blackbox yet... working
1470 if (blackbox_hint
->flags
& AttribDecoration
) {
1471 switch (blackbox_hint
->decoration
) {
1473 blackbox_attrib
.decoration
= DecorNone
;
1480 // blackbox_attrib.decoration defaults to DecorNormal
1485 delete [] blackbox_hint
;
1491 void BlackboxWindow::getTransientInfo(void) {
1492 if (client
.transient_for
&&
1493 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1494 // reset transient_for in preparation of looking for a new owner
1495 client
.transient_for
->client
.transientList
.remove(this);
1498 // we have no transient_for until we find a new one
1499 client
.transient_for
= (BlackboxWindow
*) 0;
1502 if (! XGetTransientForHint(otk::OBDisplay::display
, client
.window
,
1504 // transient_for hint not set
1508 if (trans_for
== client
.window
) {
1509 // wierd client... treat this window as a normal window
1513 if (trans_for
== None
|| trans_for
== screen
->getRootWindow()) {
1514 // this is an undocumented interpretation of the ICCCM. a transient
1515 // associated with None/Root/itself is assumed to be a modal root
1516 // transient. we don't support the concept of a global transient,
1517 // so we just associate this transient with nothing, and perhaps
1518 // we will add support later for global modality.
1519 client
.transient_for
= (BlackboxWindow
*) ~0ul;
1524 client
.transient_for
= blackbox
->searchWindow(trans_for
);
1525 if (! client
.transient_for
&&
1526 client
.window_group
&& trans_for
== client
.window_group
) {
1527 // no direct transient_for, perhaps this is a group transient?
1528 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1529 if (group
) client
.transient_for
= group
->find(screen
);
1532 if (! client
.transient_for
|| client
.transient_for
== this) {
1533 // no transient_for found, or we have a wierd client that wants to be
1534 // a transient for itself, so we treat this window as a normal window
1535 client
.transient_for
= (BlackboxWindow
*) 0;
1539 // Check for a circular transient state: this can lock up Blackbox
1540 // when it tries to find the non-transient window for a transient.
1541 BlackboxWindow
*w
= this;
1542 while(w
->client
.transient_for
&&
1543 w
->client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1544 if(w
->client
.transient_for
== this) {
1545 client
.transient_for
= (BlackboxWindow
*) 0;
1548 w
= w
->client
.transient_for
;
1551 if (client
.transient_for
&&
1552 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1553 // register ourselves with our new transient_for
1554 client
.transient_for
->client
.transientList
.push_back(this);
1555 flags
.stuck
= client
.transient_for
->flags
.stuck
;
1560 BlackboxWindow
*BlackboxWindow::getTransientFor(void) const {
1561 if (client
.transient_for
&&
1562 client
.transient_for
!= (BlackboxWindow
*) ~0ul)
1563 return client
.transient_for
;
1569 * This function is responsible for updating both the client and the frame
1571 * According to the ICCCM a client message is not sent for a resize, only a
1574 void BlackboxWindow::configure(int dx
, int dy
,
1575 unsigned int dw
, unsigned int dh
) {
1576 bool send_event
= ((frame
.rect
.x() != dx
|| frame
.rect
.y() != dy
) &&
1579 if (dw
!= frame
.rect
.width() || dh
!= frame
.rect
.height()) {
1580 frame
.rect
.setRect(dx
, dy
, dw
, dh
);
1581 frame
.inside_w
= frame
.rect
.width() - (frame
.border_w
* 2);
1582 frame
.inside_h
= frame
.rect
.height() - (frame
.border_w
* 2);
1584 if (frame
.rect
.right() <= 0 || frame
.rect
.bottom() <= 0)
1585 frame
.rect
.setPos(0, 0);
1587 client
.rect
.setCoords(frame
.rect
.left() + frame
.margin
.left
,
1588 frame
.rect
.top() + frame
.margin
.top
,
1589 frame
.rect
.right() - frame
.margin
.right
,
1590 frame
.rect
.bottom() - frame
.margin
.bottom
);
1593 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
1600 redrawWindowFrame();
1602 frame
.rect
.setPos(dx
, dy
);
1604 XMoveWindow(otk::OBDisplay::display
, frame
.window
,
1605 frame
.rect
.x(), frame
.rect
.y());
1607 we may have been called just after an opaque window move, so even though
1608 the old coords match the new ones no ConfigureNotify has been sent yet.
1609 There are likely other times when this will be relevant as well.
1611 if (! flags
.moving
) send_event
= True
;
1615 // if moving, the update and event will occur when the move finishes
1616 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1617 frame
.rect
.top() + frame
.margin
.top
);
1620 event
.type
= ConfigureNotify
;
1622 event
.xconfigure
.display
= otk::OBDisplay::display
;
1623 event
.xconfigure
.event
= client
.window
;
1624 event
.xconfigure
.window
= client
.window
;
1625 event
.xconfigure
.x
= client
.rect
.x();
1626 event
.xconfigure
.y
= client
.rect
.y();
1627 event
.xconfigure
.width
= client
.rect
.width();
1628 event
.xconfigure
.height
= client
.rect
.height();
1629 event
.xconfigure
.border_width
= client
.old_bw
;
1630 event
.xconfigure
.above
= frame
.window
;
1631 event
.xconfigure
.override_redirect
= False
;
1633 XSendEvent(otk::OBDisplay::display
, client
.window
, False
,
1634 StructureNotifyMask
, &event
);
1635 XFlush(otk::OBDisplay::display
);
1641 void BlackboxWindow::configureShape(void) {
1642 XShapeCombineShape(otk::OBDisplay::display
, frame
.window
, ShapeBounding
,
1643 frame
.margin
.left
- frame
.border_w
,
1644 frame
.margin
.top
- frame
.border_w
,
1645 client
.window
, ShapeBounding
, ShapeSet
);
1648 XRectangle xrect
[2];
1650 if (decorations
& Decor_Titlebar
) {
1651 xrect
[0].x
= xrect
[0].y
= -frame
.border_w
;
1652 xrect
[0].width
= frame
.rect
.width();
1653 xrect
[0].height
= frame
.title_h
+ (frame
.border_w
* 2);
1657 if (decorations
& Decor_Handle
) {
1658 xrect
[1].x
= -frame
.border_w
;
1659 xrect
[1].y
= frame
.rect
.height() - frame
.margin
.bottom
+
1660 frame
.mwm_border_w
- frame
.border_w
;
1661 xrect
[1].width
= frame
.rect
.width();
1662 xrect
[1].height
= frame
.handle_h
+ (frame
.border_w
* 2);
1666 XShapeCombineRectangles(otk::OBDisplay::display
, frame
.window
,
1667 ShapeBounding
, 0, 0, xrect
, num
,
1668 ShapeUnion
, Unsorted
);
1672 void BlackboxWindow::clearShape(void) {
1673 XShapeCombineMask(otk::OBDisplay::display
, frame
.window
, ShapeBounding
,
1674 frame
.margin
.left
- frame
.border_w
,
1675 frame
.margin
.top
- frame
.border_w
,
1681 bool BlackboxWindow::setInputFocus(void) {
1682 if (flags
.focused
) return True
;
1684 assert(flags
.stuck
|| // window must be on the current workspace or sticky
1685 blackbox_attrib
.workspace
== screen
->getCurrentWorkspaceID());
1688 We only do this check for normal windows and dialogs because other windows
1689 do this on purpose, such as kde's kicker, and we don't want to go moving
1692 if (window_type
== Type_Normal
|| window_type
== Type_Dialog
)
1693 if (! frame
.rect
.intersects(screen
->getRect())) {
1694 // client is outside the screen, move it to the center
1695 configure((screen
->getWidth() - frame
.rect
.width()) / 2,
1696 (screen
->getHeight() - frame
.rect
.height()) / 2,
1697 frame
.rect
.width(), frame
.rect
.height());
1700 if (client
.transientList
.size() > 0) {
1701 // transfer focus to any modal transients
1702 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1703 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1704 if ((*it
)->flags
.modal
) return (*it
)->setInputFocus();
1708 if (focus_mode
== F_LocallyActive
|| focus_mode
== F_Passive
) {
1709 XSetInputFocus(otk::OBDisplay::display
, client
.window
,
1710 RevertToPointerRoot
, CurrentTime
);
1712 /* we could set the focus to none, since the window doesn't accept focus,
1713 * but we shouldn't set focus to nothing since this would surely make
1719 if (flags
.send_focus_message
) {
1721 ce
.xclient
.type
= ClientMessage
;
1722 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1723 ce
.xclient
.display
= otk::OBDisplay::display
;
1724 ce
.xclient
.window
= client
.window
;
1725 ce
.xclient
.format
= 32;
1726 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_take_focus
);
1727 ce
.xclient
.data
.l
[1] = blackbox
->getLastTime();
1728 ce
.xclient
.data
.l
[2] = 0l;
1729 ce
.xclient
.data
.l
[3] = 0l;
1730 ce
.xclient
.data
.l
[4] = 0l;
1731 XSendEvent(otk::OBDisplay::display
, client
.window
, False
,
1733 XFlush(otk::OBDisplay::display
);
1740 void BlackboxWindow::iconify(void) {
1741 if (flags
.iconic
|| ! (functions
& Func_Iconify
)) return;
1743 // We don't need to worry about resizing because resizing always grabs the X
1744 // server. This should only ever happen if using opaque moving.
1749 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1750 * we need to clear the event mask on client.window for a split second.
1751 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1752 * split second, leaving us with a ghost window... so, we need to do this
1753 * while the X server is grabbed
1755 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1756 StructureNotifyMask
;
1757 XGrabServer(otk::OBDisplay::display
);
1758 XSelectInput(otk::OBDisplay::display
, client
.window
,
1759 event_mask
& ~StructureNotifyMask
);
1760 XUnmapWindow(otk::OBDisplay::display
, client
.window
);
1761 XSelectInput(otk::OBDisplay::display
, client
.window
, event_mask
);
1762 XUngrabServer(otk::OBDisplay::display
);
1764 XUnmapWindow(otk::OBDisplay::display
, frame
.window
);
1765 flags
.visible
= False
;
1766 flags
.iconic
= True
;
1768 setState(IconicState
);
1770 screen
->getWorkspace(blackbox_attrib
.workspace
)->removeWindow(this);
1772 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
1773 if (i
!= blackbox_attrib
.workspace
)
1774 screen
->getWorkspace(i
)->removeWindow(this, True
);
1777 if (isTransient()) {
1778 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1779 ! client
.transient_for
->flags
.iconic
) {
1780 // iconify our transient_for
1781 client
.transient_for
->iconify();
1785 screen
->addIcon(this);
1787 if (client
.transientList
.size() > 0) {
1788 // iconify all transients
1789 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1790 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1791 if (! (*it
)->flags
.iconic
) (*it
)->iconify();
1794 screen
->updateStackingList();
1798 void BlackboxWindow::show(void) {
1799 flags
.visible
= True
;
1800 flags
.iconic
= False
;
1802 current_state
= (flags
.shaded
) ? IconicState
: NormalState
;
1803 setState(current_state
);
1805 XMapWindow(otk::OBDisplay::display
, client
.window
);
1806 XMapSubwindows(otk::OBDisplay::display
, frame
.window
);
1807 XMapWindow(otk::OBDisplay::display
, frame
.window
);
1812 XTranslateCoordinates(otk::OBDisplay::display
, client
.window
,
1813 screen
->getRootWindow(),
1814 0, 0, &real_x
, &real_y
, &child
);
1815 fprintf(stderr
, "%s -- assumed: (%d, %d), real: (%d, %d)\n", getTitle(),
1816 client
.rect
.left(), client
.rect
.top(), real_x
, real_y
);
1817 assert(client
.rect
.left() == real_x
&& client
.rect
.top() == real_y
);
1822 void BlackboxWindow::deiconify(bool reassoc
, bool raise
) {
1823 if (flags
.iconic
|| reassoc
)
1824 screen
->reassociateWindow(this, BSENTINEL
, False
);
1825 else if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID())
1830 // reassociate and deiconify all transients
1831 if (reassoc
&& client
.transientList
.size() > 0) {
1832 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1833 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1834 (*it
)->deiconify(True
, False
);
1838 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1842 void BlackboxWindow::close(void) {
1843 if (! (functions
& Func_Close
)) return;
1846 ce
.xclient
.type
= ClientMessage
;
1847 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1848 ce
.xclient
.display
= otk::OBDisplay::display
;
1849 ce
.xclient
.window
= client
.window
;
1850 ce
.xclient
.format
= 32;
1851 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_delete_window
);
1852 ce
.xclient
.data
.l
[1] = CurrentTime
;
1853 ce
.xclient
.data
.l
[2] = 0l;
1854 ce
.xclient
.data
.l
[3] = 0l;
1855 ce
.xclient
.data
.l
[4] = 0l;
1856 XSendEvent(otk::OBDisplay::display
, client
.window
, False
, NoEventMask
, &ce
);
1857 XFlush(otk::OBDisplay::display
);
1861 void BlackboxWindow::withdraw(void) {
1862 // We don't need to worry about resizing because resizing always grabs the X
1863 // server. This should only ever happen if using opaque moving.
1867 flags
.visible
= False
;
1868 flags
.iconic
= False
;
1870 setState(current_state
);
1872 XUnmapWindow(otk::OBDisplay::display
, frame
.window
);
1874 XGrabServer(otk::OBDisplay::display
);
1876 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1877 StructureNotifyMask
;
1878 XSelectInput(otk::OBDisplay::display
, client
.window
,
1879 event_mask
& ~StructureNotifyMask
);
1880 XUnmapWindow(otk::OBDisplay::display
, client
.window
);
1881 XSelectInput(otk::OBDisplay::display
, client
.window
, event_mask
);
1883 XUngrabServer(otk::OBDisplay::display
);
1887 void BlackboxWindow::maximize(unsigned int button
) {
1888 if (! (functions
& Func_Maximize
)) return;
1890 // We don't need to worry about resizing because resizing always grabs the X
1891 // server. This should only ever happen if using opaque moving.
1895 if (flags
.maximized
) {
1896 flags
.maximized
= 0;
1898 blackbox_attrib
.flags
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1899 blackbox_attrib
.attrib
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1902 when a resize finishes, maximize(0) is called to clear any maximization
1903 flags currently set. Otherwise it still thinks it is maximized.
1904 so we do not need to call configure() because resizing will handle it
1906 if (! flags
.resizing
)
1907 configure(blackbox_attrib
.premax_x
, blackbox_attrib
.premax_y
,
1908 blackbox_attrib
.premax_w
, blackbox_attrib
.premax_h
);
1910 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
1911 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
1913 redrawAllButtons(); // in case it is not called in configure()
1914 setState(current_state
);
1918 blackbox_attrib
.premax_x
= frame
.rect
.x();
1919 blackbox_attrib
.premax_y
= frame
.rect
.y();
1920 blackbox_attrib
.premax_w
= frame
.rect
.width();
1921 // use client.rect so that clients can be restored even if shaded
1922 blackbox_attrib
.premax_h
=
1923 client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
;
1926 if (screen
->isXineramaActive() && blackbox
->doXineramaMaximizing()) {
1927 // find the area to use
1928 RectList availableAreas
= screen
->allAvailableAreas();
1929 RectList::iterator it
, end
= availableAreas
.end();
1931 for (it
= availableAreas
.begin(); it
!= end
; ++it
)
1932 if (it
->intersects(frame
.rect
)) break;
1933 if (it
== end
) // the window isn't inside an area
1934 it
= availableAreas
.begin(); // so just default to the first one
1936 frame
.changing
= *it
;
1939 frame
.changing
= screen
->availableArea();
1943 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1944 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1948 blackbox_attrib
.flags
|= AttribMaxVert
;
1949 blackbox_attrib
.attrib
|= AttribMaxVert
;
1951 frame
.changing
.setX(frame
.rect
.x());
1952 frame
.changing
.setWidth(frame
.rect
.width());
1956 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1957 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1959 frame
.changing
.setY(frame
.rect
.y());
1960 frame
.changing
.setHeight(frame
.rect
.height());
1967 blackbox_attrib
.flags
^= AttribShaded
;
1968 blackbox_attrib
.attrib
^= AttribShaded
;
1969 flags
.shaded
= False
;
1972 flags
.maximized
= button
;
1974 configure(frame
.changing
.x(), frame
.changing
.y(),
1975 frame
.changing
.width(), frame
.changing
.height());
1977 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1978 redrawAllButtons(); // in case it is not called in configure()
1979 setState(current_state
);
1983 // re-maximizes the window to take into account availableArea changes
1984 void BlackboxWindow::remaximize(void) {
1986 // we only update the window's attributes otherwise we lose the shade bit
1987 switch(flags
.maximized
) {
1989 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1990 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1994 blackbox_attrib
.flags
|= AttribMaxVert
;
1995 blackbox_attrib
.attrib
|= AttribMaxVert
;
1999 blackbox_attrib
.flags
|= AttribMaxHoriz
;
2000 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
2006 // save the original dimensions because maximize will wipe them out
2007 int premax_x
= blackbox_attrib
.premax_x
,
2008 premax_y
= blackbox_attrib
.premax_y
,
2009 premax_w
= blackbox_attrib
.premax_w
,
2010 premax_h
= blackbox_attrib
.premax_h
;
2012 unsigned int button
= flags
.maximized
;
2013 flags
.maximized
= 0; // trick maximize() into working
2016 // restore saved values
2017 blackbox_attrib
.premax_x
= premax_x
;
2018 blackbox_attrib
.premax_y
= premax_y
;
2019 blackbox_attrib
.premax_w
= premax_w
;
2020 blackbox_attrib
.premax_h
= premax_h
;
2024 void BlackboxWindow::setWorkspace(unsigned int n
) {
2025 blackbox_attrib
.flags
|= AttribWorkspace
;
2026 blackbox_attrib
.workspace
= n
;
2027 if (n
== BSENTINEL
) { // iconified window
2029 we set the workspace to 'all workspaces' so that taskbars will show the
2030 window. otherwise, it made uniconifying a window imposible without the
2031 blackbox workspace menu
2035 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
, n
);
2039 void BlackboxWindow::shade(void) {
2041 XResizeWindow(otk::OBDisplay::display
, frame
.window
,
2042 frame
.inside_w
, frame
.inside_h
);
2043 flags
.shaded
= False
;
2044 blackbox_attrib
.flags
^= AttribShaded
;
2045 blackbox_attrib
.attrib
^= AttribShaded
;
2047 setState(NormalState
);
2049 // set the frame rect to the normal size
2050 frame
.rect
.setHeight(client
.rect
.height() + frame
.margin
.top
+
2051 frame
.margin
.bottom
);
2053 if (! (decorations
& Decor_Titlebar
))
2054 return; // can't shade it without a titlebar!
2056 XResizeWindow(otk::OBDisplay::display
, frame
.window
,
2057 frame
.inside_w
, frame
.title_h
);
2058 flags
.shaded
= True
;
2059 blackbox_attrib
.flags
|= AttribShaded
;
2060 blackbox_attrib
.attrib
|= AttribShaded
;
2062 setState(IconicState
);
2064 // set the frame rect to the shaded size
2065 frame
.rect
.setHeight(frame
.title_h
+ (frame
.border_w
* 2));
2071 * (Un)Sticks a window and its relatives.
2073 void BlackboxWindow::stick(void) {
2075 blackbox_attrib
.flags
^= AttribOmnipresent
;
2076 blackbox_attrib
.attrib
^= AttribOmnipresent
;
2078 flags
.stuck
= False
;
2080 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
2081 if (i
!= blackbox_attrib
.workspace
)
2082 screen
->getWorkspace(i
)->removeWindow(this, True
);
2085 screen
->reassociateWindow(this, BSENTINEL
, True
);
2086 // temporary fix since sticky windows suck. set the hint to what we
2087 // actually hold in our data.
2088 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
2089 blackbox_attrib
.workspace
);
2091 setState(current_state
);
2095 blackbox_attrib
.flags
|= AttribOmnipresent
;
2096 blackbox_attrib
.attrib
|= AttribOmnipresent
;
2098 // temporary fix since sticky windows suck. set the hint to a different
2099 // value than that contained in the class' data.
2100 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
2103 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
2104 if (i
!= blackbox_attrib
.workspace
)
2105 screen
->getWorkspace(i
)->addWindow(this, False
, True
);
2107 setState(current_state
);
2113 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
2114 client
.transient_for
->isStuck() != flags
.stuck
)
2115 client
.transient_for
->stick();
2116 // go down the chain
2117 BlackboxWindowList::iterator it
;
2118 const BlackboxWindowList::iterator end
= client
.transientList
.end();
2119 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
2120 if ((*it
)->isStuck() != flags
.stuck
)
2125 void BlackboxWindow::redrawWindowFrame(void) const {
2126 if (decorations
& Decor_Titlebar
) {
2127 if (flags
.focused
) {
2129 XSetWindowBackgroundPixmap(otk::OBDisplay::display
,
2130 frame
.title
, frame
.ftitle
);
2132 XSetWindowBackground(otk::OBDisplay::display
,
2133 frame
.title
, frame
.ftitle_pixel
);
2136 XSetWindowBackgroundPixmap(otk::OBDisplay::display
,
2137 frame
.title
, frame
.utitle
);
2139 XSetWindowBackground(otk::OBDisplay::display
,
2140 frame
.title
, frame
.utitle_pixel
);
2142 XClearWindow(otk::OBDisplay::display
, frame
.title
);
2148 if (decorations
& Decor_Handle
) {
2149 if (flags
.focused
) {
2151 XSetWindowBackgroundPixmap(otk::OBDisplay::display
,
2152 frame
.handle
, frame
.fhandle
);
2154 XSetWindowBackground(otk::OBDisplay::display
,
2155 frame
.handle
, frame
.fhandle_pixel
);
2158 XSetWindowBackgroundPixmap(otk::OBDisplay::display
,
2159 frame
.left_grip
, frame
.fgrip
);
2160 XSetWindowBackgroundPixmap(otk::OBDisplay::display
,
2161 frame
.right_grip
, frame
.fgrip
);
2163 XSetWindowBackground(otk::OBDisplay::display
,
2164 frame
.left_grip
, frame
.fgrip_pixel
);
2165 XSetWindowBackground(otk::OBDisplay::display
,
2166 frame
.right_grip
, frame
.fgrip_pixel
);
2170 XSetWindowBackgroundPixmap(otk::OBDisplay::display
,
2171 frame
.handle
, frame
.uhandle
);
2173 XSetWindowBackground(otk::OBDisplay::display
,
2174 frame
.handle
, frame
.uhandle_pixel
);
2177 XSetWindowBackgroundPixmap(otk::OBDisplay::display
,
2178 frame
.left_grip
, frame
.ugrip
);
2179 XSetWindowBackgroundPixmap(otk::OBDisplay::display
,
2180 frame
.right_grip
, frame
.ugrip
);
2182 XSetWindowBackground(otk::OBDisplay::display
,
2183 frame
.left_grip
, frame
.ugrip_pixel
);
2184 XSetWindowBackground(otk::OBDisplay::display
,
2185 frame
.right_grip
, frame
.ugrip_pixel
);
2188 XClearWindow(otk::OBDisplay::display
, frame
.handle
);
2189 XClearWindow(otk::OBDisplay::display
, frame
.left_grip
);
2190 XClearWindow(otk::OBDisplay::display
, frame
.right_grip
);
2193 if (decorations
& Decor_Border
) {
2195 XSetWindowBorder(otk::OBDisplay::display
,
2196 frame
.plate
, frame
.fborder_pixel
);
2198 XSetWindowBorder(otk::OBDisplay::display
,
2199 frame
.plate
, frame
.uborder_pixel
);
2204 void BlackboxWindow::setFocusFlag(bool focus
) {
2205 // only focus a window if it is visible
2206 if (focus
&& ! flags
.visible
)
2209 flags
.focused
= focus
;
2211 redrawWindowFrame();
2214 blackbox
->setFocusedWindow(this);
2218 void BlackboxWindow::installColormap(bool install
) {
2219 int i
= 0, ncmap
= 0;
2220 Colormap
*cmaps
= XListInstalledColormaps(otk::OBDisplay::display
,
2221 client
.window
, &ncmap
);
2223 XWindowAttributes wattrib
;
2224 if (XGetWindowAttributes(otk::OBDisplay::display
,
2225 client
.window
, &wattrib
)) {
2227 // install the window's colormap
2228 for (i
= 0; i
< ncmap
; i
++) {
2229 if (*(cmaps
+ i
) == wattrib
.colormap
)
2230 // this window is using an installed color map... do not install
2233 // otherwise, install the window's colormap
2235 XInstallColormap(otk::OBDisplay::display
, wattrib
.colormap
);
2237 // uninstall the window's colormap
2238 for (i
= 0; i
< ncmap
; i
++) {
2239 if (*(cmaps
+ i
) == wattrib
.colormap
)
2240 // we found the colormap to uninstall
2241 XUninstallColormap(otk::OBDisplay::display
, wattrib
.colormap
);
2251 void BlackboxWindow::setAllowedActions(void) {
2255 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_shade
);
2256 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_change_desktop
);
2257 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_close
);
2259 if (functions
& Func_Move
)
2260 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_move
);
2261 if (functions
& Func_Resize
)
2262 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_resize
);
2263 if (functions
& Func_Maximize
) {
2264 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_horz
);
2265 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_vert
);
2268 xatom
->setValue(client
.window
, XAtom::net_wm_allowed_actions
, XAtom::atom
,
2273 void BlackboxWindow::setState(unsigned long new_state
) {
2274 current_state
= new_state
;
2276 unsigned long state
[2];
2277 state
[0] = current_state
;
2279 xatom
->setValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
, state
, 2);
2281 xatom
->setValue(client
.window
, XAtom::blackbox_attributes
,
2282 XAtom::blackbox_attributes
, (unsigned long *)&blackbox_attrib
,
2283 PropBlackboxAttributesElements
);
2288 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_modal
);
2290 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_shaded
);
2292 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_hidden
);
2293 if (flags
.skip_taskbar
)
2294 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
);
2295 if (flags
.skip_pager
)
2296 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_pager
);
2297 if (flags
.fullscreen
)
2298 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_fullscreen
);
2299 if (flags
.maximized
== 1 || flags
.maximized
== 2)
2300 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_vert
);
2301 if (flags
.maximized
== 1 || flags
.maximized
== 3)
2302 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_horz
);
2303 xatom
->setValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
2308 bool BlackboxWindow::getState(void) {
2309 bool ret
= xatom
->getValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
,
2311 if (! ret
) current_state
= 0;
2316 void BlackboxWindow::restoreAttributes(void) {
2317 unsigned long num
= PropBlackboxAttributesElements
;
2318 BlackboxAttributes
*net
;
2319 if (! xatom
->getValue(client
.window
, XAtom::blackbox_attributes
,
2320 XAtom::blackbox_attributes
, num
,
2321 (unsigned long **)&net
))
2323 if (num
< PropBlackboxAttributesElements
) {
2328 if (net
->flags
& AttribShaded
&& net
->attrib
& AttribShaded
) {
2329 flags
.shaded
= False
;
2330 unsigned long orig_state
= current_state
;
2334 At this point in the life of a window, current_state should only be set
2335 to IconicState if the window was an *icon*, not if it was shaded.
2337 if (orig_state
!= IconicState
)
2338 current_state
= WithdrawnState
;
2341 if (net
->workspace
!= screen
->getCurrentWorkspaceID() &&
2342 net
->workspace
< screen
->getWorkspaceCount())
2343 screen
->reassociateWindow(this, net
->workspace
, True
);
2345 if ((blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID()) &&
2346 (blackbox_attrib
.workspace
< screen
->getWorkspaceCount())) {
2347 // set to WithdrawnState so it will be mapped on the new workspace
2348 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2349 } else if (current_state
== WithdrawnState
) {
2350 // the window is on this workspace and is Withdrawn, so it is waiting to
2352 current_state
= NormalState
;
2355 if (net
->flags
& AttribOmnipresent
&& net
->attrib
& AttribOmnipresent
&&
2359 // if the window was on another workspace, it was going to be hidden. this
2360 // specifies that the window should be mapped since it is sticky.
2361 if (current_state
== WithdrawnState
) current_state
= NormalState
;
2364 if (net
->flags
& AttribMaxHoriz
|| net
->flags
& AttribMaxVert
) {
2365 int x
= net
->premax_x
, y
= net
->premax_y
;
2366 unsigned int w
= net
->premax_w
, h
= net
->premax_h
;
2367 flags
.maximized
= 0;
2370 if ((net
->flags
& AttribMaxHoriz
) &&
2371 (net
->flags
& AttribMaxVert
))
2372 m
= (net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
2373 else if (net
->flags
& AttribMaxVert
)
2374 m
= (net
->attrib
& AttribMaxVert
) ? 2 : 0;
2375 else if (net
->flags
& AttribMaxHoriz
)
2376 m
= (net
->attrib
& AttribMaxHoriz
) ? 3 : 0;
2380 blackbox_attrib
.premax_x
= x
;
2381 blackbox_attrib
.premax_y
= y
;
2382 blackbox_attrib
.premax_w
= w
;
2383 blackbox_attrib
.premax_h
= h
;
2386 if (net
->flags
& AttribDecoration
) {
2387 switch (net
->decoration
) {
2392 /* since tools only let you toggle this anyways, we'll just make that all
2393 it supports for now.
2404 // with the state set it will then be the map event's job to read the
2405 // window's state and behave accordingly
2412 * Positions the Rect r according the the client window position and
2415 void BlackboxWindow::applyGravity(otk::Rect
&r
) {
2416 // apply horizontal window gravity
2417 switch (client
.win_gravity
) {
2419 case NorthWestGravity
:
2420 case SouthWestGravity
:
2422 r
.setX(client
.rect
.x());
2428 r
.setX(client
.rect
.x() - (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2431 case NorthEastGravity
:
2432 case SouthEastGravity
:
2434 r
.setX(client
.rect
.x() - frame
.margin
.left
- frame
.margin
.right
+ 2);
2439 r
.setX(client
.rect
.x() - frame
.margin
.left
);
2443 // apply vertical window gravity
2444 switch (client
.win_gravity
) {
2446 case NorthWestGravity
:
2447 case NorthEastGravity
:
2449 r
.setY(client
.rect
.y());
2455 r
.setY(client
.rect
.y() - (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2458 case SouthWestGravity
:
2459 case SouthEastGravity
:
2461 r
.setY(client
.rect
.y() - frame
.margin
.top
- frame
.margin
.bottom
+ 2);
2466 r
.setY(client
.rect
.y() - frame
.margin
.top
);
2473 * The reverse of the applyGravity function.
2475 * Positions the Rect r according to the frame window position and
2478 void BlackboxWindow::restoreGravity(otk::Rect
&r
) {
2479 // restore horizontal window gravity
2480 switch (client
.win_gravity
) {
2482 case NorthWestGravity
:
2483 case SouthWestGravity
:
2485 r
.setX(frame
.rect
.x());
2491 r
.setX(frame
.rect
.x() + (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2494 case NorthEastGravity
:
2495 case SouthEastGravity
:
2497 r
.setX(frame
.rect
.x() + frame
.margin
.left
+ frame
.margin
.right
- 2);
2502 r
.setX(frame
.rect
.x() + frame
.margin
.left
);
2506 // restore vertical window gravity
2507 switch (client
.win_gravity
) {
2509 case NorthWestGravity
:
2510 case NorthEastGravity
:
2512 r
.setY(frame
.rect
.y());
2518 r
.setY(frame
.rect
.y() + (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2521 case SouthWestGravity
:
2522 case SouthEastGravity
:
2524 r
.setY(frame
.rect
.y() + frame
.margin
.top
+ frame
.margin
.bottom
- 2);
2529 r
.setY(frame
.rect
.y() + frame
.margin
.top
);
2535 void BlackboxWindow::redrawLabel(void) const {
2536 if (flags
.focused
) {
2538 XSetWindowBackgroundPixmap(otk::OBDisplay::display
,
2539 frame
.label
, frame
.flabel
);
2541 XSetWindowBackground(otk::OBDisplay::display
,
2542 frame
.label
, frame
.flabel_pixel
);
2545 XSetWindowBackgroundPixmap(otk::OBDisplay::display
,
2546 frame
.label
, frame
.ulabel
);
2548 XSetWindowBackground(otk::OBDisplay::display
,
2549 frame
.label
, frame
.ulabel_pixel
);
2551 XClearWindow(otk::OBDisplay::display
, frame
.label
);
2553 WindowStyle
*style
= screen
->getWindowStyle();
2555 int pos
= frame
.bevel_w
* 2;
2556 style
->doJustify(client
.title
.c_str(), pos
, frame
.label_w
, frame
.bevel_w
* 4);
2557 style
->font
->drawString(frame
.label
, pos
, 1,
2558 (flags
.focused
? style
->l_text_focus
:
2559 style
->l_text_unfocus
),
2564 void BlackboxWindow::redrawAllButtons(void) const {
2565 if (frame
.iconify_button
) redrawIconifyButton(False
);
2566 if (frame
.maximize_button
) redrawMaximizeButton(flags
.maximized
);
2567 if (frame
.close_button
) redrawCloseButton(False
);
2568 if (frame
.stick_button
) redrawStickyButton(flags
.stuck
);
2572 void BlackboxWindow::redrawButton(bool pressed
, Window win
,
2573 Pixmap fppix
, unsigned long fppixel
,
2574 Pixmap uppix
, unsigned long uppixel
,
2575 Pixmap fpix
, unsigned long fpixel
,
2576 Pixmap upix
, unsigned long upixel
) const {
2581 if (flags
.focused
) {
2589 if (flags
.focused
) {
2599 XSetWindowBackgroundPixmap(otk::OBDisplay::display
, win
, p
);
2601 XSetWindowBackground(otk::OBDisplay::display
, win
, pix
);
2605 void BlackboxWindow::redrawIconifyButton(bool pressed
) const {
2606 redrawButton(pressed
, frame
.iconify_button
,
2607 frame
.pfbutton
, frame
.pfbutton_pixel
,
2608 frame
.pubutton
, frame
.pubutton_pixel
,
2609 frame
.fbutton
, frame
.fbutton_pixel
,
2610 frame
.ubutton
, frame
.ubutton_pixel
);
2612 XClearWindow(otk::OBDisplay::display
, frame
.iconify_button
);
2613 otk::BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2614 screen
->getWindowStyle()->b_pic_unfocus
);
2616 PixmapMask pm
= screen
->getWindowStyle()->icon_button
;
2618 if (screen
->getWindowStyle()->icon_button
.mask
!= None
) {
2619 XSetClipMask(otk::OBDisplay::display
, pen
.gc(), pm
.mask
);
2620 XSetClipOrigin(otk::OBDisplay::display
, pen
.gc(),
2621 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2);
2623 XFillRectangle(otk::OBDisplay::display
, frame
.iconify_button
, pen
.gc(),
2624 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2,
2625 (frame
.button_w
+ pm
.w
)/2, (frame
.button_w
+ pm
.h
)/2);
2627 XSetClipMask(otk::OBDisplay::display
, pen
.gc(), None
);
2628 XSetClipOrigin(otk::OBDisplay::display
, pen
.gc(), 0, 0);
2630 XDrawRectangle(otk::OBDisplay::display
, frame
.iconify_button
, pen
.gc(),
2631 2, (frame
.button_w
- 5), (frame
.button_w
- 5), 2);
2636 void BlackboxWindow::redrawMaximizeButton(bool pressed
) const {
2637 redrawButton(pressed
, frame
.maximize_button
,
2638 frame
.pfbutton
, frame
.pfbutton_pixel
,
2639 frame
.pubutton
, frame
.pubutton_pixel
,
2640 frame
.fbutton
, frame
.fbutton_pixel
,
2641 frame
.ubutton
, frame
.ubutton_pixel
);
2643 XClearWindow(otk::OBDisplay::display
, frame
.maximize_button
);
2645 otk::BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2646 screen
->getWindowStyle()->b_pic_unfocus
);
2648 PixmapMask pm
= screen
->getWindowStyle()->max_button
;
2650 if (pm
.mask
!= None
) {
2651 XSetClipMask(otk::OBDisplay::display
, pen
.gc(), pm
.mask
);
2652 XSetClipOrigin(otk::OBDisplay::display
, pen
.gc(),
2653 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2);
2655 XFillRectangle(otk::OBDisplay::display
, frame
.maximize_button
, pen
.gc(),
2656 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2,
2657 (frame
.button_w
+ pm
.w
)/2, (frame
.button_w
+ pm
.h
)/2);
2659 XSetClipOrigin(otk::OBDisplay::display
, pen
.gc(), 0, 0 );
2660 XSetClipMask( otk::OBDisplay::display
, pen
.gc(), None
);
2662 XDrawRectangle(otk::OBDisplay::display
, frame
.maximize_button
, pen
.gc(),
2663 2, 2, (frame
.button_w
- 5), (frame
.button_w
- 5));
2664 XDrawLine(otk::OBDisplay::display
, frame
.maximize_button
, pen
.gc(),
2665 2, 3, (frame
.button_w
- 3), 3);
2670 void BlackboxWindow::redrawCloseButton(bool pressed
) const {
2671 redrawButton(pressed
, frame
.close_button
,
2672 frame
.pfbutton
, frame
.pfbutton_pixel
,
2673 frame
.pubutton
, frame
.pubutton_pixel
,
2674 frame
.fbutton
, frame
.fbutton_pixel
,
2675 frame
.ubutton
, frame
.ubutton_pixel
);
2677 XClearWindow(otk::OBDisplay::display
, frame
.close_button
);
2679 otk::BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2680 screen
->getWindowStyle()->b_pic_unfocus
);
2682 PixmapMask pm
= screen
->getWindowStyle()->close_button
;
2684 if (pm
.mask
!= None
) {
2685 XSetClipMask(otk::OBDisplay::display
, pen
.gc(), pm
.mask
);
2686 XSetClipOrigin(otk::OBDisplay::display
, pen
.gc(),
2687 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2);
2689 XFillRectangle(otk::OBDisplay::display
, frame
.close_button
, pen
.gc(),
2690 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2,
2691 (frame
.button_w
+ pm
.w
)/2, (frame
.button_w
+ pm
.h
)/2);
2694 XSetClipOrigin(otk::OBDisplay::display
, pen
.gc(), 0, 0 );
2695 XSetClipMask( otk::OBDisplay::display
, pen
.gc(), None
);
2697 XDrawLine(otk::OBDisplay::display
, frame
.close_button
, pen
.gc(),
2698 2, 2, (frame
.button_w
- 3), (frame
.button_w
- 3));
2699 XDrawLine(otk::OBDisplay::display
, frame
.close_button
, pen
.gc(),
2700 2, (frame
.button_w
- 3), (frame
.button_w
- 3), 2);
2704 void BlackboxWindow::redrawStickyButton(bool pressed
) const {
2705 redrawButton(pressed
, frame
.stick_button
,
2706 frame
.pfbutton
, frame
.pfbutton_pixel
,
2707 frame
.pubutton
, frame
.pubutton_pixel
,
2708 frame
.fbutton
, frame
.fbutton_pixel
,
2709 frame
.ubutton
, frame
.ubutton_pixel
);
2711 XClearWindow(otk::OBDisplay::display
, frame
.stick_button
);
2713 otk::BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2714 screen
->getWindowStyle()->b_pic_unfocus
);
2716 PixmapMask pm
= screen
->getWindowStyle()->stick_button
;
2718 if (pm
.mask
!= None
) {
2719 XSetClipMask(otk::OBDisplay::display
, pen
.gc(), pm
.mask
);
2720 XSetClipOrigin(otk::OBDisplay::display
, pen
.gc(),
2721 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2);
2723 XFillRectangle(otk::OBDisplay::display
, frame
.stick_button
, pen
.gc(),
2724 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2,
2725 (frame
.button_w
+ pm
.w
)/2, (frame
.button_w
+ pm
.h
)/2);
2728 XSetClipOrigin(otk::OBDisplay::display
, pen
.gc(), 0, 0 );
2729 XSetClipMask( otk::OBDisplay::display
, pen
.gc(), None
);
2731 XFillRectangle(otk::OBDisplay::display
, frame
.stick_button
, pen
.gc(),
2732 frame
.button_w
/2 - 1, frame
.button_w
/2 -1, 2, 2 );
2736 void BlackboxWindow::mapRequestEvent(const XMapRequestEvent
*re
) {
2737 if (re
->window
!= client
.window
)
2741 fprintf(stderr
, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2746 Even though the window wants to be shown, if it is not on the current
2747 workspace, then it isn't going to be shown right now.
2749 if (! flags
.stuck
&&
2750 blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID() &&
2751 blackbox_attrib
.workspace
< screen
->getWorkspaceCount())
2752 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2754 switch (current_state
) {
2759 case WithdrawnState
:
2768 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2770 if (blackbox
->state() != Openbox::State_Starting
) {
2771 XSync(otk::OBDisplay::display
, False
); // make sure the frame is mapped
2772 if (screen
->doFocusNew() || (isTransient() && getTransientFor() &&
2773 getTransientFor()->isFocused())) {
2776 if (screen
->getPlacementPolicy() == BScreen::ClickMousePlacement
) {
2780 XQueryPointer(otk::OBDisplay::display
, screen
->getRootWindow(),
2781 &r
, &c
, &rx
, &ry
, &x
, &y
, &m
);
2791 void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent
*ue
) {
2792 if (ue
->window
!= client
.window
)
2796 fprintf(stderr
, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2800 screen
->unmanageWindow(this, False
);
2804 void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent
*de
) {
2805 if (de
->window
!= client
.window
)
2809 fprintf(stderr
, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2813 screen
->unmanageWindow(this, False
);
2817 void BlackboxWindow::reparentNotifyEvent(const XReparentEvent
*re
) {
2818 if (re
->window
!= client
.window
|| re
->parent
== frame
.plate
)
2822 fprintf(stderr
, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2823 "0x%lx.\n", client
.window
, re
->parent
);
2828 XPutBackEvent(otk::OBDisplay::display
, &ev
);
2829 screen
->unmanageWindow(this, True
);
2833 void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent
*pe
) {
2834 if (pe
->state
== PropertyDelete
|| ! validateClient())
2838 fprintf(stderr
, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n",
2844 case XA_WM_CLIENT_MACHINE
:
2848 case XA_WM_TRANSIENT_FOR
: {
2849 bool s
= flags
.stuck
;
2851 // determine if this is a transient window
2854 if (flags
.stuck
!= s
) stick();
2856 // adjust the window decorations based on transience
2857 if (isTransient()) {
2858 functions
&= ~Func_Maximize
;
2859 setAllowedActions();
2871 case XA_WM_ICON_NAME
:
2873 if (flags
.iconic
) screen
->propagateWindowName(this);
2876 case XAtom::net_wm_name
:
2880 if (decorations
& Decor_Titlebar
)
2883 screen
->propagateWindowName(this);
2886 case XA_WM_NORMAL_HINTS
: {
2889 if ((client
.normal_hint_flags
& PMinSize
) &&
2890 (client
.normal_hint_flags
& PMaxSize
)) {
2891 // the window now can/can't resize itself, so the buttons need to be
2894 if (client
.max_width
<= client
.min_width
&&
2895 client
.max_height
<= client
.min_height
) {
2896 functions
&= ~(Func_Resize
| Func_Maximize
);
2898 if (! isTransient())
2899 functions
|= Func_Maximize
;
2900 functions
|= Func_Resize
;
2903 setAllowedActions();
2907 otk::Rect old_rect
= frame
.rect
;
2911 if (old_rect
!= frame
.rect
)
2918 if (pe
->atom
== xatom
->getAtom(XAtom::wm_protocols
)) {
2921 if ((decorations
& Decor_Close
) && (! frame
.close_button
)) {
2922 createCloseButton();
2923 if (decorations
& Decor_Titlebar
) {
2924 positionButtons(True
);
2925 XMapSubwindows(otk::OBDisplay::display
, frame
.title
);
2928 } else if (pe
->atom
== xatom
->getAtom(XAtom::net_wm_strut
)) {
2937 void BlackboxWindow::exposeEvent(const XExposeEvent
*ee
) {
2939 fprintf(stderr
, "BlackboxWindow::exposeEvent() for 0x%lx\n", client
.window
);
2942 if (frame
.label
== ee
->window
&& (decorations
& Decor_Titlebar
))
2944 else if (frame
.close_button
== ee
->window
)
2945 redrawCloseButton(False
);
2946 else if (frame
.maximize_button
== ee
->window
)
2947 redrawMaximizeButton(flags
.maximized
);
2948 else if (frame
.iconify_button
== ee
->window
)
2949 redrawIconifyButton(False
);
2950 else if (frame
.stick_button
== ee
->window
)
2951 redrawStickyButton(flags
.stuck
);
2955 void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent
*cr
) {
2956 if (cr
->window
!= client
.window
|| flags
.iconic
)
2959 if (cr
->value_mask
& CWBorderWidth
)
2960 client
.old_bw
= cr
->border_width
;
2962 if (cr
->value_mask
& (CWX
| CWY
| CWWidth
| CWHeight
)) {
2963 frame
.changing
= frame
.rect
;
2965 if (cr
->value_mask
& (CWX
| CWY
)) {
2966 if (cr
->value_mask
& CWX
)
2967 client
.rect
.setX(cr
->x
);
2968 if (cr
->value_mask
& CWY
)
2969 client
.rect
.setY(cr
->y
);
2971 applyGravity(frame
.changing
);
2974 if (cr
->value_mask
& (CWWidth
| CWHeight
)) {
2975 if (cr
->value_mask
& CWWidth
)
2976 frame
.changing
.setWidth(cr
->width
+
2977 frame
.margin
.left
+ frame
.margin
.right
);
2979 if (cr
->value_mask
& CWHeight
)
2980 frame
.changing
.setHeight(cr
->height
+
2981 frame
.margin
.top
+ frame
.margin
.bottom
);
2984 if a position change has been specified, then that position will be
2985 used instead of determining a position based on the window's gravity.
2987 if (! (cr
->value_mask
& (CWX
| CWY
))) {
2989 switch (client
.win_gravity
) {
2990 case NorthEastGravity
:
2994 case SouthWestGravity
:
2996 corner
= BottomLeft
;
2998 case SouthEastGravity
:
2999 corner
= BottomRight
;
3001 default: // NorthWest, Static, etc
3008 configure(frame
.changing
.x(), frame
.changing
.y(),
3009 frame
.changing
.width(), frame
.changing
.height());
3012 if (cr
->value_mask
& CWStackMode
&& !isDesktop()) {
3013 switch (cr
->detail
) {
3016 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
3022 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3029 void BlackboxWindow::buttonPressEvent(const XButtonEvent
*be
) {
3031 fprintf(stderr
, "BlackboxWindow::buttonPressEvent() for 0x%lx\n",
3035 if (frame
.maximize_button
== be
->window
&& be
->button
<= 3) {
3036 redrawMaximizeButton(True
);
3037 } else if (be
->button
== 1 || (be
->button
== 3 && be
->state
== mod_mask
)) {
3038 if (! flags
.focused
)
3041 if (frame
.iconify_button
== be
->window
) {
3042 redrawIconifyButton(True
);
3043 } else if (frame
.close_button
== be
->window
) {
3044 redrawCloseButton(True
);
3045 } else if (frame
.stick_button
== be
->window
) {
3046 redrawStickyButton(True
);
3047 } else if (frame
.plate
== be
->window
) {
3048 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3050 XAllowEvents(otk::OBDisplay::display
, ReplayPointer
, be
->time
);
3052 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
3053 if (((be
->time
- lastButtonPressTime
) <=
3054 blackbox
->getDoubleClickInterval()) ||
3055 (be
->state
== ControlMask
)) {
3056 lastButtonPressTime
= 0;
3059 lastButtonPressTime
= be
->time
;
3063 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3065 } else if (be
->button
== 2 && (be
->window
!= frame
.iconify_button
) &&
3066 (be
->window
!= frame
.close_button
) &&
3067 (be
->window
!= frame
.stick_button
)) {
3068 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
3070 } else if (be
->button
== 4) {
3071 if ((be
->window
== frame
.label
||
3072 be
->window
== frame
.title
||
3073 be
->window
== frame
.maximize_button
||
3074 be
->window
== frame
.iconify_button
||
3075 be
->window
== frame
.close_button
||
3076 be
->window
== frame
.stick_button
) &&
3080 } else if (be
->button
== 5) {
3081 if ((be
->window
== frame
.label
||
3082 be
->window
== frame
.title
||
3083 be
->window
== frame
.maximize_button
||
3084 be
->window
== frame
.iconify_button
||
3085 be
->window
== frame
.close_button
||
3086 be
->window
== frame
.stick_button
) &&
3093 void BlackboxWindow::buttonReleaseEvent(const XButtonEvent
*re
) {
3095 fprintf(stderr
, "BlackboxWindow::buttonReleaseEvent() for 0x%lx\n",
3099 if (re
->window
== frame
.maximize_button
&&
3100 re
->button
>= 1 && re
->button
<= 3) {
3101 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3102 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
3103 maximize(re
->button
);
3105 redrawMaximizeButton(flags
.maximized
);
3107 } else if (re
->window
== frame
.iconify_button
&& re
->button
== 1) {
3108 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3109 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
3112 redrawIconifyButton(False
);
3114 } else if (re
->window
== frame
.stick_button
&& re
->button
== 1) {
3115 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3116 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
3119 redrawStickyButton(False
);
3121 } else if (re
->window
== frame
.close_button
& re
->button
== 1) {
3122 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3123 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
)))
3125 redrawCloseButton(False
);
3126 } else if (flags
.moving
) {
3128 } else if (flags
.resizing
) {
3130 } else if (re
->window
== frame
.window
) {
3131 if (re
->button
== 2 && re
->state
== mod_mask
)
3132 XUngrabPointer(otk::OBDisplay::display
, CurrentTime
);
3138 void BlackboxWindow::beginMove(int x_root
, int y_root
) {
3139 if (! (functions
& Func_Move
)) return;
3141 assert(! (flags
.resizing
|| flags
.moving
));
3144 Only one window can be moved/resized at a time. If another window is already
3145 being moved or resized, then stop it before whating to work with this one.
3147 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3148 if (changing
&& changing
!= this) {
3149 if (changing
->flags
.moving
)
3150 changing
->endMove();
3151 else // if (changing->flags.resizing)
3152 changing
->endResize();
3155 XGrabPointer(otk::OBDisplay::display
, frame
.window
, False
,
3156 PointerMotionMask
| ButtonReleaseMask
,
3157 GrabModeAsync
, GrabModeAsync
,
3158 None
, blackbox
->getMoveCursor(), CurrentTime
);
3160 flags
.moving
= True
;
3161 blackbox
->setChangingWindow(this);
3163 if (! screen
->doOpaqueMove()) {
3164 XGrabServer(otk::OBDisplay::display
);
3166 frame
.changing
= frame
.rect
;
3167 screen
->showPosition(frame
.changing
.x(), frame
.changing
.y());
3169 XDrawRectangle(otk::OBDisplay::display
, screen
->getRootWindow(),
3173 frame
.changing
.width() - 1,
3174 frame
.changing
.height() - 1);
3177 frame
.grab_x
= x_root
- frame
.rect
.x() - frame
.border_w
;
3178 frame
.grab_y
= y_root
- frame
.rect
.y() - frame
.border_w
;
3182 void BlackboxWindow::doMove(int x_root
, int y_root
) {
3183 assert(flags
.moving
);
3184 assert(blackbox
->getChangingWindow() == this);
3186 int dx
= x_root
- frame
.grab_x
, dy
= y_root
- frame
.grab_y
;
3187 dx
-= frame
.border_w
;
3188 dy
-= frame
.border_w
;
3190 doWindowSnapping(dx
, dy
);
3192 if (screen
->doOpaqueMove()) {
3193 if (screen
->doWorkspaceWarping())
3194 doWorkspaceWarping(x_root
, y_root
, dx
);
3196 configure(dx
, dy
, frame
.rect
.width(), frame
.rect
.height());
3198 XDrawRectangle(otk::OBDisplay::display
, screen
->getRootWindow(),
3202 frame
.changing
.width() - 1,
3203 frame
.changing
.height() - 1);
3205 if (screen
->doWorkspaceWarping())
3206 doWorkspaceWarping(x_root
, y_root
, dx
);
3208 frame
.changing
.setPos(dx
, dy
);
3210 XDrawRectangle(otk::OBDisplay::display
, screen
->getRootWindow(),
3214 frame
.changing
.width() - 1,
3215 frame
.changing
.height() - 1);
3218 screen
->showPosition(dx
, dy
);
3222 void BlackboxWindow::doWorkspaceWarping(int x_root
, int y_root
, int &dx
) {
3223 // workspace warping
3225 unsigned int dest
= screen
->getCurrentWorkspaceID();
3229 if (dest
> 0) dest
--;
3230 else dest
= screen
->getNumberOfWorkspaces() - 1;
3232 } else if (x_root
>= screen
->getRect().right()) {
3235 if (dest
< screen
->getNumberOfWorkspaces() - 1) dest
++;
3241 bool focus
= flags
.focused
; // had focus while moving?
3243 int dest_x
= x_root
;
3245 dest_x
+= screen
->getRect().width() - 1;
3246 dx
+= screen
->getRect().width() - 1;
3248 dest_x
-= screen
->getRect().width() - 1;
3249 dx
-= screen
->getRect().width() - 1;
3253 screen
->reassociateWindow(this, dest
, False
);
3254 screen
->changeWorkspaceID(dest
);
3256 if (screen
->doOpaqueMove())
3257 XGrabServer(otk::OBDisplay::display
);
3259 XUngrabPointer(otk::OBDisplay::display
, CurrentTime
);
3260 XWarpPointer(otk::OBDisplay::display
, None
,
3261 screen
->getRootWindow(), 0, 0, 0, 0,
3263 XGrabPointer(otk::OBDisplay::display
, frame
.window
, False
,
3264 PointerMotionMask
| ButtonReleaseMask
,
3265 GrabModeAsync
, GrabModeAsync
,
3266 None
, blackbox
->getMoveCursor(), CurrentTime
);
3268 if (screen
->doOpaqueMove())
3269 XUngrabServer(otk::OBDisplay::display
);
3277 void BlackboxWindow::doWindowSnapping(int &dx
, int &dy
) {
3278 // how much resistance to edges to provide
3279 const int resistance_size
= screen
->getResistanceSize();
3281 // how far away to snap
3282 const int snap_distance
= screen
->getSnapThreshold();
3284 // how to snap windows
3285 const int snap_to_windows
= screen
->getWindowToWindowSnap();
3286 const int snap_to_edges
= screen
->getWindowToEdgeSnap();
3287 // the amount of space away from the edge to provide resistance/snap
3288 const int snap_offset
= screen
->getSnapOffset();
3290 // find the geomeetery where the moving window currently is
3291 const otk::Rect
&moving
=
3292 screen
->doOpaqueMove() ? frame
.rect
: frame
.changing
;
3295 const int wleft
= dx
,
3296 wright
= dx
+ frame
.rect
.width() - 1,
3298 wbottom
= dy
+ frame
.rect
.height() - 1;
3300 if (snap_to_windows
) {
3301 otk::RectList rectlist
;
3303 Workspace
*w
= screen
->getWorkspace(getWorkspaceNumber());
3306 // add windows on the workspace to the rect list
3307 const BlackboxWindowList
& stack_list
= w
->getStackingList();
3308 BlackboxWindowList::const_iterator st_it
, st_end
= stack_list
.end();
3309 for (st_it
= stack_list
.begin(); st_it
!= st_end
; ++st_it
)
3310 if (*st_it
!= this) // don't snap to ourself
3311 rectlist
.push_back( (*st_it
)->frameRect() );
3313 otk::RectList::const_iterator it
, end
= rectlist
.end();
3314 for (it
= rectlist
.begin(); it
!= end
; ++it
) {
3315 bool snapped
= False
;
3316 const otk::Rect
&winrect
= *it
;
3317 otk::Rect offsetrect
;
3318 offsetrect
.setCoords(winrect
.left() - snap_offset
,
3319 winrect
.top() - snap_offset
,
3320 winrect
.right() + snap_offset
,
3321 winrect
.bottom() + snap_offset
);
3323 if (snap_to_windows
== BScreen::WindowResistance
)
3324 // if the window is already over top of this snap target, then
3325 // resistance is futile, so just ignore it
3326 if (winrect
.intersects(moving
))
3329 int dleft
, dright
, dtop
, dbottom
;
3331 // if the windows are in the same plane vertically
3332 if (wtop
>= (signed)(winrect
.y() - frame
.rect
.height() + 1) &&
3333 wtop
< (signed)(winrect
.y() + winrect
.height() - 1)) {
3335 if (snap_to_windows
== BScreen::WindowResistance
) {
3336 dleft
= wright
- offsetrect
.left();
3337 dright
= offsetrect
.right() - wleft
;
3339 // snap left of other window?
3340 if (dleft
>= 0 && dleft
< resistance_size
&&
3341 dleft
< (wright
- wleft
)) {
3342 dx
= offsetrect
.left() - frame
.rect
.width();
3345 // snap right of other window?
3346 else if (dright
>= 0 && dright
< resistance_size
&&
3347 dright
< (wright
- wleft
)) {
3348 dx
= offsetrect
.right() + 1;
3351 } else { // BScreen::WindowSnap
3352 dleft
= abs(wright
- offsetrect
.left());
3353 dright
= abs(wleft
- offsetrect
.right());
3355 // snap left of other window?
3356 if (dleft
< snap_distance
&& dleft
<= dright
) {
3357 dx
= offsetrect
.left() - frame
.rect
.width();
3360 // snap right of other window?
3361 else if (dright
< snap_distance
) {
3362 dx
= offsetrect
.right() + 1;
3368 if (screen
->getWindowCornerSnap()) {
3369 // try corner-snap to its other sides
3370 if (snap_to_windows
== BScreen::WindowResistance
) {
3371 dtop
= winrect
.top() - wtop
;
3372 dbottom
= wbottom
- winrect
.bottom();
3373 if (dtop
> 0 && dtop
< resistance_size
) {
3374 // if we're already past the top edge, then don't provide
3376 if (moving
.top() >= winrect
.top())
3378 } else if (dbottom
> 0 && dbottom
< resistance_size
) {
3379 // if we're already past the bottom edge, then don't provide
3381 if (moving
.bottom() <= winrect
.bottom())
3382 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
3384 } else { // BScreen::WindowSnap
3385 dtop
= abs(wtop
- winrect
.top());
3386 dbottom
= abs(wbottom
- winrect
.bottom());
3387 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3389 else if (dbottom
< snap_distance
)
3390 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
3398 // if the windows are on the same plane horizontally
3399 if (wleft
>= (signed)(winrect
.x() - frame
.rect
.width() + 1) &&
3400 wleft
< (signed)(winrect
.x() + winrect
.width() - 1)) {
3402 if (snap_to_windows
== BScreen::WindowResistance
) {
3403 dtop
= wbottom
- offsetrect
.top();
3404 dbottom
= offsetrect
.bottom() - wtop
;
3406 // snap top of other window?
3407 if (dtop
>= 0 && dtop
< resistance_size
&& dtop
< (wbottom
- wtop
)) {
3408 dy
= offsetrect
.top() - frame
.rect
.height();
3411 // snap bottom of other window?
3412 else if (dbottom
>= 0 && dbottom
< resistance_size
&&
3413 dbottom
< (wbottom
- wtop
)) {
3414 dy
= offsetrect
.bottom() + 1;
3417 } else { // BScreen::WindowSnap
3418 dtop
= abs(wbottom
- offsetrect
.top());
3419 dbottom
= abs(wtop
- offsetrect
.bottom());
3421 // snap top of other window?
3422 if (dtop
< snap_distance
&& dtop
<= dbottom
) {
3423 dy
= offsetrect
.top() - frame
.rect
.height();
3426 // snap bottom of other window?
3427 else if (dbottom
< snap_distance
) {
3428 dy
= offsetrect
.bottom() + 1;
3435 if (screen
->getWindowCornerSnap()) {
3436 // try corner-snap to its other sides
3437 if (snap_to_windows
== BScreen::WindowResistance
) {
3438 dleft
= winrect
.left() - wleft
;
3439 dright
= wright
- winrect
.right();
3440 if (dleft
> 0 && dleft
< resistance_size
) {
3441 // if we're already past the left edge, then don't provide
3443 if (moving
.left() >= winrect
.left())
3444 dx
= winrect
.left();
3445 } else if (dright
> 0 && dright
< resistance_size
) {
3446 // if we're already past the right edge, then don't provide
3448 if (moving
.right() <= winrect
.right())
3449 dx
= winrect
.right() - frame
.rect
.width() + 1;
3451 } else { // BScreen::WindowSnap
3452 dleft
= abs(wleft
- winrect
.left());
3453 dright
= abs(wright
- winrect
.right());
3454 if (dleft
< snap_distance
&& dleft
<= dright
)
3455 dx
= winrect
.left();
3456 else if (dright
< snap_distance
)
3457 dx
= winrect
.right() - frame
.rect
.width() + 1;
3467 if (snap_to_edges
) {
3468 otk::RectList rectlist
;
3470 // snap to the screen edges (and screen boundaries for xinerama)
3472 if (screen
->isXineramaActive() && blackbox
->doXineramaSnapping()) {
3473 rectlist
.insert(rectlist
.begin(),
3474 screen
->getXineramaAreas().begin(),
3475 screen
->getXineramaAreas().end());
3478 rectlist
.push_back(screen
->getRect());
3480 otk::RectList::const_iterator it
, end
= rectlist
.end();
3481 for (it
= rectlist
.begin(); it
!= end
; ++it
) {
3482 const otk::Rect
&srect
= *it
;
3483 otk::Rect offsetrect
;
3484 offsetrect
.setCoords(srect
.left() + snap_offset
,
3485 srect
.top() + snap_offset
,
3486 srect
.right() - snap_offset
,
3487 srect
.bottom() - snap_offset
);
3489 if (snap_to_edges
== BScreen::WindowResistance
) {
3490 // if we're not in the rectangle then don't snap to it.
3491 if (! srect
.contains(moving
))
3493 } else { // BScreen::WindowSnap
3494 // if we're not in the rectangle then don't snap to it.
3495 if (! srect
.intersects(otk::Rect(wleft
, wtop
, frame
.rect
.width(),
3496 frame
.rect
.height())))
3500 if (snap_to_edges
== BScreen::WindowResistance
) {
3501 int dleft
= offsetrect
.left() - wleft
,
3502 dright
= wright
- offsetrect
.right(),
3503 dtop
= offsetrect
.top() - wtop
,
3504 dbottom
= wbottom
- offsetrect
.bottom();
3507 if (dleft
> 0 && dleft
< resistance_size
)
3508 dx
= offsetrect
.left();
3510 else if (dright
> 0 && dright
< resistance_size
)
3511 dx
= offsetrect
.right() - frame
.rect
.width() + 1;
3514 if (dtop
> 0 && dtop
< resistance_size
)
3515 dy
= offsetrect
.top();
3517 else if (dbottom
> 0 && dbottom
< resistance_size
)
3518 dy
= offsetrect
.bottom() - frame
.rect
.height() + 1;
3519 } else { // BScreen::WindowSnap
3520 int dleft
= abs(wleft
- offsetrect
.left()),
3521 dright
= abs(wright
- offsetrect
.right()),
3522 dtop
= abs(wtop
- offsetrect
.top()),
3523 dbottom
= abs(wbottom
- offsetrect
.bottom());
3526 if (dleft
< snap_distance
&& dleft
<= dright
)
3527 dx
= offsetrect
.left();
3529 else if (dright
< snap_distance
)
3530 dx
= offsetrect
.right() - frame
.rect
.width() + 1;
3533 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3534 dy
= offsetrect
.top();
3536 else if (dbottom
< snap_distance
)
3537 dy
= offsetrect
.bottom() - frame
.rect
.height() + 1;
3544 void BlackboxWindow::endMove(void) {
3545 assert(flags
.moving
);
3546 assert(blackbox
->getChangingWindow() == this);
3548 flags
.moving
= False
;
3549 blackbox
->setChangingWindow(0);
3551 if (! screen
->doOpaqueMove()) {
3552 /* when drawing the rubber band, we need to make sure we only draw inside
3553 * the frame... frame.changing_* contain the new coords for the window,
3554 * so we need to subtract 1 from changing_w/changing_h every where we
3555 * draw the rubber band (for both moving and resizing)
3557 XDrawRectangle(otk::OBDisplay::display
, screen
->getRootWindow(),
3558 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3559 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3560 XUngrabServer(otk::OBDisplay::display
);
3562 configure(frame
.changing
.x(), frame
.changing
.y(),
3563 frame
.changing
.width(), frame
.changing
.height());
3565 configure(frame
.rect
.x(), frame
.rect
.y(),
3566 frame
.rect
.width(), frame
.rect
.height());
3568 screen
->hideGeometry();
3570 XUngrabPointer(otk::OBDisplay::display
, CurrentTime
);
3572 // if there are any left over motions from the move, drop them now
3573 XSync(otk::OBDisplay::display
, false); // make sure we don't miss any
3575 while (XCheckTypedWindowEvent(otk::OBDisplay::display
, frame
.window
,
3580 void BlackboxWindow::beginResize(int x_root
, int y_root
, Corner dir
) {
3581 if (! (functions
& Func_Resize
)) return;
3583 assert(! (flags
.resizing
|| flags
.moving
));
3586 Only one window can be moved/resized at a time. If another window is
3587 already being moved or resized, then stop it before whating to work with
3590 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3591 if (changing
&& changing
!= this) {
3592 if (changing
->flags
.moving
)
3593 changing
->endMove();
3594 else // if (changing->flags.resizing)
3595 changing
->endResize();
3603 switch (resize_dir
) {
3606 cursor
= blackbox
->getLowerLeftAngleCursor();
3611 cursor
= blackbox
->getLowerRightAngleCursor();
3615 anchor
= BottomRight
;
3616 cursor
= blackbox
->getUpperLeftAngleCursor();
3620 anchor
= BottomLeft
;
3621 cursor
= blackbox
->getUpperRightAngleCursor();
3625 assert(false); // unhandled Corner
3626 return; // unreachable, for the compiler
3629 XGrabServer(otk::OBDisplay::display
);
3630 XGrabPointer(otk::OBDisplay::display
, frame
.window
, False
,
3631 PointerMotionMask
| ButtonReleaseMask
,
3632 GrabModeAsync
, GrabModeAsync
, None
, cursor
, CurrentTime
);
3634 flags
.resizing
= True
;
3635 blackbox
->setChangingWindow(this);
3637 unsigned int gw
, gh
;
3638 frame
.changing
= frame
.rect
;
3640 constrain(anchor
, &gw
, &gh
);
3642 XDrawRectangle(otk::OBDisplay::display
, screen
->getRootWindow(),
3643 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3644 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3646 screen
->showGeometry(gw
, gh
);
3648 frame
.grab_x
= x_root
;
3649 frame
.grab_y
= y_root
;
3653 void BlackboxWindow::doResize(int x_root
, int y_root
) {
3654 assert(flags
.resizing
);
3655 assert(blackbox
->getChangingWindow() == this);
3657 XDrawRectangle(otk::OBDisplay::display
, screen
->getRootWindow(),
3658 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3659 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3661 unsigned int gw
, gh
;
3663 int dx
, dy
; // the amount of change in the size of the window
3665 switch (resize_dir
) {
3668 dx
= - (x_root
- frame
.grab_x
);
3669 dy
= + (y_root
- frame
.grab_y
);
3673 dx
= + (x_root
- frame
.grab_x
);
3674 dy
= + (y_root
- frame
.grab_y
);
3677 anchor
= BottomRight
;
3678 dx
= - (x_root
- frame
.grab_x
);
3679 dy
= - (y_root
- frame
.grab_y
);
3682 anchor
= BottomLeft
;
3683 dx
= + (x_root
- frame
.grab_x
);
3684 dy
= - (y_root
- frame
.grab_y
);
3688 assert(false); // unhandled Corner
3689 return; // unreachable, for the compiler
3692 // make sure the user cant resize the window smaller than 0, which makes it
3693 // wrap around and become huge
3694 if (dx
< -(signed)client
.rect
.width()) dx
= -(signed)client
.rect
.width();
3695 if (dy
< -(signed)client
.rect
.height()) dy
= -(signed)client
.rect
.height();
3697 frame
.changing
.setSize(frame
.rect
.width() + dx
, frame
.rect
.height() + dy
);
3699 constrain(anchor
, &gw
, &gh
);
3701 XDrawRectangle(otk::OBDisplay::display
, screen
->getRootWindow(),
3702 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3703 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3705 screen
->showGeometry(gw
, gh
);
3709 void BlackboxWindow::endResize(void) {
3710 assert(flags
.resizing
);
3711 assert(blackbox
->getChangingWindow() == this);
3713 XDrawRectangle(otk::OBDisplay::display
, screen
->getRootWindow(),
3714 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3715 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3716 XUngrabServer(otk::OBDisplay::display
);
3718 // unset maximized state after resized when fully maximized
3719 if (flags
.maximized
== 1)
3722 flags
.resizing
= False
;
3723 blackbox
->setChangingWindow(0);
3725 configure(frame
.changing
.x(), frame
.changing
.y(),
3726 frame
.changing
.width(), frame
.changing
.height());
3727 screen
->hideGeometry();
3729 XUngrabPointer(otk::OBDisplay::display
, CurrentTime
);
3731 // if there are any left over motions from the resize, drop them now
3732 XSync(otk::OBDisplay::display
, false); // make sure we don't miss any
3734 while (XCheckTypedWindowEvent(otk::OBDisplay::display
, frame
.window
,
3739 void BlackboxWindow::motionNotifyEvent(const XMotionEvent
*me
) {
3741 fprintf(stderr
, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n",
3746 doMove(me
->x_root
, me
->y_root
);
3747 } else if (flags
.resizing
) {
3748 doResize(me
->x_root
, me
->y_root
);
3750 if ((functions
& Func_Move
) &&
3751 (me
->state
& Button1Mask
) &&
3752 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3753 frame
.handle
== me
->window
|| frame
.window
== me
->window
)) {
3754 beginMove(me
->x_root
, me
->y_root
);
3755 } else if ((functions
& Func_Resize
) &&
3756 ((me
->state
& Button1Mask
) &&
3757 (me
->window
== frame
.right_grip
||
3758 me
->window
== frame
.left_grip
)) ||
3759 ((me
->state
& Button3Mask
) && (me
->state
& mod_mask
) &&
3760 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3761 frame
.handle
== me
->window
|| frame
.window
== me
->window
||
3762 frame
.right_grip
== me
->window
||
3763 frame
.left_grip
== me
->window
))) {
3764 unsigned int zones
= screen
->getResizeZones();
3767 if (me
->window
== frame
.left_grip
) {
3768 corner
= BottomLeft
;
3769 } else if (me
->window
== frame
.right_grip
|| zones
== 1) {
3770 corner
= BottomRight
;
3773 bool left
= (me
->x_root
- frame
.rect
.x() <=
3774 static_cast<signed>(frame
.rect
.width() / 2));
3777 else // (zones == 4)
3778 top
= (me
->y_root
- frame
.rect
.y() <=
3779 static_cast<signed>(frame
.rect
.height() / 2));
3780 corner
= (top
? (left
? TopLeft
: TopRight
) :
3781 (left
? BottomLeft
: BottomRight
));
3784 beginResize(me
->x_root
, me
->y_root
, corner
);
3790 void BlackboxWindow::enterNotifyEvent(const XCrossingEvent
* ce
) {
3791 if (! (screen
->isSloppyFocus() && isVisible() && isNormal()))
3795 bool leave
= False
, inferior
= False
;
3797 while (XCheckTypedWindowEvent(otk::OBDisplay::display
, ce
->window
,
3799 if (e
.type
== LeaveNotify
&& e
.xcrossing
.mode
== NotifyNormal
) {
3801 inferior
= (e
.xcrossing
.detail
== NotifyInferior
);
3805 if (! leave
|| inferior
) {
3806 if (! isFocused()) {
3807 bool success
= setInputFocus();
3808 if (success
) // if focus succeeded install the colormap
3809 installColormap(True
); // XXX: shouldnt we honour no install?
3812 We only auto-raise when the window wasn't focused because otherwise
3813 we run into problems with gtk+ drop-down lists. The window ends up
3814 raising over the list.
3816 if (screen
->doAutoRaise())
3823 void BlackboxWindow::leaveNotifyEvent(const XCrossingEvent
*) {
3824 if (! (screen
->isSloppyFocus() && screen
->doAutoRaise() && isNormal()))
3827 installColormap(False
);
3829 if (timer
->isTiming())
3835 void BlackboxWindow::shapeEvent(XShapeEvent
*e
) {
3836 if (blackbox
->hasShapeExtensions()) {
3837 if (! e
->shaped
&& flags
.shaped
) {
3839 flags
.shaped
= False
;
3840 } else if (e
->shaped
) {
3842 flags
.shaped
= True
;
3849 bool BlackboxWindow::validateClient(void) const {
3850 XSync(otk::OBDisplay::display
, False
);
3853 if (XCheckTypedWindowEvent(otk::OBDisplay::display
, client
.window
,
3854 DestroyNotify
, &e
) ||
3855 XCheckTypedWindowEvent(otk::OBDisplay::display
, client
.window
,
3857 XPutBackEvent(otk::OBDisplay::display
, &e
);
3866 void BlackboxWindow::restore(bool remap
) {
3867 XChangeSaveSet(otk::OBDisplay::display
, client
.window
, SetModeDelete
);
3868 XSelectInput(otk::OBDisplay::display
, client
.window
, NoEventMask
);
3869 XSelectInput(otk::OBDisplay::display
, frame
.plate
, NoEventMask
);
3871 // do not leave a shaded window as an icon unless it was an icon
3872 if (flags
.shaded
&& ! flags
.iconic
)
3873 setState(NormalState
);
3875 // erase the netwm stuff that we read when a window maps, so that it
3876 // doesn't persist between mappings.
3877 // (these are the ones read in getNetWMFlags().)
3878 xatom
->eraseValue(client
.window
, XAtom::net_wm_desktop
);
3879 xatom
->eraseValue(client
.window
, XAtom::net_wm_state
);
3881 restoreGravity(client
.rect
);
3883 XUnmapWindow(otk::OBDisplay::display
, frame
.window
);
3884 XUnmapWindow(otk::OBDisplay::display
, client
.window
);
3886 XSetWindowBorderWidth(otk::OBDisplay::display
, client
.window
, client
.old_bw
);
3889 if (XCheckTypedWindowEvent(otk::OBDisplay::display
, client
.window
,
3890 ReparentNotify
, &ev
)) {
3893 // according to the ICCCM - if the client doesn't reparent to
3894 // root, then we have to do it for them
3895 XReparentWindow(otk::OBDisplay::display
, client
.window
,
3896 screen
->getRootWindow(),
3897 client
.rect
.x(), client
.rect
.y());
3900 if (remap
) XMapWindow(otk::OBDisplay::display
, client
.window
);
3904 // timer for autoraise
3905 void BlackboxWindow::timeout(void) {
3906 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3910 void BlackboxWindow::changeBlackboxHints(const BlackboxHints
*net
) {
3911 if ((net
->flags
& AttribShaded
) &&
3912 ((blackbox_attrib
.attrib
& AttribShaded
) !=
3913 (net
->attrib
& AttribShaded
)))
3916 if (flags
.visible
&& // watch out for requests when we can not be seen
3917 (net
->flags
& (AttribMaxVert
| AttribMaxHoriz
)) &&
3918 ((blackbox_attrib
.attrib
& (AttribMaxVert
| AttribMaxHoriz
)) !=
3919 (net
->attrib
& (AttribMaxVert
| AttribMaxHoriz
)))) {
3920 if (flags
.maximized
) {
3925 if ((net
->flags
& AttribMaxHoriz
) && (net
->flags
& AttribMaxVert
))
3926 button
= ((net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0);
3927 else if (net
->flags
& AttribMaxVert
)
3928 button
= ((net
->attrib
& AttribMaxVert
) ? 2 : 0);
3929 else if (net
->flags
& AttribMaxHoriz
)
3930 button
= ((net
->attrib
& AttribMaxHoriz
) ? 3 : 0);
3936 if ((net
->flags
& AttribOmnipresent
) &&
3937 ((blackbox_attrib
.attrib
& AttribOmnipresent
) !=
3938 (net
->attrib
& AttribOmnipresent
)))
3941 if ((net
->flags
& AttribWorkspace
) &&
3942 (blackbox_attrib
.workspace
!= net
->workspace
)) {
3943 screen
->reassociateWindow(this, net
->workspace
, True
);
3945 if (screen
->getCurrentWorkspaceID() != net
->workspace
) {
3949 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3953 if (net
->flags
& AttribDecoration
) {
3954 switch (net
->decoration
) {
3971 * Set the sizes of all components of the window frame
3972 * (the window decorations).
3973 * These values are based upon the current style settings and the client
3974 * window's dimensions.
3976 void BlackboxWindow::upsize(void) {
3977 frame
.bevel_w
= screen
->getBevelWidth();
3979 if (decorations
& Decor_Border
) {
3980 frame
.border_w
= screen
->getBorderWidth();
3981 if (! isTransient())
3982 frame
.mwm_border_w
= screen
->getFrameWidth();
3984 frame
.mwm_border_w
= 0;
3986 frame
.mwm_border_w
= frame
.border_w
= 0;
3989 if (decorations
& Decor_Titlebar
) {
3990 // the height of the titlebar is based upon the height of the font being
3991 // used to display the window's title
3992 WindowStyle
*style
= screen
->getWindowStyle();
3993 frame
.title_h
= style
->font
->height() + (frame
.bevel_w
* 2) + 2;
3995 frame
.label_h
= frame
.title_h
- (frame
.bevel_w
* 2);
3996 frame
.button_w
= (frame
.label_h
- 2);
3998 // set the top frame margin
3999 frame
.margin
.top
= frame
.border_w
+ frame
.title_h
+
4000 frame
.border_w
+ frame
.mwm_border_w
;
4006 // set the top frame margin
4007 frame
.margin
.top
= frame
.border_w
+ frame
.mwm_border_w
;
4010 // set the left/right frame margin
4011 frame
.margin
.left
= frame
.margin
.right
= frame
.border_w
+ frame
.mwm_border_w
;
4013 if (decorations
& Decor_Handle
) {
4014 frame
.grip_w
= frame
.button_w
* 2;
4015 frame
.handle_h
= screen
->getHandleWidth();
4017 // set the bottom frame margin
4018 frame
.margin
.bottom
= frame
.border_w
+ frame
.handle_h
+
4019 frame
.border_w
+ frame
.mwm_border_w
;
4024 // set the bottom frame margin
4025 frame
.margin
.bottom
= frame
.border_w
+ frame
.mwm_border_w
;
4029 We first get the normal dimensions and use this to define the inside_w/h
4030 then we modify the height if shading is in effect.
4031 If the shade state is not considered then frame.rect gets reset to the
4032 normal window size on a reconfigure() call resulting in improper
4033 dimensions appearing in move/resize and other events.
4036 height
= client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
,
4037 width
= client
.rect
.width() + frame
.margin
.left
+ frame
.margin
.right
;
4039 frame
.inside_w
= width
- (frame
.border_w
* 2);
4040 frame
.inside_h
= height
- (frame
.border_w
* 2);
4043 height
= frame
.title_h
+ (frame
.border_w
* 2);
4044 frame
.rect
.setSize(width
, height
);
4049 * Calculate the size of the client window and constrain it to the
4050 * size specified by the size hints of the client window.
4052 * The logical width and height are placed into pw and ph, if they
4053 * are non-zero. Logical size refers to the users perception of
4054 * the window size (for example an xterm resizes in cells, not in pixels).
4055 * pw and ph are then used to display the geometry during window moves, resize,
4058 * The physical geometry is placed into frame.changing_{x,y,width,height}.
4059 * Physical geometry refers to the geometry of the window in pixels.
4061 void BlackboxWindow::constrain(Corner anchor
,
4062 unsigned int *pw
, unsigned int *ph
) {
4063 // frame.changing represents the requested frame size, we need to
4064 // strip the frame margin off and constrain the client size
4065 frame
.changing
.setCoords(frame
.changing
.left() + frame
.margin
.left
,
4066 frame
.changing
.top() + frame
.margin
.top
,
4067 frame
.changing
.right() - frame
.margin
.right
,
4068 frame
.changing
.bottom() - frame
.margin
.bottom
);
4070 unsigned int dw
= frame
.changing
.width(), dh
= frame
.changing
.height(),
4071 base_width
= (client
.base_width
) ? client
.base_width
: client
.min_width
,
4072 base_height
= (client
.base_height
) ? client
.base_height
:
4075 // constrain, but only if the min/max are being used. if they aren't, then
4076 // this resize is going to be from a ConfigureRequest because the window
4077 // isn't allowed to be resized by the user. And in that case, we don't want
4078 // to limit what the app can do
4079 if (client
.max_width
> client
.min_width
||
4080 client
.max_height
> client
.min_height
) {
4081 if (dw
< client
.min_width
) dw
= client
.min_width
;
4082 if (dh
< client
.min_height
) dh
= client
.min_height
;
4083 if (dw
> client
.max_width
) dw
= client
.max_width
;
4084 if (dh
> client
.max_height
) dh
= client
.max_height
;
4087 if (client
.width_inc
> 1) {
4089 dw
/= client
.width_inc
;
4091 if (client
.height_inc
> 1) {
4093 dh
/= client
.height_inc
;
4102 if (client
.width_inc
> 1) {
4103 dw
*= client
.width_inc
;
4106 if (client
.height_inc
> 1) {
4107 dh
*= client
.height_inc
;
4111 frame
.changing
.setSize(dw
, dh
);
4113 // add the frame margin back onto frame.changing
4114 frame
.changing
.setCoords(frame
.changing
.left() - frame
.margin
.left
,
4115 frame
.changing
.top() - frame
.margin
.top
,
4116 frame
.changing
.right() + frame
.margin
.right
,
4117 frame
.changing
.bottom() + frame
.margin
.bottom
);
4119 // move frame.changing to the specified anchor
4127 dx
= frame
.rect
.right() - frame
.changing
.right();
4131 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
4135 dx
= frame
.rect
.right() - frame
.changing
.right();
4136 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
4140 assert(false); // unhandled corner
4142 frame
.changing
.setPos(frame
.changing
.x() + dx
, frame
.changing
.y() + dy
);
4146 void WindowStyle::doJustify(const std::string
&text
, int &start_pos
,
4147 unsigned int max_length
,
4148 unsigned int modifier
) const {
4149 size_t text_len
= text
.size();
4150 unsigned int length
;
4153 length
= font
->measureString(string(text
, 0, text_len
)) + modifier
;
4154 } while (length
> max_length
&& text_len
-- > 0);
4158 start_pos
+= max_length
- length
;
4162 start_pos
+= (max_length
- length
) / 2;
4172 BWindowGroup::BWindowGroup(Blackbox
*b
, Window _group
)
4173 : blackbox(b
), group(_group
) {
4174 XWindowAttributes wattrib
;
4175 if (! XGetWindowAttributes(otk::OBDisplay::display
, group
, &wattrib
)) {
4176 // group window doesn't seem to exist anymore
4181 XSelectInput(otk::OBDisplay::display
, group
,
4182 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
4184 blackbox
->saveGroupSearch(group
, this);
4188 BWindowGroup::~BWindowGroup(void) {
4189 blackbox
->removeGroupSearch(group
);
4194 BWindowGroup::find(BScreen
*screen
, bool allow_transients
) const {
4195 BlackboxWindow
*ret
= blackbox
->getFocusedWindow();
4197 // does the focus window match (or any transient_fors)?
4198 for (; ret
; ret
= ret
->getTransientFor()) {
4199 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
&&
4200 (! ret
->isTransient() || allow_transients
))
4204 if (ret
) return ret
;
4206 // the focus window didn't match, look in the group's window list
4207 BlackboxWindowList::const_iterator it
, end
= windowList
.end();
4208 for (it
= windowList
.begin(); it
!= end
; ++it
) {
4210 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
&&
4211 (! ret
->isTransient() || allow_transients
))