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 otk::OBTimer(Openbox::instance
->timerManager(),
139 (otk::OBTimeoutHandler
)timeout
,
141 timer
->setTimeout(blackbox
->getAutoRaiseDelay());
143 // get size, aspect, minimum/maximum size and other hints set by the
146 if (! getBlackboxHints())
153 frame
.window
= createToplevelWindow();
155 blackbox
->saveWindowSearch(frame
.window
, this);
157 frame
.plate
= createChildWindow(frame
.window
, ExposureMask
);
158 blackbox
->saveWindowSearch(frame
.plate
, this);
160 // determine if this is a transient window
163 // determine the window's type, so we can decide its decorations and
164 // functionality, or if we should not manage it at all
165 if (getWindowType()) {
166 // adjust the window decorations/behavior based on the window type
167 switch (window_type
) {
171 blackbox_attrib
.workspace
= 0; // we do need to belong to a workspace
172 flags
.stuck
= True
; // we show up on all workspaces
174 // none of these windows are manipulated by the window manager
180 // these windows get less functionality
181 functions
&= ~(Func_Maximize
| Func_Resize
| Func_Iconify
);
185 // dialogs cannot be maximized
186 functions
&= ~Func_Maximize
;
190 // normal windows retain all of the possible decorations and
198 // further adjeust the window's decorations/behavior based on window sizes
199 if ((client
.normal_hint_flags
& PMinSize
) &&
200 (client
.normal_hint_flags
& PMaxSize
) &&
201 client
.max_width
<= client
.min_width
&&
202 client
.max_height
<= client
.min_height
) {
203 functions
&= ~(Func_Resize
| Func_Maximize
);
210 if (decorations
& Decor_Titlebar
)
213 if (decorations
& Decor_Handle
)
216 // apply the size and gravity hint to the frame
220 bool place_window
= True
;
221 if (blackbox
->state() == Openbox::State_Starting
|| isTransient() ||
222 client
.normal_hint_flags
& (PPosition
|USPosition
)) {
223 applyGravity(frame
.rect
);
225 if (blackbox
->state() == Openbox::State_Starting
||
226 client
.rect
.intersects(screen
->getRect()))
227 place_window
= False
;
230 // add the window's strut. note this is done *after* placing the window.
231 screen
->addStrut(&client
.strut
);
235 the server needs to be grabbed here to prevent client's from sending
236 events while we are in the process of configuring their window.
237 We hold the grab until after we are done moving the window around.
240 XGrabServer(otk::OBDisplay::display
);
242 associateClientWindow();
244 blackbox
->saveWindowSearch(client
.window
, this);
246 if (blackbox_attrib
.workspace
>= screen
->getWorkspaceCount())
247 screen
->getCurrentWorkspace()->addWindow(this, place_window
);
249 screen
->getWorkspace(blackbox_attrib
.workspace
)->
250 addWindow(this, place_window
);
252 if (! place_window
) {
253 // don't need to call configure if we are letting the workspace
255 configure(frame
.rect
.x(), frame
.rect
.y(),
256 frame
.rect
.width(), frame
.rect
.height());
262 XUngrabServer(otk::OBDisplay::display
);
265 if (blackbox
->hasShapeExtensions() && flags
.shaped
)
269 // now that we know where to put the window and what it should look like
270 // we apply the decorations
275 XMapSubwindows(otk::OBDisplay::display
, frame
.window
);
277 // this ensures the title, buttons, and other decor are properly displayed
280 // preserve the window's initial state on first map, and its current state
282 unsigned long initial_state
= current_state
;
284 current_state
= initial_state
;
286 // get sticky state from our parent window if we've got one
287 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
288 client
.transient_for
->isStuck() != flags
.stuck
)
292 flags
.shaded
= False
;
293 initial_state
= current_state
;
297 At this point in the life of a window, current_state should only be set
298 to IconicState if the window was an *icon*, not if it was shaded.
300 if (initial_state
!= IconicState
)
301 current_state
= NormalState
;
309 if (flags
.maximized
&& (functions
& Func_Maximize
))
314 BlackboxWindow::~BlackboxWindow(void) {
316 fprintf(stderr
, "BlackboxWindow::~BlackboxWindow: destroying 0x%lx\n",
320 if (! timer
) // window not managed...
326 screen
->removeStrut(&client
.strut
);
327 screen
->updateAvailableArea();
329 // We don't need to worry about resizing because resizing always grabs the X
330 // server. This should only ever happen if using opaque moving.
336 if (client
.window_group
) {
337 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
338 if (group
) group
->removeWindow(this);
341 // remove ourselves from our transient_for
343 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul)
344 client
.transient_for
->client
.transientList
.remove(this);
345 client
.transient_for
= (BlackboxWindow
*) 0;
348 if (client
.transientList
.size() > 0) {
349 // reset transient_for for all transients
350 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
351 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
352 (*it
)->client
.transient_for
= (BlackboxWindow
*) 0;
362 blackbox
->removeWindowSearch(frame
.plate
);
363 XDestroyWindow(otk::OBDisplay::display
, frame
.plate
);
367 blackbox
->removeWindowSearch(frame
.window
);
368 XDestroyWindow(otk::OBDisplay::display
, frame
.window
);
371 blackbox
->removeWindowSearch(client
.window
);
375 void BlackboxWindow::enableDecor(bool enable
) {
376 blackbox_attrib
.flags
|= AttribDecoration
;
377 blackbox_attrib
.decoration
= enable
? DecorNormal
: DecorNone
;
380 // we can not be shaded if we lack a titlebar
381 if (! (decorations
& Decor_Titlebar
) && flags
.shaded
)
384 if (flags
.visible
&& frame
.window
) {
385 XMapSubwindows(otk::OBDisplay::display
, frame
.window
);
386 XMapWindow(otk::OBDisplay::display
, frame
.window
);
390 setState(current_state
);
394 void BlackboxWindow::setupDecor() {
395 if (blackbox_attrib
.decoration
!= DecorNone
) {
396 // start with everything on
397 decorations
= Decor_Close
|
398 (mwm_decorations
& Decor_Titlebar
? Decor_Titlebar
: 0) |
399 (mwm_decorations
& Decor_Border
? Decor_Border
: 0) |
400 (mwm_decorations
& Decor_Handle
? Decor_Handle
: 0) |
401 (mwm_decorations
& Decor_Iconify
? Decor_Iconify
: 0) |
402 (mwm_decorations
& Decor_Maximize
? Decor_Maximize
: 0);
404 if (! (functions
& Func_Close
)) decorations
&= ~Decor_Close
;
405 if (! (functions
& Func_Maximize
)) decorations
&= ~Decor_Maximize
;
406 if (! (functions
& Func_Iconify
)) decorations
&= ~Decor_Iconify
;
407 if (! (functions
& Func_Resize
)) decorations
&= ~Decor_Handle
;
409 switch (window_type
) {
414 // none of these windows are decorated by the window manager at all
420 decorations
&= ~(Decor_Border
);
424 decorations
&= ~Decor_Handle
;
436 * Creates a new top level window, with a given location, size, and border
438 * Returns: the newly created window
440 Window
BlackboxWindow::createToplevelWindow(void) {
441 XSetWindowAttributes attrib_create
;
442 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
| CWColormap
|
443 CWOverrideRedirect
| CWEventMask
;
445 attrib_create
.background_pixmap
= None
;
446 attrib_create
.colormap
= screen
->getColormap();
447 attrib_create
.override_redirect
= True
;
448 attrib_create
.event_mask
= EnterWindowMask
| LeaveWindowMask
|
451 We catch button presses because other wise they get passed down to the
452 root window, which will then cause root menus to show when you click the
456 return XCreateWindow(otk::OBDisplay::display
, screen
->getRootWindow(),
457 0, 0, 1, 1, frame
.border_w
, screen
->getDepth(),
458 InputOutput
, screen
->getVisual(), create_mask
,
464 * Creates a child window, and optionally associates a given cursor with
467 Window
BlackboxWindow::createChildWindow(Window parent
,
468 unsigned long event_mask
,
470 XSetWindowAttributes attrib_create
;
471 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
|
474 attrib_create
.background_pixmap
= None
;
475 attrib_create
.event_mask
= event_mask
;
478 create_mask
|= CWCursor
;
479 attrib_create
.cursor
= cursor
;
482 return XCreateWindow(otk::OBDisplay::display
, parent
, 0, 0, 1, 1, 0,
483 screen
->getDepth(), InputOutput
, screen
->getVisual(),
484 create_mask
, &attrib_create
);
488 void BlackboxWindow::associateClientWindow(void) {
489 XSetWindowBorderWidth(otk::OBDisplay::display
, client
.window
, 0);
493 XChangeSaveSet(otk::OBDisplay::display
, client
.window
, SetModeInsert
);
495 XSelectInput(otk::OBDisplay::display
, frame
.plate
, SubstructureRedirectMask
);
498 note we used to grab around this call to XReparentWindow however the
499 server is now grabbed before this method is called
501 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
503 XSelectInput(otk::OBDisplay::display
, client
.window
,
504 event_mask
& ~StructureNotifyMask
);
505 XReparentWindow(otk::OBDisplay::display
, client
.window
, frame
.plate
, 0, 0);
506 XSelectInput(otk::OBDisplay::display
, client
.window
, event_mask
);
508 XRaiseWindow(otk::OBDisplay::display
, frame
.plate
);
509 XMapSubwindows(otk::OBDisplay::display
, frame
.plate
);
512 if (blackbox
->hasShapeExtensions()) {
513 XShapeSelectInput(otk::OBDisplay::display
, client
.window
,
520 XShapeQueryExtents(otk::OBDisplay::display
, client
.window
, &shaped
,
521 &foo
, &foo
, &ufoo
, &ufoo
, &foo
, &foo
, &foo
,
523 flags
.shaped
= shaped
;
529 void BlackboxWindow::decorate(void) {
530 otk::BTexture
* texture
;
532 texture
= &(screen
->getWindowStyle()->b_focus
);
533 frame
.fbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
536 frame
.fbutton_pixel
= texture
->color().pixel();
538 texture
= &(screen
->getWindowStyle()->b_unfocus
);
539 frame
.ubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
542 frame
.ubutton_pixel
= texture
->color().pixel();
544 unsigned char needsPressed
= 0;
546 texture
= &(screen
->getWindowStyle()->b_pressed_focus
);
548 if (texture
->texture() != otk::BTexture::NoTexture
) {
549 frame
.pfbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
551 if (! frame
.pfbutton
)
552 frame
.pfbutton_pixel
= texture
->color().pixel();
557 texture
= &(screen
->getWindowStyle()->b_pressed_unfocus
);
559 if (texture
->texture() != otk::BTexture::NoTexture
) {
560 frame
.pubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
562 if (! frame
.pubutton
)
563 frame
.pubutton
= texture
->color().pixel();
568 // if we either pressed unfocused, or pressed focused were undefined,
569 // make them inherit from the old resource. It's a hack for sure, but
570 // it allows for some backwards and forwards compatibility.
572 texture
= &(screen
->getWindowStyle()->b_pressed
);
574 if (needsPressed
& 0x1) {
575 frame
.pfbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
577 if (! frame
.pfbutton
)
578 frame
.pfbutton_pixel
= texture
->color().pixel();
580 if (needsPressed
& 0x2) {
581 frame
.pubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
583 if (! frame
.pubutton
)
584 frame
.pubutton
= texture
->color().pixel();
589 if (decorations
& Decor_Titlebar
) {
590 texture
= &(screen
->getWindowStyle()->t_focus
);
591 frame
.ftitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
594 frame
.ftitle_pixel
= texture
->color().pixel();
596 texture
= &(screen
->getWindowStyle()->t_unfocus
);
597 frame
.utitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
600 frame
.utitle_pixel
= texture
->color().pixel();
602 XSetWindowBorder(otk::OBDisplay::display
, frame
.title
,
603 screen
->getBorderColor()->pixel());
608 if (decorations
& Decor_Border
) {
609 frame
.fborder_pixel
= screen
->getWindowStyle()->f_focus
.color().pixel();
610 frame
.uborder_pixel
= screen
->getWindowStyle()->f_unfocus
.color().pixel();
613 if (decorations
& Decor_Handle
) {
614 texture
= &(screen
->getWindowStyle()->h_focus
);
615 frame
.fhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
618 frame
.fhandle_pixel
= texture
->color().pixel();
620 texture
= &(screen
->getWindowStyle()->h_unfocus
);
621 frame
.uhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
624 frame
.uhandle_pixel
= texture
->color().pixel();
626 texture
= &(screen
->getWindowStyle()->g_focus
);
627 frame
.fgrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.fgrip
);
629 frame
.fgrip_pixel
= texture
->color().pixel();
631 texture
= &(screen
->getWindowStyle()->g_unfocus
);
632 frame
.ugrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.ugrip
);
634 frame
.ugrip_pixel
= texture
->color().pixel();
636 XSetWindowBorder(otk::OBDisplay::display
, frame
.handle
,
637 screen
->getBorderColor()->pixel());
638 XSetWindowBorder(otk::OBDisplay::display
, frame
.left_grip
,
639 screen
->getBorderColor()->pixel());
640 XSetWindowBorder(otk::OBDisplay::display
, frame
.right_grip
,
641 screen
->getBorderColor()->pixel());
644 XSetWindowBorder(otk::OBDisplay::display
, frame
.window
,
645 screen
->getBorderColor()->pixel());
649 void BlackboxWindow::decorateLabel(void) {
650 otk::BTexture
*texture
;
652 texture
= &(screen
->getWindowStyle()->l_focus
);
653 frame
.flabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.flabel
);
655 frame
.flabel_pixel
= texture
->color().pixel();
657 texture
= &(screen
->getWindowStyle()->l_unfocus
);
658 frame
.ulabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.ulabel
);
660 frame
.ulabel_pixel
= texture
->color().pixel();
664 void BlackboxWindow::createHandle(void) {
665 frame
.handle
= createChildWindow(frame
.window
,
666 ButtonPressMask
| ButtonReleaseMask
|
667 ButtonMotionMask
| ExposureMask
);
668 blackbox
->saveWindowSearch(frame
.handle
, this);
671 createChildWindow(frame
.handle
,
672 ButtonPressMask
| ButtonReleaseMask
|
673 ButtonMotionMask
| ExposureMask
,
674 blackbox
->getLowerLeftAngleCursor());
675 blackbox
->saveWindowSearch(frame
.left_grip
, this);
678 createChildWindow(frame
.handle
,
679 ButtonPressMask
| ButtonReleaseMask
|
680 ButtonMotionMask
| ExposureMask
,
681 blackbox
->getLowerRightAngleCursor());
682 blackbox
->saveWindowSearch(frame
.right_grip
, this);
686 void BlackboxWindow::destroyHandle(void) {
688 screen
->getImageControl()->removeImage(frame
.fhandle
);
691 screen
->getImageControl()->removeImage(frame
.uhandle
);
694 screen
->getImageControl()->removeImage(frame
.fgrip
);
697 screen
->getImageControl()->removeImage(frame
.ugrip
);
699 blackbox
->removeWindowSearch(frame
.left_grip
);
700 blackbox
->removeWindowSearch(frame
.right_grip
);
702 XDestroyWindow(otk::OBDisplay::display
, frame
.left_grip
);
703 XDestroyWindow(otk::OBDisplay::display
, frame
.right_grip
);
704 frame
.left_grip
= frame
.right_grip
= None
;
706 blackbox
->removeWindowSearch(frame
.handle
);
707 XDestroyWindow(otk::OBDisplay::display
, frame
.handle
);
712 void BlackboxWindow::createTitlebar(void) {
713 frame
.title
= createChildWindow(frame
.window
,
714 ButtonPressMask
| ButtonReleaseMask
|
715 ButtonMotionMask
| ExposureMask
);
716 frame
.label
= createChildWindow(frame
.title
,
717 ButtonPressMask
| ButtonReleaseMask
|
718 ButtonMotionMask
| ExposureMask
);
719 blackbox
->saveWindowSearch(frame
.title
, this);
720 blackbox
->saveWindowSearch(frame
.label
, this);
722 if (decorations
& Decor_Iconify
) createIconifyButton();
723 if (decorations
& Decor_Maximize
) createMaximizeButton();
724 if (decorations
& Decor_Close
) createCloseButton();
728 void BlackboxWindow::destroyTitlebar(void) {
729 if (frame
.close_button
)
730 destroyCloseButton();
732 if (frame
.iconify_button
)
733 destroyIconifyButton();
735 if (frame
.maximize_button
)
736 destroyMaximizeButton();
738 if (frame
.stick_button
)
739 destroyStickyButton();
742 screen
->getImageControl()->removeImage(frame
.ftitle
);
745 screen
->getImageControl()->removeImage(frame
.utitle
);
748 screen
->getImageControl()->removeImage(frame
.flabel
);
751 screen
->getImageControl()->removeImage(frame
.ulabel
);
754 screen
->getImageControl()->removeImage(frame
.fbutton
);
757 screen
->getImageControl()->removeImage(frame
.ubutton
);
759 blackbox
->removeWindowSearch(frame
.title
);
760 blackbox
->removeWindowSearch(frame
.label
);
762 XDestroyWindow(otk::OBDisplay::display
, frame
.label
);
763 XDestroyWindow(otk::OBDisplay::display
, frame
.title
);
764 frame
.title
= frame
.label
= None
;
768 void BlackboxWindow::createCloseButton(void) {
769 if (frame
.title
!= None
) {
770 frame
.close_button
= createChildWindow(frame
.title
,
773 ButtonMotionMask
| ExposureMask
);
774 blackbox
->saveWindowSearch(frame
.close_button
, this);
779 void BlackboxWindow::destroyCloseButton(void) {
780 blackbox
->removeWindowSearch(frame
.close_button
);
781 XDestroyWindow(otk::OBDisplay::display
, frame
.close_button
);
782 frame
.close_button
= None
;
786 void BlackboxWindow::createIconifyButton(void) {
787 if (frame
.title
!= None
) {
788 frame
.iconify_button
= createChildWindow(frame
.title
,
791 ButtonMotionMask
| ExposureMask
);
792 blackbox
->saveWindowSearch(frame
.iconify_button
, this);
797 void BlackboxWindow::destroyIconifyButton(void) {
798 blackbox
->removeWindowSearch(frame
.iconify_button
);
799 XDestroyWindow(otk::OBDisplay::display
, frame
.iconify_button
);
800 frame
.iconify_button
= None
;
804 void BlackboxWindow::createMaximizeButton(void) {
805 if (frame
.title
!= None
) {
806 frame
.maximize_button
= createChildWindow(frame
.title
,
809 ButtonMotionMask
| ExposureMask
);
810 blackbox
->saveWindowSearch(frame
.maximize_button
, this);
815 void BlackboxWindow::destroyMaximizeButton(void) {
816 blackbox
->removeWindowSearch(frame
.maximize_button
);
817 XDestroyWindow(otk::OBDisplay::display
, frame
.maximize_button
);
818 frame
.maximize_button
= None
;
821 void BlackboxWindow::createStickyButton(void) {
822 if (frame
.title
!= None
) {
823 frame
.stick_button
= createChildWindow(frame
.title
,
826 ButtonMotionMask
| ExposureMask
);
827 blackbox
->saveWindowSearch(frame
.stick_button
, this);
831 void BlackboxWindow::destroyStickyButton(void) {
832 blackbox
->removeWindowSearch(frame
.stick_button
);
833 XDestroyWindow(otk::OBDisplay::display
, frame
.stick_button
);
834 frame
.stick_button
= None
;
837 void BlackboxWindow::positionButtons(bool redecorate_label
) {
838 string layout
= blackbox
->getTitlebarLayout();
841 bool hasclose
, hasiconify
, hasmaximize
, haslabel
, hasstick
;
842 hasclose
= hasiconify
= hasmaximize
= haslabel
= hasstick
= false;
844 string::const_iterator it
, end
;
845 for (it
= layout
.begin(), end
= layout
.end(); it
!= end
; ++it
) {
848 if (! hasclose
&& (decorations
& Decor_Close
)) {
854 if (! hasiconify
&& (decorations
& Decor_Iconify
)) {
866 if (! hasmaximize
&& (decorations
& Decor_Maximize
)) {
880 if (! hasclose
&& frame
.close_button
)
881 destroyCloseButton();
882 if (! hasiconify
&& frame
.iconify_button
)
883 destroyIconifyButton();
884 if (! hasmaximize
&& frame
.maximize_button
)
885 destroyMaximizeButton();
886 if (! hasstick
&& frame
.stick_button
)
887 destroyStickyButton();
889 parsed
+= 'L'; // require that the label be in the layout
891 const unsigned int bsep
= frame
.bevel_w
+ 1; // separation between elements
892 const unsigned int by
= frame
.bevel_w
+ 1;
893 const unsigned int ty
= frame
.bevel_w
;
895 frame
.label_w
= frame
.inside_w
- bsep
* 2 -
896 (frame
.button_w
+ bsep
) * (parsed
.size() - 1);
898 unsigned int x
= bsep
;
899 for (it
= parsed
.begin(), end
= parsed
.end(); it
!= end
; ++it
) {
902 if (! frame
.close_button
) createCloseButton();
903 XMoveResizeWindow(otk::OBDisplay::display
, frame
.close_button
, x
, by
,
904 frame
.button_w
, frame
.button_w
);
905 x
+= frame
.button_w
+ bsep
;
908 if (! frame
.iconify_button
) createIconifyButton();
909 XMoveResizeWindow(otk::OBDisplay::display
, frame
.iconify_button
, x
, by
,
910 frame
.button_w
, frame
.button_w
);
911 x
+= frame
.button_w
+ bsep
;
914 if (! frame
.stick_button
) createStickyButton();
915 XMoveResizeWindow(otk::OBDisplay::display
, frame
.stick_button
, x
, by
,
916 frame
.button_w
, frame
.button_w
);
917 x
+= frame
.button_w
+ bsep
;
920 if (! frame
.maximize_button
) createMaximizeButton();
921 XMoveResizeWindow(otk::OBDisplay::display
, frame
.maximize_button
, x
, by
,
922 frame
.button_w
, frame
.button_w
);
923 x
+= frame
.button_w
+ bsep
;
926 XMoveResizeWindow(otk::OBDisplay::display
, frame
.label
, x
, ty
,
927 frame
.label_w
, frame
.label_h
);
928 x
+= frame
.label_w
+ bsep
;
933 if (redecorate_label
) decorateLabel();
939 void BlackboxWindow::reconfigure(void) {
940 restoreGravity(client
.rect
);
942 applyGravity(frame
.rect
);
952 void BlackboxWindow::grabButtons(void) {
953 mod_mask
= blackbox
->getMouseModMask();
955 if (! screen
->isSloppyFocus() || screen
->doClickRaise())
956 // grab button 1 for changing focus/raising
957 otk::OBDisplay::grabButton(Button1
, 0, frame
.plate
, True
, ButtonPressMask
,
958 GrabModeSync
, GrabModeSync
, frame
.plate
, None
,
959 screen
->allowScrollLock());
961 if (functions
& Func_Move
)
962 otk::OBDisplay::grabButton(Button1
, mod_mask
, frame
.window
, True
,
963 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
964 GrabModeAsync
, frame
.window
, None
,
965 screen
->allowScrollLock());
966 if (functions
& Func_Resize
)
967 otk::OBDisplay::grabButton(Button3
, mod_mask
, frame
.window
, True
,
968 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
969 GrabModeAsync
, frame
.window
, None
,
970 screen
->allowScrollLock());
971 // alt+middle lowers the window
972 otk::OBDisplay::grabButton(Button2
, mod_mask
, frame
.window
, True
,
973 ButtonReleaseMask
, GrabModeAsync
, GrabModeAsync
,
974 frame
.window
, None
, screen
->allowScrollLock());
978 void BlackboxWindow::ungrabButtons(void) {
979 otk::OBDisplay::ungrabButton(Button1
, 0, frame
.plate
);
980 otk::OBDisplay::ungrabButton(Button1
, mod_mask
, frame
.window
);
981 otk::OBDisplay::ungrabButton(Button2
, mod_mask
, frame
.window
);
982 otk::OBDisplay::ungrabButton(Button3
, mod_mask
, frame
.window
);
986 void BlackboxWindow::positionWindows(void) {
987 XMoveResizeWindow(otk::OBDisplay::display
, frame
.window
,
988 frame
.rect
.x(), frame
.rect
.y(), frame
.inside_w
,
989 (flags
.shaded
) ? frame
.title_h
: frame
.inside_h
);
990 XSetWindowBorderWidth(otk::OBDisplay::display
, frame
.window
,
992 XSetWindowBorderWidth(otk::OBDisplay::display
, frame
.plate
,
994 XMoveResizeWindow(otk::OBDisplay::display
, frame
.plate
,
995 frame
.margin
.left
- frame
.mwm_border_w
- frame
.border_w
,
996 frame
.margin
.top
- frame
.mwm_border_w
- frame
.border_w
,
997 client
.rect
.width(), client
.rect
.height());
998 XMoveResizeWindow(otk::OBDisplay::display
, client
.window
,
999 0, 0, client
.rect
.width(), client
.rect
.height());
1000 // ensure client.rect contains the real location
1001 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1002 frame
.rect
.top() + frame
.margin
.top
);
1004 if (decorations
& Decor_Titlebar
) {
1005 if (frame
.title
== None
) createTitlebar();
1007 XSetWindowBorderWidth(otk::OBDisplay::display
, frame
.title
,
1009 XMoveResizeWindow(otk::OBDisplay::display
, frame
.title
, -frame
.border_w
,
1010 -frame
.border_w
, frame
.inside_w
, frame
.title_h
);
1013 XMapSubwindows(otk::OBDisplay::display
, frame
.title
);
1014 XMapWindow(otk::OBDisplay::display
, frame
.title
);
1015 } else if (frame
.title
) {
1018 if (decorations
& Decor_Handle
) {
1019 if (frame
.handle
== None
) createHandle();
1020 XSetWindowBorderWidth(otk::OBDisplay::display
, frame
.handle
,
1022 XSetWindowBorderWidth(otk::OBDisplay::display
, frame
.left_grip
,
1024 XSetWindowBorderWidth(otk::OBDisplay::display
, frame
.right_grip
,
1027 // use client.rect here so the value is correct even if shaded
1028 XMoveResizeWindow(otk::OBDisplay::display
, frame
.handle
,
1030 client
.rect
.height() + frame
.margin
.top
+
1031 frame
.mwm_border_w
- frame
.border_w
,
1032 frame
.inside_w
, frame
.handle_h
);
1033 XMoveResizeWindow(otk::OBDisplay::display
, frame
.left_grip
,
1034 -frame
.border_w
, -frame
.border_w
,
1035 frame
.grip_w
, frame
.handle_h
);
1036 XMoveResizeWindow(otk::OBDisplay::display
, frame
.right_grip
,
1037 frame
.inside_w
- frame
.grip_w
- frame
.border_w
,
1038 -frame
.border_w
, frame
.grip_w
, frame
.handle_h
);
1040 XMapSubwindows(otk::OBDisplay::display
, frame
.handle
);
1041 XMapWindow(otk::OBDisplay::display
, frame
.handle
);
1042 } else if (frame
.handle
) {
1045 XSync(otk::OBDisplay::display
, False
);
1049 void BlackboxWindow::updateStrut(void) {
1050 unsigned long num
= 4;
1051 unsigned long *data
;
1052 if (! xatom
->getValue(client
.window
, XAtom::net_wm_strut
, XAtom::cardinal
,
1057 client
.strut
.left
= data
[0];
1058 client
.strut
.right
= data
[1];
1059 client
.strut
.top
= data
[2];
1060 client
.strut
.bottom
= data
[3];
1062 screen
->updateAvailableArea();
1069 bool BlackboxWindow::getWindowType(void) {
1070 window_type
= (WindowType
) -1;
1073 unsigned long num
= (unsigned) -1;
1074 if (xatom
->getValue(client
.window
, XAtom::net_wm_window_type
, XAtom::atom
,
1076 for (unsigned long i
= 0; i
< num
; ++i
) {
1077 if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_desktop
))
1078 window_type
= Type_Desktop
;
1079 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_dock
))
1080 window_type
= Type_Dock
;
1081 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_toolbar
))
1082 window_type
= Type_Toolbar
;
1083 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_menu
))
1084 window_type
= Type_Menu
;
1085 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_utility
))
1086 window_type
= Type_Utility
;
1087 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_splash
))
1088 window_type
= Type_Splash
;
1089 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_dialog
))
1090 window_type
= Type_Dialog
;
1091 else if (val
[i
] == xatom
->getAtom(XAtom::net_wm_window_type_normal
))
1092 window_type
= Type_Normal
;
1094 xatom
->getAtom(XAtom::kde_net_wm_window_type_override
))
1095 mwm_decorations
= 0; // prevent this window from getting any decor
1100 if (window_type
== (WindowType
) -1) {
1102 * the window type hint was not set, which means we either classify ourself
1103 * as a normal window or a dialog, depending on if we are a transient.
1106 window_type
= Type_Dialog
;
1108 window_type
= Type_Normal
;
1117 void BlackboxWindow::getWMName(void) {
1118 if (xatom
->getValue(client
.window
, XAtom::net_wm_name
,
1119 XAtom::utf8
, client
.title
) &&
1120 !client
.title
.empty()) {
1121 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
1124 //fall through to using WM_NAME
1125 if (xatom
->getValue(client
.window
, XAtom::wm_name
, XAtom::ansi
, client
.title
)
1126 && !client
.title
.empty()) {
1127 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_name
);
1130 // fall back to an internal default
1131 client
.title
= "Unnamed";
1132 xatom
->setValue(client
.window
, XAtom::net_wm_visible_name
, XAtom::utf8
,
1135 #ifdef DEBUG_WITH_ID
1136 // the 16 is the 8 chars of the debug text plus the number
1137 char *tmp
= new char[client
.title
.length() + 16];
1138 sprintf(tmp
, "%s; id: 0x%lx", client
.title
.c_str(), client
.window
);
1145 void BlackboxWindow::getWMIconName(void) {
1146 if (xatom
->getValue(client
.window
, XAtom::net_wm_icon_name
,
1147 XAtom::utf8
, client
.icon_title
) &&
1148 !client
.icon_title
.empty()) {
1149 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1152 //fall through to using WM_ICON_NAME
1153 if (xatom
->getValue(client
.window
, XAtom::wm_icon_name
, XAtom::ansi
,
1154 client
.icon_title
) &&
1155 !client
.icon_title
.empty()) {
1156 xatom
->eraseValue(client
.window
, XAtom::net_wm_visible_icon_name
);
1159 // fall back to using the main name
1160 client
.icon_title
= client
.title
;
1161 xatom
->setValue(client
.window
, XAtom::net_wm_visible_icon_name
, XAtom::utf8
,
1167 * Retrieve which WM Protocols are supported by the client window.
1168 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
1169 * window's decorations and allow the close behavior.
1170 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
1173 void BlackboxWindow::getWMProtocols(void) {
1177 if (XGetWMProtocols(otk::OBDisplay::display
, client
.window
,
1178 &proto
, &num_return
)) {
1179 for (int i
= 0; i
< num_return
; ++i
) {
1180 if (proto
[i
] == xatom
->getAtom(XAtom::wm_delete_window
)) {
1181 decorations
|= Decor_Close
;
1182 functions
|= Func_Close
;
1183 } else if (proto
[i
] == xatom
->getAtom(XAtom::wm_take_focus
))
1184 flags
.send_focus_message
= True
;
1193 * Gets the value of the WM_HINTS property.
1194 * If the property is not set, then use a set of default values.
1196 void BlackboxWindow::getWMHints(void) {
1197 focus_mode
= F_Passive
;
1199 // remove from current window group
1200 if (client
.window_group
) {
1201 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1202 if (group
) group
->removeWindow(this);
1204 client
.window_group
= None
;
1206 XWMHints
*wmhint
= XGetWMHints(otk::OBDisplay::display
, client
.window
);
1211 if (wmhint
->flags
& InputHint
) {
1212 if (wmhint
->input
== True
) {
1213 if (flags
.send_focus_message
)
1214 focus_mode
= F_LocallyActive
;
1216 if (flags
.send_focus_message
)
1217 focus_mode
= F_GloballyActive
;
1219 focus_mode
= F_NoInput
;
1223 if (wmhint
->flags
& StateHint
)
1224 current_state
= wmhint
->initial_state
;
1226 if (wmhint
->flags
& WindowGroupHint
) {
1227 client
.window_group
= wmhint
->window_group
;
1229 // add window to the appropriate group
1230 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1231 if (! group
) { // no group found, create it!
1232 new BWindowGroup(blackbox
, client
.window_group
);
1233 group
= blackbox
->searchGroup(client
.window_group
);
1236 group
->addWindow(this);
1244 * Gets the value of the WM_NORMAL_HINTS property.
1245 * If the property is not set, then use a set of default values.
1247 void BlackboxWindow::getWMNormalHints(void) {
1249 XSizeHints sizehint
;
1251 client
.min_width
= client
.min_height
=
1252 client
.width_inc
= client
.height_inc
= 1;
1253 client
.base_width
= client
.base_height
= 0;
1254 client
.win_gravity
= NorthWestGravity
;
1256 client
.min_aspect_x
= client
.min_aspect_y
=
1257 client
.max_aspect_x
= client
.max_aspect_y
= 1;
1260 // don't limit the size of a window, the default max width is the biggest
1262 client
.max_width
= (unsigned) -1;
1263 client
.max_height
= (unsigned) -1;
1266 if (! XGetWMNormalHints(otk::OBDisplay::display
, client
.window
,
1267 &sizehint
, &icccm_mask
))
1270 client
.normal_hint_flags
= sizehint
.flags
;
1272 if (sizehint
.flags
& PMinSize
) {
1273 if (sizehint
.min_width
>= 0)
1274 client
.min_width
= sizehint
.min_width
;
1275 if (sizehint
.min_height
>= 0)
1276 client
.min_height
= sizehint
.min_height
;
1279 if (sizehint
.flags
& PMaxSize
) {
1280 if (sizehint
.max_width
> static_cast<signed>(client
.min_width
))
1281 client
.max_width
= sizehint
.max_width
;
1283 client
.max_width
= client
.min_width
;
1285 if (sizehint
.max_height
> static_cast<signed>(client
.min_height
))
1286 client
.max_height
= sizehint
.max_height
;
1288 client
.max_height
= client
.min_height
;
1291 if (sizehint
.flags
& PResizeInc
) {
1292 client
.width_inc
= sizehint
.width_inc
;
1293 client
.height_inc
= sizehint
.height_inc
;
1296 #if 0 // we do not support this at the moment
1297 if (sizehint
.flags
& PAspect
) {
1298 client
.min_aspect_x
= sizehint
.min_aspect
.x
;
1299 client
.min_aspect_y
= sizehint
.min_aspect
.y
;
1300 client
.max_aspect_x
= sizehint
.max_aspect
.x
;
1301 client
.max_aspect_y
= sizehint
.max_aspect
.y
;
1305 if (sizehint
.flags
& PBaseSize
) {
1306 client
.base_width
= sizehint
.base_width
;
1307 client
.base_height
= sizehint
.base_height
;
1310 if (sizehint
.flags
& PWinGravity
)
1311 client
.win_gravity
= sizehint
.win_gravity
;
1316 * Gets the NETWM hints for the class' contained window.
1318 void BlackboxWindow::getNetWMHints(void) {
1319 unsigned long workspace
;
1321 if (xatom
->getValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
1323 if (workspace
== 0xffffffff)
1326 blackbox_attrib
.workspace
= workspace
;
1329 unsigned long *state
;
1330 unsigned long num
= (unsigned) -1;
1331 if (xatom
->getValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
1335 for (unsigned long i
= 0; i
< num
; ++i
) {
1336 if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_modal
))
1338 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_shaded
))
1339 flags
.shaded
= True
;
1340 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
))
1341 flags
.skip_taskbar
= True
;
1342 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_skip_pager
))
1343 flags
.skip_pager
= True
;
1344 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_fullscreen
))
1345 flags
.fullscreen
= True
;
1346 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_hidden
))
1347 setState(IconicState
);
1348 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_vert
))
1350 else if (state
[i
] == xatom
->getAtom(XAtom::net_wm_state_maximized_horz
))
1354 flags
.maximized
= 1;
1356 flags
.maximized
= 2;
1358 flags
.maximized
= 3;
1366 * Gets the MWM hints for the class' contained window.
1367 * This is used while initializing the window to its first state, and not
1369 * Returns: true if the MWM hints are successfully retreived and applied;
1370 * false if they are not.
1372 void BlackboxWindow::getMWMHints(void) {
1376 num
= PropMwmHintsElements
;
1377 if (! xatom
->getValue(client
.window
, XAtom::motif_wm_hints
,
1378 XAtom::motif_wm_hints
, num
,
1379 (unsigned long **)&mwm_hint
))
1381 if (num
< PropMwmHintsElements
) {
1386 if (mwm_hint
->flags
& MwmHintsDecorations
) {
1387 if (mwm_hint
->decorations
& MwmDecorAll
) {
1388 mwm_decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
1389 Decor_Iconify
| Decor_Maximize
;
1391 mwm_decorations
= 0;
1393 if (mwm_hint
->decorations
& MwmDecorBorder
)
1394 mwm_decorations
|= Decor_Border
;
1395 if (mwm_hint
->decorations
& MwmDecorHandle
)
1396 mwm_decorations
|= Decor_Handle
;
1397 if (mwm_hint
->decorations
& MwmDecorTitle
)
1398 mwm_decorations
|= Decor_Titlebar
;
1399 if (mwm_hint
->decorations
& MwmDecorIconify
)
1400 mwm_decorations
|= Decor_Iconify
;
1401 if (mwm_hint
->decorations
& MwmDecorMaximize
)
1402 mwm_decorations
|= Decor_Maximize
;
1406 if (mwm_hint
->flags
& MwmHintsFunctions
) {
1407 if (mwm_hint
->functions
& MwmFuncAll
) {
1408 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
|
1413 if (mwm_hint
->functions
& MwmFuncResize
)
1414 functions
|= Func_Resize
;
1415 if (mwm_hint
->functions
& MwmFuncMove
)
1416 functions
|= Func_Move
;
1417 if (mwm_hint
->functions
& MwmFuncIconify
)
1418 functions
|= Func_Iconify
;
1419 if (mwm_hint
->functions
& MwmFuncMaximize
)
1420 functions
|= Func_Maximize
;
1421 if (mwm_hint
->functions
& MwmFuncClose
)
1422 functions
|= Func_Close
;
1430 * Gets the blackbox hints from the class' contained window.
1431 * This is used while initializing the window to its first state, and not
1433 * Returns: true if the hints are successfully retreived and applied; false if
1436 bool BlackboxWindow::getBlackboxHints(void) {
1438 BlackboxHints
*blackbox_hint
;
1440 num
= PropBlackboxHintsElements
;
1441 if (! xatom
->getValue(client
.window
, XAtom::blackbox_hints
,
1442 XAtom::blackbox_hints
, num
,
1443 (unsigned long **)&blackbox_hint
))
1445 if (num
< PropBlackboxHintsElements
) {
1446 delete [] blackbox_hint
;
1450 if (blackbox_hint
->flags
& AttribShaded
)
1451 flags
.shaded
= (blackbox_hint
->attrib
& AttribShaded
);
1453 if ((blackbox_hint
->flags
& AttribMaxHoriz
) &&
1454 (blackbox_hint
->flags
& AttribMaxVert
))
1455 flags
.maximized
= (blackbox_hint
->attrib
&
1456 (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1457 else if (blackbox_hint
->flags
& AttribMaxVert
)
1458 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxVert
) ? 2 : 0;
1459 else if (blackbox_hint
->flags
& AttribMaxHoriz
)
1460 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1462 if (blackbox_hint
->flags
& AttribOmnipresent
)
1463 flags
.stuck
= (blackbox_hint
->attrib
& AttribOmnipresent
);
1465 if (blackbox_hint
->flags
& AttribWorkspace
)
1466 blackbox_attrib
.workspace
= blackbox_hint
->workspace
;
1468 // if (blackbox_hint->flags & AttribStack)
1469 // don't yet have always on top/bottom for blackbox yet... working
1472 if (blackbox_hint
->flags
& AttribDecoration
) {
1473 switch (blackbox_hint
->decoration
) {
1475 blackbox_attrib
.decoration
= DecorNone
;
1482 // blackbox_attrib.decoration defaults to DecorNormal
1487 delete [] blackbox_hint
;
1493 void BlackboxWindow::getTransientInfo(void) {
1494 if (client
.transient_for
&&
1495 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1496 // reset transient_for in preparation of looking for a new owner
1497 client
.transient_for
->client
.transientList
.remove(this);
1500 // we have no transient_for until we find a new one
1501 client
.transient_for
= (BlackboxWindow
*) 0;
1504 if (! XGetTransientForHint(otk::OBDisplay::display
, client
.window
,
1506 // transient_for hint not set
1510 if (trans_for
== client
.window
) {
1511 // wierd client... treat this window as a normal window
1515 if (trans_for
== None
|| trans_for
== screen
->getRootWindow()) {
1516 // this is an undocumented interpretation of the ICCCM. a transient
1517 // associated with None/Root/itself is assumed to be a modal root
1518 // transient. we don't support the concept of a global transient,
1519 // so we just associate this transient with nothing, and perhaps
1520 // we will add support later for global modality.
1521 client
.transient_for
= (BlackboxWindow
*) ~0ul;
1526 client
.transient_for
= blackbox
->searchWindow(trans_for
);
1527 if (! client
.transient_for
&&
1528 client
.window_group
&& trans_for
== client
.window_group
) {
1529 // no direct transient_for, perhaps this is a group transient?
1530 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1531 if (group
) client
.transient_for
= group
->find(screen
);
1534 if (! client
.transient_for
|| client
.transient_for
== this) {
1535 // no transient_for found, or we have a wierd client that wants to be
1536 // a transient for itself, so we treat this window as a normal window
1537 client
.transient_for
= (BlackboxWindow
*) 0;
1541 // Check for a circular transient state: this can lock up Blackbox
1542 // when it tries to find the non-transient window for a transient.
1543 BlackboxWindow
*w
= this;
1544 while(w
->client
.transient_for
&&
1545 w
->client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1546 if(w
->client
.transient_for
== this) {
1547 client
.transient_for
= (BlackboxWindow
*) 0;
1550 w
= w
->client
.transient_for
;
1553 if (client
.transient_for
&&
1554 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1555 // register ourselves with our new transient_for
1556 client
.transient_for
->client
.transientList
.push_back(this);
1557 flags
.stuck
= client
.transient_for
->flags
.stuck
;
1562 BlackboxWindow
*BlackboxWindow::getTransientFor(void) const {
1563 if (client
.transient_for
&&
1564 client
.transient_for
!= (BlackboxWindow
*) ~0ul)
1565 return client
.transient_for
;
1571 * This function is responsible for updating both the client and the frame
1573 * According to the ICCCM a client message is not sent for a resize, only a
1576 void BlackboxWindow::configure(int dx
, int dy
,
1577 unsigned int dw
, unsigned int dh
) {
1578 bool send_event
= ((frame
.rect
.x() != dx
|| frame
.rect
.y() != dy
) &&
1581 if (dw
!= frame
.rect
.width() || dh
!= frame
.rect
.height()) {
1582 frame
.rect
.setRect(dx
, dy
, dw
, dh
);
1583 frame
.inside_w
= frame
.rect
.width() - (frame
.border_w
* 2);
1584 frame
.inside_h
= frame
.rect
.height() - (frame
.border_w
* 2);
1586 if (frame
.rect
.right() <= 0 || frame
.rect
.bottom() <= 0)
1587 frame
.rect
.setPos(0, 0);
1589 client
.rect
.setCoords(frame
.rect
.left() + frame
.margin
.left
,
1590 frame
.rect
.top() + frame
.margin
.top
,
1591 frame
.rect
.right() - frame
.margin
.right
,
1592 frame
.rect
.bottom() - frame
.margin
.bottom
);
1595 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
1602 redrawWindowFrame();
1604 frame
.rect
.setPos(dx
, dy
);
1606 XMoveWindow(otk::OBDisplay::display
, frame
.window
,
1607 frame
.rect
.x(), frame
.rect
.y());
1609 we may have been called just after an opaque window move, so even though
1610 the old coords match the new ones no ConfigureNotify has been sent yet.
1611 There are likely other times when this will be relevant as well.
1613 if (! flags
.moving
) send_event
= True
;
1617 // if moving, the update and event will occur when the move finishes
1618 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1619 frame
.rect
.top() + frame
.margin
.top
);
1622 event
.type
= ConfigureNotify
;
1624 event
.xconfigure
.display
= otk::OBDisplay::display
;
1625 event
.xconfigure
.event
= client
.window
;
1626 event
.xconfigure
.window
= client
.window
;
1627 event
.xconfigure
.x
= client
.rect
.x();
1628 event
.xconfigure
.y
= client
.rect
.y();
1629 event
.xconfigure
.width
= client
.rect
.width();
1630 event
.xconfigure
.height
= client
.rect
.height();
1631 event
.xconfigure
.border_width
= client
.old_bw
;
1632 event
.xconfigure
.above
= frame
.window
;
1633 event
.xconfigure
.override_redirect
= False
;
1635 XSendEvent(otk::OBDisplay::display
, client
.window
, False
,
1636 StructureNotifyMask
, &event
);
1637 XFlush(otk::OBDisplay::display
);
1643 void BlackboxWindow::configureShape(void) {
1644 XShapeCombineShape(otk::OBDisplay::display
, frame
.window
, ShapeBounding
,
1645 frame
.margin
.left
- frame
.border_w
,
1646 frame
.margin
.top
- frame
.border_w
,
1647 client
.window
, ShapeBounding
, ShapeSet
);
1650 XRectangle xrect
[2];
1652 if (decorations
& Decor_Titlebar
) {
1653 xrect
[0].x
= xrect
[0].y
= -frame
.border_w
;
1654 xrect
[0].width
= frame
.rect
.width();
1655 xrect
[0].height
= frame
.title_h
+ (frame
.border_w
* 2);
1659 if (decorations
& Decor_Handle
) {
1660 xrect
[1].x
= -frame
.border_w
;
1661 xrect
[1].y
= frame
.rect
.height() - frame
.margin
.bottom
+
1662 frame
.mwm_border_w
- frame
.border_w
;
1663 xrect
[1].width
= frame
.rect
.width();
1664 xrect
[1].height
= frame
.handle_h
+ (frame
.border_w
* 2);
1668 XShapeCombineRectangles(otk::OBDisplay::display
, frame
.window
,
1669 ShapeBounding
, 0, 0, xrect
, num
,
1670 ShapeUnion
, Unsorted
);
1674 void BlackboxWindow::clearShape(void) {
1675 XShapeCombineMask(otk::OBDisplay::display
, frame
.window
, ShapeBounding
,
1676 frame
.margin
.left
- frame
.border_w
,
1677 frame
.margin
.top
- frame
.border_w
,
1683 bool BlackboxWindow::setInputFocus(void) {
1684 if (flags
.focused
) return True
;
1686 assert(flags
.stuck
|| // window must be on the current workspace or sticky
1687 blackbox_attrib
.workspace
== screen
->getCurrentWorkspaceID());
1690 We only do this check for normal windows and dialogs because other windows
1691 do this on purpose, such as kde's kicker, and we don't want to go moving
1694 if (window_type
== Type_Normal
|| window_type
== Type_Dialog
)
1695 if (! frame
.rect
.intersects(screen
->getRect())) {
1696 // client is outside the screen, move it to the center
1697 configure((screen
->getWidth() - frame
.rect
.width()) / 2,
1698 (screen
->getHeight() - frame
.rect
.height()) / 2,
1699 frame
.rect
.width(), frame
.rect
.height());
1702 if (client
.transientList
.size() > 0) {
1703 // transfer focus to any modal transients
1704 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1705 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1706 if ((*it
)->flags
.modal
) return (*it
)->setInputFocus();
1710 if (focus_mode
== F_LocallyActive
|| focus_mode
== F_Passive
) {
1711 XSetInputFocus(otk::OBDisplay::display
, client
.window
,
1712 RevertToPointerRoot
, CurrentTime
);
1714 /* we could set the focus to none, since the window doesn't accept focus,
1715 * but we shouldn't set focus to nothing since this would surely make
1721 if (flags
.send_focus_message
) {
1723 ce
.xclient
.type
= ClientMessage
;
1724 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1725 ce
.xclient
.display
= otk::OBDisplay::display
;
1726 ce
.xclient
.window
= client
.window
;
1727 ce
.xclient
.format
= 32;
1728 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_take_focus
);
1729 ce
.xclient
.data
.l
[1] = blackbox
->getLastTime();
1730 ce
.xclient
.data
.l
[2] = 0l;
1731 ce
.xclient
.data
.l
[3] = 0l;
1732 ce
.xclient
.data
.l
[4] = 0l;
1733 XSendEvent(otk::OBDisplay::display
, client
.window
, False
,
1735 XFlush(otk::OBDisplay::display
);
1742 void BlackboxWindow::iconify(void) {
1743 if (flags
.iconic
|| ! (functions
& Func_Iconify
)) return;
1745 // We don't need to worry about resizing because resizing always grabs the X
1746 // server. This should only ever happen if using opaque moving.
1751 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1752 * we need to clear the event mask on client.window for a split second.
1753 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1754 * split second, leaving us with a ghost window... so, we need to do this
1755 * while the X server is grabbed
1757 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1758 StructureNotifyMask
;
1759 XGrabServer(otk::OBDisplay::display
);
1760 XSelectInput(otk::OBDisplay::display
, client
.window
,
1761 event_mask
& ~StructureNotifyMask
);
1762 XUnmapWindow(otk::OBDisplay::display
, client
.window
);
1763 XSelectInput(otk::OBDisplay::display
, client
.window
, event_mask
);
1764 XUngrabServer(otk::OBDisplay::display
);
1766 XUnmapWindow(otk::OBDisplay::display
, frame
.window
);
1767 flags
.visible
= False
;
1768 flags
.iconic
= True
;
1770 setState(IconicState
);
1772 screen
->getWorkspace(blackbox_attrib
.workspace
)->removeWindow(this);
1774 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
1775 if (i
!= blackbox_attrib
.workspace
)
1776 screen
->getWorkspace(i
)->removeWindow(this, True
);
1779 if (isTransient()) {
1780 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1781 ! client
.transient_for
->flags
.iconic
) {
1782 // iconify our transient_for
1783 client
.transient_for
->iconify();
1787 screen
->addIcon(this);
1789 if (client
.transientList
.size() > 0) {
1790 // iconify all transients
1791 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1792 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1793 if (! (*it
)->flags
.iconic
) (*it
)->iconify();
1796 screen
->updateStackingList();
1800 void BlackboxWindow::show(void) {
1801 flags
.visible
= True
;
1802 flags
.iconic
= False
;
1804 current_state
= (flags
.shaded
) ? IconicState
: NormalState
;
1805 setState(current_state
);
1807 XMapWindow(otk::OBDisplay::display
, client
.window
);
1808 XMapSubwindows(otk::OBDisplay::display
, frame
.window
);
1809 XMapWindow(otk::OBDisplay::display
, frame
.window
);
1814 XTranslateCoordinates(otk::OBDisplay::display
, client
.window
,
1815 screen
->getRootWindow(),
1816 0, 0, &real_x
, &real_y
, &child
);
1817 fprintf(stderr
, "%s -- assumed: (%d, %d), real: (%d, %d)\n", getTitle(),
1818 client
.rect
.left(), client
.rect
.top(), real_x
, real_y
);
1819 assert(client
.rect
.left() == real_x
&& client
.rect
.top() == real_y
);
1824 void BlackboxWindow::deiconify(bool reassoc
, bool raise
) {
1825 if (flags
.iconic
|| reassoc
)
1826 screen
->reassociateWindow(this, BSENTINEL
, False
);
1827 else if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID())
1832 // reassociate and deiconify all transients
1833 if (reassoc
&& client
.transientList
.size() > 0) {
1834 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1835 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1836 (*it
)->deiconify(True
, False
);
1840 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1844 void BlackboxWindow::close(void) {
1845 if (! (functions
& Func_Close
)) return;
1848 ce
.xclient
.type
= ClientMessage
;
1849 ce
.xclient
.message_type
= xatom
->getAtom(XAtom::wm_protocols
);
1850 ce
.xclient
.display
= otk::OBDisplay::display
;
1851 ce
.xclient
.window
= client
.window
;
1852 ce
.xclient
.format
= 32;
1853 ce
.xclient
.data
.l
[0] = xatom
->getAtom(XAtom::wm_delete_window
);
1854 ce
.xclient
.data
.l
[1] = CurrentTime
;
1855 ce
.xclient
.data
.l
[2] = 0l;
1856 ce
.xclient
.data
.l
[3] = 0l;
1857 ce
.xclient
.data
.l
[4] = 0l;
1858 XSendEvent(otk::OBDisplay::display
, client
.window
, False
, NoEventMask
, &ce
);
1859 XFlush(otk::OBDisplay::display
);
1863 void BlackboxWindow::withdraw(void) {
1864 // We don't need to worry about resizing because resizing always grabs the X
1865 // server. This should only ever happen if using opaque moving.
1869 flags
.visible
= False
;
1870 flags
.iconic
= False
;
1872 setState(current_state
);
1874 XUnmapWindow(otk::OBDisplay::display
, frame
.window
);
1876 XGrabServer(otk::OBDisplay::display
);
1878 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1879 StructureNotifyMask
;
1880 XSelectInput(otk::OBDisplay::display
, client
.window
,
1881 event_mask
& ~StructureNotifyMask
);
1882 XUnmapWindow(otk::OBDisplay::display
, client
.window
);
1883 XSelectInput(otk::OBDisplay::display
, client
.window
, event_mask
);
1885 XUngrabServer(otk::OBDisplay::display
);
1889 void BlackboxWindow::maximize(unsigned int button
) {
1890 if (! (functions
& Func_Maximize
)) return;
1892 // We don't need to worry about resizing because resizing always grabs the X
1893 // server. This should only ever happen if using opaque moving.
1897 if (flags
.maximized
) {
1898 flags
.maximized
= 0;
1900 blackbox_attrib
.flags
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1901 blackbox_attrib
.attrib
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1904 when a resize finishes, maximize(0) is called to clear any maximization
1905 flags currently set. Otherwise it still thinks it is maximized.
1906 so we do not need to call configure() because resizing will handle it
1908 if (! flags
.resizing
)
1909 configure(blackbox_attrib
.premax_x
, blackbox_attrib
.premax_y
,
1910 blackbox_attrib
.premax_w
, blackbox_attrib
.premax_h
);
1912 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
1913 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
1915 redrawAllButtons(); // in case it is not called in configure()
1916 setState(current_state
);
1920 blackbox_attrib
.premax_x
= frame
.rect
.x();
1921 blackbox_attrib
.premax_y
= frame
.rect
.y();
1922 blackbox_attrib
.premax_w
= frame
.rect
.width();
1923 // use client.rect so that clients can be restored even if shaded
1924 blackbox_attrib
.premax_h
=
1925 client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
;
1928 if (screen
->isXineramaActive() && blackbox
->doXineramaMaximizing()) {
1929 // find the area to use
1930 RectList availableAreas
= screen
->allAvailableAreas();
1931 RectList::iterator it
, end
= availableAreas
.end();
1933 for (it
= availableAreas
.begin(); it
!= end
; ++it
)
1934 if (it
->intersects(frame
.rect
)) break;
1935 if (it
== end
) // the window isn't inside an area
1936 it
= availableAreas
.begin(); // so just default to the first one
1938 frame
.changing
= *it
;
1941 frame
.changing
= screen
->availableArea();
1945 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1946 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1950 blackbox_attrib
.flags
|= AttribMaxVert
;
1951 blackbox_attrib
.attrib
|= AttribMaxVert
;
1953 frame
.changing
.setX(frame
.rect
.x());
1954 frame
.changing
.setWidth(frame
.rect
.width());
1958 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1959 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1961 frame
.changing
.setY(frame
.rect
.y());
1962 frame
.changing
.setHeight(frame
.rect
.height());
1969 blackbox_attrib
.flags
^= AttribShaded
;
1970 blackbox_attrib
.attrib
^= AttribShaded
;
1971 flags
.shaded
= False
;
1974 flags
.maximized
= button
;
1976 configure(frame
.changing
.x(), frame
.changing
.y(),
1977 frame
.changing
.width(), frame
.changing
.height());
1979 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1980 redrawAllButtons(); // in case it is not called in configure()
1981 setState(current_state
);
1985 // re-maximizes the window to take into account availableArea changes
1986 void BlackboxWindow::remaximize(void) {
1988 // we only update the window's attributes otherwise we lose the shade bit
1989 switch(flags
.maximized
) {
1991 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1992 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1996 blackbox_attrib
.flags
|= AttribMaxVert
;
1997 blackbox_attrib
.attrib
|= AttribMaxVert
;
2001 blackbox_attrib
.flags
|= AttribMaxHoriz
;
2002 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
2008 // save the original dimensions because maximize will wipe them out
2009 int premax_x
= blackbox_attrib
.premax_x
,
2010 premax_y
= blackbox_attrib
.premax_y
,
2011 premax_w
= blackbox_attrib
.premax_w
,
2012 premax_h
= blackbox_attrib
.premax_h
;
2014 unsigned int button
= flags
.maximized
;
2015 flags
.maximized
= 0; // trick maximize() into working
2018 // restore saved values
2019 blackbox_attrib
.premax_x
= premax_x
;
2020 blackbox_attrib
.premax_y
= premax_y
;
2021 blackbox_attrib
.premax_w
= premax_w
;
2022 blackbox_attrib
.premax_h
= premax_h
;
2026 void BlackboxWindow::setWorkspace(unsigned int n
) {
2027 blackbox_attrib
.flags
|= AttribWorkspace
;
2028 blackbox_attrib
.workspace
= n
;
2029 if (n
== BSENTINEL
) { // iconified window
2031 we set the workspace to 'all workspaces' so that taskbars will show the
2032 window. otherwise, it made uniconifying a window imposible without the
2033 blackbox workspace menu
2037 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
, n
);
2041 void BlackboxWindow::shade(void) {
2043 XResizeWindow(otk::OBDisplay::display
, frame
.window
,
2044 frame
.inside_w
, frame
.inside_h
);
2045 flags
.shaded
= False
;
2046 blackbox_attrib
.flags
^= AttribShaded
;
2047 blackbox_attrib
.attrib
^= AttribShaded
;
2049 setState(NormalState
);
2051 // set the frame rect to the normal size
2052 frame
.rect
.setHeight(client
.rect
.height() + frame
.margin
.top
+
2053 frame
.margin
.bottom
);
2055 if (! (decorations
& Decor_Titlebar
))
2056 return; // can't shade it without a titlebar!
2058 XResizeWindow(otk::OBDisplay::display
, frame
.window
,
2059 frame
.inside_w
, frame
.title_h
);
2060 flags
.shaded
= True
;
2061 blackbox_attrib
.flags
|= AttribShaded
;
2062 blackbox_attrib
.attrib
|= AttribShaded
;
2064 setState(IconicState
);
2066 // set the frame rect to the shaded size
2067 frame
.rect
.setHeight(frame
.title_h
+ (frame
.border_w
* 2));
2073 * (Un)Sticks a window and its relatives.
2075 void BlackboxWindow::stick(void) {
2077 blackbox_attrib
.flags
^= AttribOmnipresent
;
2078 blackbox_attrib
.attrib
^= AttribOmnipresent
;
2080 flags
.stuck
= False
;
2082 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
2083 if (i
!= blackbox_attrib
.workspace
)
2084 screen
->getWorkspace(i
)->removeWindow(this, True
);
2087 screen
->reassociateWindow(this, BSENTINEL
, True
);
2088 // temporary fix since sticky windows suck. set the hint to what we
2089 // actually hold in our data.
2090 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
2091 blackbox_attrib
.workspace
);
2093 setState(current_state
);
2097 blackbox_attrib
.flags
|= AttribOmnipresent
;
2098 blackbox_attrib
.attrib
|= AttribOmnipresent
;
2100 // temporary fix since sticky windows suck. set the hint to a different
2101 // value than that contained in the class' data.
2102 xatom
->setValue(client
.window
, XAtom::net_wm_desktop
, XAtom::cardinal
,
2105 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
2106 if (i
!= blackbox_attrib
.workspace
)
2107 screen
->getWorkspace(i
)->addWindow(this, False
, True
);
2109 setState(current_state
);
2115 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
2116 client
.transient_for
->isStuck() != flags
.stuck
)
2117 client
.transient_for
->stick();
2118 // go down the chain
2119 BlackboxWindowList::iterator it
;
2120 const BlackboxWindowList::iterator end
= client
.transientList
.end();
2121 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
2122 if ((*it
)->isStuck() != flags
.stuck
)
2127 void BlackboxWindow::redrawWindowFrame(void) const {
2128 if (decorations
& Decor_Titlebar
) {
2129 if (flags
.focused
) {
2131 XSetWindowBackgroundPixmap(otk::OBDisplay::display
,
2132 frame
.title
, frame
.ftitle
);
2134 XSetWindowBackground(otk::OBDisplay::display
,
2135 frame
.title
, frame
.ftitle_pixel
);
2138 XSetWindowBackgroundPixmap(otk::OBDisplay::display
,
2139 frame
.title
, frame
.utitle
);
2141 XSetWindowBackground(otk::OBDisplay::display
,
2142 frame
.title
, frame
.utitle_pixel
);
2144 XClearWindow(otk::OBDisplay::display
, frame
.title
);
2150 if (decorations
& Decor_Handle
) {
2151 if (flags
.focused
) {
2153 XSetWindowBackgroundPixmap(otk::OBDisplay::display
,
2154 frame
.handle
, frame
.fhandle
);
2156 XSetWindowBackground(otk::OBDisplay::display
,
2157 frame
.handle
, frame
.fhandle_pixel
);
2160 XSetWindowBackgroundPixmap(otk::OBDisplay::display
,
2161 frame
.left_grip
, frame
.fgrip
);
2162 XSetWindowBackgroundPixmap(otk::OBDisplay::display
,
2163 frame
.right_grip
, frame
.fgrip
);
2165 XSetWindowBackground(otk::OBDisplay::display
,
2166 frame
.left_grip
, frame
.fgrip_pixel
);
2167 XSetWindowBackground(otk::OBDisplay::display
,
2168 frame
.right_grip
, frame
.fgrip_pixel
);
2172 XSetWindowBackgroundPixmap(otk::OBDisplay::display
,
2173 frame
.handle
, frame
.uhandle
);
2175 XSetWindowBackground(otk::OBDisplay::display
,
2176 frame
.handle
, frame
.uhandle_pixel
);
2179 XSetWindowBackgroundPixmap(otk::OBDisplay::display
,
2180 frame
.left_grip
, frame
.ugrip
);
2181 XSetWindowBackgroundPixmap(otk::OBDisplay::display
,
2182 frame
.right_grip
, frame
.ugrip
);
2184 XSetWindowBackground(otk::OBDisplay::display
,
2185 frame
.left_grip
, frame
.ugrip_pixel
);
2186 XSetWindowBackground(otk::OBDisplay::display
,
2187 frame
.right_grip
, frame
.ugrip_pixel
);
2190 XClearWindow(otk::OBDisplay::display
, frame
.handle
);
2191 XClearWindow(otk::OBDisplay::display
, frame
.left_grip
);
2192 XClearWindow(otk::OBDisplay::display
, frame
.right_grip
);
2195 if (decorations
& Decor_Border
) {
2197 XSetWindowBorder(otk::OBDisplay::display
,
2198 frame
.plate
, frame
.fborder_pixel
);
2200 XSetWindowBorder(otk::OBDisplay::display
,
2201 frame
.plate
, frame
.uborder_pixel
);
2206 void BlackboxWindow::setFocusFlag(bool focus
) {
2207 // only focus a window if it is visible
2208 if (focus
&& ! flags
.visible
)
2211 flags
.focused
= focus
;
2213 redrawWindowFrame();
2216 blackbox
->setFocusedWindow(this);
2220 void BlackboxWindow::installColormap(bool install
) {
2221 int i
= 0, ncmap
= 0;
2222 Colormap
*cmaps
= XListInstalledColormaps(otk::OBDisplay::display
,
2223 client
.window
, &ncmap
);
2225 XWindowAttributes wattrib
;
2226 if (XGetWindowAttributes(otk::OBDisplay::display
,
2227 client
.window
, &wattrib
)) {
2229 // install the window's colormap
2230 for (i
= 0; i
< ncmap
; i
++) {
2231 if (*(cmaps
+ i
) == wattrib
.colormap
)
2232 // this window is using an installed color map... do not install
2235 // otherwise, install the window's colormap
2237 XInstallColormap(otk::OBDisplay::display
, wattrib
.colormap
);
2239 // uninstall the window's colormap
2240 for (i
= 0; i
< ncmap
; i
++) {
2241 if (*(cmaps
+ i
) == wattrib
.colormap
)
2242 // we found the colormap to uninstall
2243 XUninstallColormap(otk::OBDisplay::display
, wattrib
.colormap
);
2253 void BlackboxWindow::setAllowedActions(void) {
2257 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_shade
);
2258 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_change_desktop
);
2259 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_close
);
2261 if (functions
& Func_Move
)
2262 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_move
);
2263 if (functions
& Func_Resize
)
2264 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_resize
);
2265 if (functions
& Func_Maximize
) {
2266 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_horz
);
2267 actions
[num
++] = xatom
->getAtom(XAtom::net_wm_action_maximize_vert
);
2270 xatom
->setValue(client
.window
, XAtom::net_wm_allowed_actions
, XAtom::atom
,
2275 void BlackboxWindow::setState(unsigned long new_state
) {
2276 current_state
= new_state
;
2278 unsigned long state
[2];
2279 state
[0] = current_state
;
2281 xatom
->setValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
, state
, 2);
2283 xatom
->setValue(client
.window
, XAtom::blackbox_attributes
,
2284 XAtom::blackbox_attributes
, (unsigned long *)&blackbox_attrib
,
2285 PropBlackboxAttributesElements
);
2290 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_modal
);
2292 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_shaded
);
2294 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_hidden
);
2295 if (flags
.skip_taskbar
)
2296 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_taskbar
);
2297 if (flags
.skip_pager
)
2298 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_skip_pager
);
2299 if (flags
.fullscreen
)
2300 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_fullscreen
);
2301 if (flags
.maximized
== 1 || flags
.maximized
== 2)
2302 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_vert
);
2303 if (flags
.maximized
== 1 || flags
.maximized
== 3)
2304 netstate
[num
++] = xatom
->getAtom(XAtom::net_wm_state_maximized_horz
);
2305 xatom
->setValue(client
.window
, XAtom::net_wm_state
, XAtom::atom
,
2310 bool BlackboxWindow::getState(void) {
2311 bool ret
= xatom
->getValue(client
.window
, XAtom::wm_state
, XAtom::wm_state
,
2313 if (! ret
) current_state
= 0;
2318 void BlackboxWindow::restoreAttributes(void) {
2319 unsigned long num
= PropBlackboxAttributesElements
;
2320 BlackboxAttributes
*net
;
2321 if (! xatom
->getValue(client
.window
, XAtom::blackbox_attributes
,
2322 XAtom::blackbox_attributes
, num
,
2323 (unsigned long **)&net
))
2325 if (num
< PropBlackboxAttributesElements
) {
2330 if (net
->flags
& AttribShaded
&& net
->attrib
& AttribShaded
) {
2331 flags
.shaded
= False
;
2332 unsigned long orig_state
= current_state
;
2336 At this point in the life of a window, current_state should only be set
2337 to IconicState if the window was an *icon*, not if it was shaded.
2339 if (orig_state
!= IconicState
)
2340 current_state
= WithdrawnState
;
2343 if (net
->workspace
!= screen
->getCurrentWorkspaceID() &&
2344 net
->workspace
< screen
->getWorkspaceCount())
2345 screen
->reassociateWindow(this, net
->workspace
, True
);
2347 if ((blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID()) &&
2348 (blackbox_attrib
.workspace
< screen
->getWorkspaceCount())) {
2349 // set to WithdrawnState so it will be mapped on the new workspace
2350 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2351 } else if (current_state
== WithdrawnState
) {
2352 // the window is on this workspace and is Withdrawn, so it is waiting to
2354 current_state
= NormalState
;
2357 if (net
->flags
& AttribOmnipresent
&& net
->attrib
& AttribOmnipresent
&&
2361 // if the window was on another workspace, it was going to be hidden. this
2362 // specifies that the window should be mapped since it is sticky.
2363 if (current_state
== WithdrawnState
) current_state
= NormalState
;
2366 if (net
->flags
& AttribMaxHoriz
|| net
->flags
& AttribMaxVert
) {
2367 int x
= net
->premax_x
, y
= net
->premax_y
;
2368 unsigned int w
= net
->premax_w
, h
= net
->premax_h
;
2369 flags
.maximized
= 0;
2372 if ((net
->flags
& AttribMaxHoriz
) &&
2373 (net
->flags
& AttribMaxVert
))
2374 m
= (net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
2375 else if (net
->flags
& AttribMaxVert
)
2376 m
= (net
->attrib
& AttribMaxVert
) ? 2 : 0;
2377 else if (net
->flags
& AttribMaxHoriz
)
2378 m
= (net
->attrib
& AttribMaxHoriz
) ? 3 : 0;
2382 blackbox_attrib
.premax_x
= x
;
2383 blackbox_attrib
.premax_y
= y
;
2384 blackbox_attrib
.premax_w
= w
;
2385 blackbox_attrib
.premax_h
= h
;
2388 if (net
->flags
& AttribDecoration
) {
2389 switch (net
->decoration
) {
2394 /* since tools only let you toggle this anyways, we'll just make that all
2395 it supports for now.
2406 // with the state set it will then be the map event's job to read the
2407 // window's state and behave accordingly
2414 * Positions the Rect r according the the client window position and
2417 void BlackboxWindow::applyGravity(otk::Rect
&r
) {
2418 // apply horizontal window gravity
2419 switch (client
.win_gravity
) {
2421 case NorthWestGravity
:
2422 case SouthWestGravity
:
2424 r
.setX(client
.rect
.x());
2430 r
.setX(client
.rect
.x() - (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2433 case NorthEastGravity
:
2434 case SouthEastGravity
:
2436 r
.setX(client
.rect
.x() - frame
.margin
.left
- frame
.margin
.right
+ 2);
2441 r
.setX(client
.rect
.x() - frame
.margin
.left
);
2445 // apply vertical window gravity
2446 switch (client
.win_gravity
) {
2448 case NorthWestGravity
:
2449 case NorthEastGravity
:
2451 r
.setY(client
.rect
.y());
2457 r
.setY(client
.rect
.y() - (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2460 case SouthWestGravity
:
2461 case SouthEastGravity
:
2463 r
.setY(client
.rect
.y() - frame
.margin
.top
- frame
.margin
.bottom
+ 2);
2468 r
.setY(client
.rect
.y() - frame
.margin
.top
);
2475 * The reverse of the applyGravity function.
2477 * Positions the Rect r according to the frame window position and
2480 void BlackboxWindow::restoreGravity(otk::Rect
&r
) {
2481 // restore horizontal window gravity
2482 switch (client
.win_gravity
) {
2484 case NorthWestGravity
:
2485 case SouthWestGravity
:
2487 r
.setX(frame
.rect
.x());
2493 r
.setX(frame
.rect
.x() + (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2496 case NorthEastGravity
:
2497 case SouthEastGravity
:
2499 r
.setX(frame
.rect
.x() + frame
.margin
.left
+ frame
.margin
.right
- 2);
2504 r
.setX(frame
.rect
.x() + frame
.margin
.left
);
2508 // restore vertical window gravity
2509 switch (client
.win_gravity
) {
2511 case NorthWestGravity
:
2512 case NorthEastGravity
:
2514 r
.setY(frame
.rect
.y());
2520 r
.setY(frame
.rect
.y() + (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2523 case SouthWestGravity
:
2524 case SouthEastGravity
:
2526 r
.setY(frame
.rect
.y() + frame
.margin
.top
+ frame
.margin
.bottom
- 2);
2531 r
.setY(frame
.rect
.y() + frame
.margin
.top
);
2537 void BlackboxWindow::redrawLabel(void) const {
2538 if (flags
.focused
) {
2540 XSetWindowBackgroundPixmap(otk::OBDisplay::display
,
2541 frame
.label
, frame
.flabel
);
2543 XSetWindowBackground(otk::OBDisplay::display
,
2544 frame
.label
, frame
.flabel_pixel
);
2547 XSetWindowBackgroundPixmap(otk::OBDisplay::display
,
2548 frame
.label
, frame
.ulabel
);
2550 XSetWindowBackground(otk::OBDisplay::display
,
2551 frame
.label
, frame
.ulabel_pixel
);
2553 XClearWindow(otk::OBDisplay::display
, frame
.label
);
2555 WindowStyle
*style
= screen
->getWindowStyle();
2557 int pos
= frame
.bevel_w
* 2;
2558 style
->doJustify(client
.title
.c_str(), pos
, frame
.label_w
, frame
.bevel_w
* 4);
2559 style
->font
->drawString(frame
.label
, pos
, 1,
2560 (flags
.focused
? style
->l_text_focus
:
2561 style
->l_text_unfocus
),
2566 void BlackboxWindow::redrawAllButtons(void) const {
2567 if (frame
.iconify_button
) redrawIconifyButton(False
);
2568 if (frame
.maximize_button
) redrawMaximizeButton(flags
.maximized
);
2569 if (frame
.close_button
) redrawCloseButton(False
);
2570 if (frame
.stick_button
) redrawStickyButton(flags
.stuck
);
2574 void BlackboxWindow::redrawButton(bool pressed
, Window win
,
2575 Pixmap fppix
, unsigned long fppixel
,
2576 Pixmap uppix
, unsigned long uppixel
,
2577 Pixmap fpix
, unsigned long fpixel
,
2578 Pixmap upix
, unsigned long upixel
) const {
2583 if (flags
.focused
) {
2591 if (flags
.focused
) {
2601 XSetWindowBackgroundPixmap(otk::OBDisplay::display
, win
, p
);
2603 XSetWindowBackground(otk::OBDisplay::display
, win
, pix
);
2607 void BlackboxWindow::redrawIconifyButton(bool pressed
) const {
2608 redrawButton(pressed
, frame
.iconify_button
,
2609 frame
.pfbutton
, frame
.pfbutton_pixel
,
2610 frame
.pubutton
, frame
.pubutton_pixel
,
2611 frame
.fbutton
, frame
.fbutton_pixel
,
2612 frame
.ubutton
, frame
.ubutton_pixel
);
2614 XClearWindow(otk::OBDisplay::display
, frame
.iconify_button
);
2615 otk::BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2616 screen
->getWindowStyle()->b_pic_unfocus
);
2618 PixmapMask pm
= screen
->getWindowStyle()->icon_button
;
2620 if (screen
->getWindowStyle()->icon_button
.mask
!= None
) {
2621 XSetClipMask(otk::OBDisplay::display
, pen
.gc(), pm
.mask
);
2622 XSetClipOrigin(otk::OBDisplay::display
, pen
.gc(),
2623 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2);
2625 XFillRectangle(otk::OBDisplay::display
, frame
.iconify_button
, pen
.gc(),
2626 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2,
2627 (frame
.button_w
+ pm
.w
)/2, (frame
.button_w
+ pm
.h
)/2);
2629 XSetClipMask(otk::OBDisplay::display
, pen
.gc(), None
);
2630 XSetClipOrigin(otk::OBDisplay::display
, pen
.gc(), 0, 0);
2632 XDrawRectangle(otk::OBDisplay::display
, frame
.iconify_button
, pen
.gc(),
2633 2, (frame
.button_w
- 5), (frame
.button_w
- 5), 2);
2638 void BlackboxWindow::redrawMaximizeButton(bool pressed
) const {
2639 redrawButton(pressed
, frame
.maximize_button
,
2640 frame
.pfbutton
, frame
.pfbutton_pixel
,
2641 frame
.pubutton
, frame
.pubutton_pixel
,
2642 frame
.fbutton
, frame
.fbutton_pixel
,
2643 frame
.ubutton
, frame
.ubutton_pixel
);
2645 XClearWindow(otk::OBDisplay::display
, frame
.maximize_button
);
2647 otk::BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2648 screen
->getWindowStyle()->b_pic_unfocus
);
2650 PixmapMask pm
= screen
->getWindowStyle()->max_button
;
2652 if (pm
.mask
!= None
) {
2653 XSetClipMask(otk::OBDisplay::display
, pen
.gc(), pm
.mask
);
2654 XSetClipOrigin(otk::OBDisplay::display
, pen
.gc(),
2655 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2);
2657 XFillRectangle(otk::OBDisplay::display
, frame
.maximize_button
, pen
.gc(),
2658 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2,
2659 (frame
.button_w
+ pm
.w
)/2, (frame
.button_w
+ pm
.h
)/2);
2661 XSetClipOrigin(otk::OBDisplay::display
, pen
.gc(), 0, 0 );
2662 XSetClipMask( otk::OBDisplay::display
, pen
.gc(), None
);
2664 XDrawRectangle(otk::OBDisplay::display
, frame
.maximize_button
, pen
.gc(),
2665 2, 2, (frame
.button_w
- 5), (frame
.button_w
- 5));
2666 XDrawLine(otk::OBDisplay::display
, frame
.maximize_button
, pen
.gc(),
2667 2, 3, (frame
.button_w
- 3), 3);
2672 void BlackboxWindow::redrawCloseButton(bool pressed
) const {
2673 redrawButton(pressed
, frame
.close_button
,
2674 frame
.pfbutton
, frame
.pfbutton_pixel
,
2675 frame
.pubutton
, frame
.pubutton_pixel
,
2676 frame
.fbutton
, frame
.fbutton_pixel
,
2677 frame
.ubutton
, frame
.ubutton_pixel
);
2679 XClearWindow(otk::OBDisplay::display
, frame
.close_button
);
2681 otk::BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2682 screen
->getWindowStyle()->b_pic_unfocus
);
2684 PixmapMask pm
= screen
->getWindowStyle()->close_button
;
2686 if (pm
.mask
!= None
) {
2687 XSetClipMask(otk::OBDisplay::display
, pen
.gc(), pm
.mask
);
2688 XSetClipOrigin(otk::OBDisplay::display
, pen
.gc(),
2689 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2);
2691 XFillRectangle(otk::OBDisplay::display
, frame
.close_button
, pen
.gc(),
2692 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2,
2693 (frame
.button_w
+ pm
.w
)/2, (frame
.button_w
+ pm
.h
)/2);
2696 XSetClipOrigin(otk::OBDisplay::display
, pen
.gc(), 0, 0 );
2697 XSetClipMask( otk::OBDisplay::display
, pen
.gc(), None
);
2699 XDrawLine(otk::OBDisplay::display
, frame
.close_button
, pen
.gc(),
2700 2, 2, (frame
.button_w
- 3), (frame
.button_w
- 3));
2701 XDrawLine(otk::OBDisplay::display
, frame
.close_button
, pen
.gc(),
2702 2, (frame
.button_w
- 3), (frame
.button_w
- 3), 2);
2706 void BlackboxWindow::redrawStickyButton(bool pressed
) const {
2707 redrawButton(pressed
, frame
.stick_button
,
2708 frame
.pfbutton
, frame
.pfbutton_pixel
,
2709 frame
.pubutton
, frame
.pubutton_pixel
,
2710 frame
.fbutton
, frame
.fbutton_pixel
,
2711 frame
.ubutton
, frame
.ubutton_pixel
);
2713 XClearWindow(otk::OBDisplay::display
, frame
.stick_button
);
2715 otk::BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2716 screen
->getWindowStyle()->b_pic_unfocus
);
2718 PixmapMask pm
= screen
->getWindowStyle()->stick_button
;
2720 if (pm
.mask
!= None
) {
2721 XSetClipMask(otk::OBDisplay::display
, pen
.gc(), pm
.mask
);
2722 XSetClipOrigin(otk::OBDisplay::display
, pen
.gc(),
2723 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2);
2725 XFillRectangle(otk::OBDisplay::display
, frame
.stick_button
, pen
.gc(),
2726 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2,
2727 (frame
.button_w
+ pm
.w
)/2, (frame
.button_w
+ pm
.h
)/2);
2730 XSetClipOrigin(otk::OBDisplay::display
, pen
.gc(), 0, 0 );
2731 XSetClipMask( otk::OBDisplay::display
, pen
.gc(), None
);
2733 XFillRectangle(otk::OBDisplay::display
, frame
.stick_button
, pen
.gc(),
2734 frame
.button_w
/2 - 1, frame
.button_w
/2 -1, 2, 2 );
2738 void BlackboxWindow::mapRequestEvent(const XMapRequestEvent
*re
) {
2739 if (re
->window
!= client
.window
)
2743 fprintf(stderr
, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2748 Even though the window wants to be shown, if it is not on the current
2749 workspace, then it isn't going to be shown right now.
2751 if (! flags
.stuck
&&
2752 blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID() &&
2753 blackbox_attrib
.workspace
< screen
->getWorkspaceCount())
2754 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2756 switch (current_state
) {
2761 case WithdrawnState
:
2770 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2772 if (blackbox
->state() != Openbox::State_Starting
) {
2773 XSync(otk::OBDisplay::display
, False
); // make sure the frame is mapped
2774 if (screen
->doFocusNew() || (isTransient() && getTransientFor() &&
2775 getTransientFor()->isFocused())) {
2778 if (screen
->getPlacementPolicy() == BScreen::ClickMousePlacement
) {
2782 XQueryPointer(otk::OBDisplay::display
, screen
->getRootWindow(),
2783 &r
, &c
, &rx
, &ry
, &x
, &y
, &m
);
2793 void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent
*ue
) {
2794 if (ue
->window
!= client
.window
)
2798 fprintf(stderr
, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2802 screen
->unmanageWindow(this, False
);
2806 void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent
*de
) {
2807 if (de
->window
!= client
.window
)
2811 fprintf(stderr
, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2815 screen
->unmanageWindow(this, False
);
2819 void BlackboxWindow::reparentNotifyEvent(const XReparentEvent
*re
) {
2820 if (re
->window
!= client
.window
|| re
->parent
== frame
.plate
)
2824 fprintf(stderr
, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2825 "0x%lx.\n", client
.window
, re
->parent
);
2830 XPutBackEvent(otk::OBDisplay::display
, &ev
);
2831 screen
->unmanageWindow(this, True
);
2835 void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent
*pe
) {
2836 if (pe
->state
== PropertyDelete
|| ! validateClient())
2840 fprintf(stderr
, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n",
2846 case XA_WM_CLIENT_MACHINE
:
2850 case XA_WM_TRANSIENT_FOR
: {
2851 bool s
= flags
.stuck
;
2853 // determine if this is a transient window
2856 if (flags
.stuck
!= s
) stick();
2858 // adjust the window decorations based on transience
2859 if (isTransient()) {
2860 functions
&= ~Func_Maximize
;
2861 setAllowedActions();
2873 case XA_WM_ICON_NAME
:
2875 if (flags
.iconic
) screen
->propagateWindowName(this);
2878 case XAtom::net_wm_name
:
2882 if (decorations
& Decor_Titlebar
)
2885 screen
->propagateWindowName(this);
2888 case XA_WM_NORMAL_HINTS
: {
2891 if ((client
.normal_hint_flags
& PMinSize
) &&
2892 (client
.normal_hint_flags
& PMaxSize
)) {
2893 // the window now can/can't resize itself, so the buttons need to be
2896 if (client
.max_width
<= client
.min_width
&&
2897 client
.max_height
<= client
.min_height
) {
2898 functions
&= ~(Func_Resize
| Func_Maximize
);
2900 if (! isTransient())
2901 functions
|= Func_Maximize
;
2902 functions
|= Func_Resize
;
2905 setAllowedActions();
2909 otk::Rect old_rect
= frame
.rect
;
2913 if (old_rect
!= frame
.rect
)
2920 if (pe
->atom
== xatom
->getAtom(XAtom::wm_protocols
)) {
2923 if ((decorations
& Decor_Close
) && (! frame
.close_button
)) {
2924 createCloseButton();
2925 if (decorations
& Decor_Titlebar
) {
2926 positionButtons(True
);
2927 XMapSubwindows(otk::OBDisplay::display
, frame
.title
);
2930 } else if (pe
->atom
== xatom
->getAtom(XAtom::net_wm_strut
)) {
2939 void BlackboxWindow::exposeEvent(const XExposeEvent
*ee
) {
2941 fprintf(stderr
, "BlackboxWindow::exposeEvent() for 0x%lx\n", client
.window
);
2944 if (frame
.label
== ee
->window
&& (decorations
& Decor_Titlebar
))
2946 else if (frame
.close_button
== ee
->window
)
2947 redrawCloseButton(False
);
2948 else if (frame
.maximize_button
== ee
->window
)
2949 redrawMaximizeButton(flags
.maximized
);
2950 else if (frame
.iconify_button
== ee
->window
)
2951 redrawIconifyButton(False
);
2952 else if (frame
.stick_button
== ee
->window
)
2953 redrawStickyButton(flags
.stuck
);
2957 void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent
*cr
) {
2958 if (cr
->window
!= client
.window
|| flags
.iconic
)
2961 if (cr
->value_mask
& CWBorderWidth
)
2962 client
.old_bw
= cr
->border_width
;
2964 if (cr
->value_mask
& (CWX
| CWY
| CWWidth
| CWHeight
)) {
2965 frame
.changing
= frame
.rect
;
2967 if (cr
->value_mask
& (CWX
| CWY
)) {
2968 if (cr
->value_mask
& CWX
)
2969 client
.rect
.setX(cr
->x
);
2970 if (cr
->value_mask
& CWY
)
2971 client
.rect
.setY(cr
->y
);
2973 applyGravity(frame
.changing
);
2976 if (cr
->value_mask
& (CWWidth
| CWHeight
)) {
2977 if (cr
->value_mask
& CWWidth
)
2978 frame
.changing
.setWidth(cr
->width
+
2979 frame
.margin
.left
+ frame
.margin
.right
);
2981 if (cr
->value_mask
& CWHeight
)
2982 frame
.changing
.setHeight(cr
->height
+
2983 frame
.margin
.top
+ frame
.margin
.bottom
);
2986 if a position change has been specified, then that position will be
2987 used instead of determining a position based on the window's gravity.
2989 if (! (cr
->value_mask
& (CWX
| CWY
))) {
2991 switch (client
.win_gravity
) {
2992 case NorthEastGravity
:
2996 case SouthWestGravity
:
2998 corner
= BottomLeft
;
3000 case SouthEastGravity
:
3001 corner
= BottomRight
;
3003 default: // NorthWest, Static, etc
3010 configure(frame
.changing
.x(), frame
.changing
.y(),
3011 frame
.changing
.width(), frame
.changing
.height());
3014 if (cr
->value_mask
& CWStackMode
&& !isDesktop()) {
3015 switch (cr
->detail
) {
3018 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
3024 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3031 void BlackboxWindow::buttonPressEvent(const XButtonEvent
*be
) {
3033 fprintf(stderr
, "BlackboxWindow::buttonPressEvent() for 0x%lx\n",
3037 if (frame
.maximize_button
== be
->window
&& be
->button
<= 3) {
3038 redrawMaximizeButton(True
);
3039 } else if (be
->button
== 1 || (be
->button
== 3 && be
->state
== mod_mask
)) {
3040 if (! flags
.focused
)
3043 if (frame
.iconify_button
== be
->window
) {
3044 redrawIconifyButton(True
);
3045 } else if (frame
.close_button
== be
->window
) {
3046 redrawCloseButton(True
);
3047 } else if (frame
.stick_button
== be
->window
) {
3048 redrawStickyButton(True
);
3049 } else if (frame
.plate
== be
->window
) {
3050 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3052 XAllowEvents(otk::OBDisplay::display
, ReplayPointer
, be
->time
);
3054 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
3055 if (((be
->time
- lastButtonPressTime
) <=
3056 blackbox
->getDoubleClickInterval()) ||
3057 (be
->state
== ControlMask
)) {
3058 lastButtonPressTime
= 0;
3061 lastButtonPressTime
= be
->time
;
3065 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3067 } else if (be
->button
== 2 && (be
->window
!= frame
.iconify_button
) &&
3068 (be
->window
!= frame
.close_button
) &&
3069 (be
->window
!= frame
.stick_button
)) {
3070 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
3072 } else if (be
->button
== 4) {
3073 if ((be
->window
== frame
.label
||
3074 be
->window
== frame
.title
||
3075 be
->window
== frame
.maximize_button
||
3076 be
->window
== frame
.iconify_button
||
3077 be
->window
== frame
.close_button
||
3078 be
->window
== frame
.stick_button
) &&
3082 } else if (be
->button
== 5) {
3083 if ((be
->window
== frame
.label
||
3084 be
->window
== frame
.title
||
3085 be
->window
== frame
.maximize_button
||
3086 be
->window
== frame
.iconify_button
||
3087 be
->window
== frame
.close_button
||
3088 be
->window
== frame
.stick_button
) &&
3095 void BlackboxWindow::buttonReleaseEvent(const XButtonEvent
*re
) {
3097 fprintf(stderr
, "BlackboxWindow::buttonReleaseEvent() for 0x%lx\n",
3101 if (re
->window
== frame
.maximize_button
&&
3102 re
->button
>= 1 && re
->button
<= 3) {
3103 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3104 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
3105 maximize(re
->button
);
3107 redrawMaximizeButton(flags
.maximized
);
3109 } else if (re
->window
== frame
.iconify_button
&& re
->button
== 1) {
3110 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3111 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
3114 redrawIconifyButton(False
);
3116 } else if (re
->window
== frame
.stick_button
&& re
->button
== 1) {
3117 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3118 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
3121 redrawStickyButton(False
);
3123 } else if (re
->window
== frame
.close_button
& re
->button
== 1) {
3124 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3125 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
)))
3127 redrawCloseButton(False
);
3128 } else if (flags
.moving
) {
3130 } else if (flags
.resizing
) {
3132 } else if (re
->window
== frame
.window
) {
3133 if (re
->button
== 2 && re
->state
== mod_mask
)
3134 XUngrabPointer(otk::OBDisplay::display
, CurrentTime
);
3140 void BlackboxWindow::beginMove(int x_root
, int y_root
) {
3141 if (! (functions
& Func_Move
)) return;
3143 assert(! (flags
.resizing
|| flags
.moving
));
3146 Only one window can be moved/resized at a time. If another window is already
3147 being moved or resized, then stop it before whating to work with this one.
3149 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3150 if (changing
&& changing
!= this) {
3151 if (changing
->flags
.moving
)
3152 changing
->endMove();
3153 else // if (changing->flags.resizing)
3154 changing
->endResize();
3157 XGrabPointer(otk::OBDisplay::display
, frame
.window
, False
,
3158 PointerMotionMask
| ButtonReleaseMask
,
3159 GrabModeAsync
, GrabModeAsync
,
3160 None
, blackbox
->getMoveCursor(), CurrentTime
);
3162 flags
.moving
= True
;
3163 blackbox
->setChangingWindow(this);
3165 if (! screen
->doOpaqueMove()) {
3166 XGrabServer(otk::OBDisplay::display
);
3168 frame
.changing
= frame
.rect
;
3169 screen
->showPosition(frame
.changing
.x(), frame
.changing
.y());
3171 XDrawRectangle(otk::OBDisplay::display
, screen
->getRootWindow(),
3175 frame
.changing
.width() - 1,
3176 frame
.changing
.height() - 1);
3179 frame
.grab_x
= x_root
- frame
.rect
.x() - frame
.border_w
;
3180 frame
.grab_y
= y_root
- frame
.rect
.y() - frame
.border_w
;
3184 void BlackboxWindow::doMove(int x_root
, int y_root
) {
3185 assert(flags
.moving
);
3186 assert(blackbox
->getChangingWindow() == this);
3188 int dx
= x_root
- frame
.grab_x
, dy
= y_root
- frame
.grab_y
;
3189 dx
-= frame
.border_w
;
3190 dy
-= frame
.border_w
;
3192 doWindowSnapping(dx
, dy
);
3194 if (screen
->doOpaqueMove()) {
3195 if (screen
->doWorkspaceWarping())
3196 doWorkspaceWarping(x_root
, y_root
, dx
);
3198 configure(dx
, dy
, frame
.rect
.width(), frame
.rect
.height());
3200 XDrawRectangle(otk::OBDisplay::display
, screen
->getRootWindow(),
3204 frame
.changing
.width() - 1,
3205 frame
.changing
.height() - 1);
3207 if (screen
->doWorkspaceWarping())
3208 doWorkspaceWarping(x_root
, y_root
, dx
);
3210 frame
.changing
.setPos(dx
, dy
);
3212 XDrawRectangle(otk::OBDisplay::display
, screen
->getRootWindow(),
3216 frame
.changing
.width() - 1,
3217 frame
.changing
.height() - 1);
3220 screen
->showPosition(dx
, dy
);
3224 void BlackboxWindow::doWorkspaceWarping(int x_root
, int y_root
, int &dx
) {
3225 // workspace warping
3227 unsigned int dest
= screen
->getCurrentWorkspaceID();
3231 if (dest
> 0) dest
--;
3232 else dest
= screen
->getNumberOfWorkspaces() - 1;
3234 } else if (x_root
>= screen
->getRect().right()) {
3237 if (dest
< screen
->getNumberOfWorkspaces() - 1) dest
++;
3243 bool focus
= flags
.focused
; // had focus while moving?
3245 int dest_x
= x_root
;
3247 dest_x
+= screen
->getRect().width() - 1;
3248 dx
+= screen
->getRect().width() - 1;
3250 dest_x
-= screen
->getRect().width() - 1;
3251 dx
-= screen
->getRect().width() - 1;
3255 screen
->reassociateWindow(this, dest
, False
);
3256 screen
->changeWorkspaceID(dest
);
3258 if (screen
->doOpaqueMove())
3259 XGrabServer(otk::OBDisplay::display
);
3261 XUngrabPointer(otk::OBDisplay::display
, CurrentTime
);
3262 XWarpPointer(otk::OBDisplay::display
, None
,
3263 screen
->getRootWindow(), 0, 0, 0, 0,
3265 XGrabPointer(otk::OBDisplay::display
, frame
.window
, False
,
3266 PointerMotionMask
| ButtonReleaseMask
,
3267 GrabModeAsync
, GrabModeAsync
,
3268 None
, blackbox
->getMoveCursor(), CurrentTime
);
3270 if (screen
->doOpaqueMove())
3271 XUngrabServer(otk::OBDisplay::display
);
3279 void BlackboxWindow::doWindowSnapping(int &dx
, int &dy
) {
3280 // how much resistance to edges to provide
3281 const int resistance_size
= screen
->getResistanceSize();
3283 // how far away to snap
3284 const int snap_distance
= screen
->getSnapThreshold();
3286 // how to snap windows
3287 const int snap_to_windows
= screen
->getWindowToWindowSnap();
3288 const int snap_to_edges
= screen
->getWindowToEdgeSnap();
3289 // the amount of space away from the edge to provide resistance/snap
3290 const int snap_offset
= screen
->getSnapOffset();
3292 // find the geomeetery where the moving window currently is
3293 const otk::Rect
&moving
=
3294 screen
->doOpaqueMove() ? frame
.rect
: frame
.changing
;
3297 const int wleft
= dx
,
3298 wright
= dx
+ frame
.rect
.width() - 1,
3300 wbottom
= dy
+ frame
.rect
.height() - 1;
3302 if (snap_to_windows
) {
3303 otk::RectList rectlist
;
3305 Workspace
*w
= screen
->getWorkspace(getWorkspaceNumber());
3308 // add windows on the workspace to the rect list
3309 const BlackboxWindowList
& stack_list
= w
->getStackingList();
3310 BlackboxWindowList::const_iterator st_it
, st_end
= stack_list
.end();
3311 for (st_it
= stack_list
.begin(); st_it
!= st_end
; ++st_it
)
3312 if (*st_it
!= this) // don't snap to ourself
3313 rectlist
.push_back( (*st_it
)->frameRect() );
3315 otk::RectList::const_iterator it
, end
= rectlist
.end();
3316 for (it
= rectlist
.begin(); it
!= end
; ++it
) {
3317 bool snapped
= False
;
3318 const otk::Rect
&winrect
= *it
;
3319 otk::Rect offsetrect
;
3320 offsetrect
.setCoords(winrect
.left() - snap_offset
,
3321 winrect
.top() - snap_offset
,
3322 winrect
.right() + snap_offset
,
3323 winrect
.bottom() + snap_offset
);
3325 if (snap_to_windows
== BScreen::WindowResistance
)
3326 // if the window is already over top of this snap target, then
3327 // resistance is futile, so just ignore it
3328 if (winrect
.intersects(moving
))
3331 int dleft
, dright
, dtop
, dbottom
;
3333 // if the windows are in the same plane vertically
3334 if (wtop
>= (signed)(winrect
.y() - frame
.rect
.height() + 1) &&
3335 wtop
< (signed)(winrect
.y() + winrect
.height() - 1)) {
3337 if (snap_to_windows
== BScreen::WindowResistance
) {
3338 dleft
= wright
- offsetrect
.left();
3339 dright
= offsetrect
.right() - wleft
;
3341 // snap left of other window?
3342 if (dleft
>= 0 && dleft
< resistance_size
&&
3343 dleft
< (wright
- wleft
)) {
3344 dx
= offsetrect
.left() - frame
.rect
.width();
3347 // snap right of other window?
3348 else if (dright
>= 0 && dright
< resistance_size
&&
3349 dright
< (wright
- wleft
)) {
3350 dx
= offsetrect
.right() + 1;
3353 } else { // BScreen::WindowSnap
3354 dleft
= abs(wright
- offsetrect
.left());
3355 dright
= abs(wleft
- offsetrect
.right());
3357 // snap left of other window?
3358 if (dleft
< snap_distance
&& dleft
<= dright
) {
3359 dx
= offsetrect
.left() - frame
.rect
.width();
3362 // snap right of other window?
3363 else if (dright
< snap_distance
) {
3364 dx
= offsetrect
.right() + 1;
3370 if (screen
->getWindowCornerSnap()) {
3371 // try corner-snap to its other sides
3372 if (snap_to_windows
== BScreen::WindowResistance
) {
3373 dtop
= winrect
.top() - wtop
;
3374 dbottom
= wbottom
- winrect
.bottom();
3375 if (dtop
> 0 && dtop
< resistance_size
) {
3376 // if we're already past the top edge, then don't provide
3378 if (moving
.top() >= winrect
.top())
3380 } else if (dbottom
> 0 && dbottom
< resistance_size
) {
3381 // if we're already past the bottom edge, then don't provide
3383 if (moving
.bottom() <= winrect
.bottom())
3384 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
3386 } else { // BScreen::WindowSnap
3387 dtop
= abs(wtop
- winrect
.top());
3388 dbottom
= abs(wbottom
- winrect
.bottom());
3389 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3391 else if (dbottom
< snap_distance
)
3392 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
3400 // if the windows are on the same plane horizontally
3401 if (wleft
>= (signed)(winrect
.x() - frame
.rect
.width() + 1) &&
3402 wleft
< (signed)(winrect
.x() + winrect
.width() - 1)) {
3404 if (snap_to_windows
== BScreen::WindowResistance
) {
3405 dtop
= wbottom
- offsetrect
.top();
3406 dbottom
= offsetrect
.bottom() - wtop
;
3408 // snap top of other window?
3409 if (dtop
>= 0 && dtop
< resistance_size
&& dtop
< (wbottom
- wtop
)) {
3410 dy
= offsetrect
.top() - frame
.rect
.height();
3413 // snap bottom of other window?
3414 else if (dbottom
>= 0 && dbottom
< resistance_size
&&
3415 dbottom
< (wbottom
- wtop
)) {
3416 dy
= offsetrect
.bottom() + 1;
3419 } else { // BScreen::WindowSnap
3420 dtop
= abs(wbottom
- offsetrect
.top());
3421 dbottom
= abs(wtop
- offsetrect
.bottom());
3423 // snap top of other window?
3424 if (dtop
< snap_distance
&& dtop
<= dbottom
) {
3425 dy
= offsetrect
.top() - frame
.rect
.height();
3428 // snap bottom of other window?
3429 else if (dbottom
< snap_distance
) {
3430 dy
= offsetrect
.bottom() + 1;
3437 if (screen
->getWindowCornerSnap()) {
3438 // try corner-snap to its other sides
3439 if (snap_to_windows
== BScreen::WindowResistance
) {
3440 dleft
= winrect
.left() - wleft
;
3441 dright
= wright
- winrect
.right();
3442 if (dleft
> 0 && dleft
< resistance_size
) {
3443 // if we're already past the left edge, then don't provide
3445 if (moving
.left() >= winrect
.left())
3446 dx
= winrect
.left();
3447 } else if (dright
> 0 && dright
< resistance_size
) {
3448 // if we're already past the right edge, then don't provide
3450 if (moving
.right() <= winrect
.right())
3451 dx
= winrect
.right() - frame
.rect
.width() + 1;
3453 } else { // BScreen::WindowSnap
3454 dleft
= abs(wleft
- winrect
.left());
3455 dright
= abs(wright
- winrect
.right());
3456 if (dleft
< snap_distance
&& dleft
<= dright
)
3457 dx
= winrect
.left();
3458 else if (dright
< snap_distance
)
3459 dx
= winrect
.right() - frame
.rect
.width() + 1;
3469 if (snap_to_edges
) {
3470 otk::RectList rectlist
;
3472 // snap to the screen edges (and screen boundaries for xinerama)
3474 if (screen
->isXineramaActive() && blackbox
->doXineramaSnapping()) {
3475 rectlist
.insert(rectlist
.begin(),
3476 screen
->getXineramaAreas().begin(),
3477 screen
->getXineramaAreas().end());
3480 rectlist
.push_back(screen
->getRect());
3482 otk::RectList::const_iterator it
, end
= rectlist
.end();
3483 for (it
= rectlist
.begin(); it
!= end
; ++it
) {
3484 const otk::Rect
&srect
= *it
;
3485 otk::Rect offsetrect
;
3486 offsetrect
.setCoords(srect
.left() + snap_offset
,
3487 srect
.top() + snap_offset
,
3488 srect
.right() - snap_offset
,
3489 srect
.bottom() - snap_offset
);
3491 if (snap_to_edges
== BScreen::WindowResistance
) {
3492 // if we're not in the rectangle then don't snap to it.
3493 if (! srect
.contains(moving
))
3495 } else { // BScreen::WindowSnap
3496 // if we're not in the rectangle then don't snap to it.
3497 if (! srect
.intersects(otk::Rect(wleft
, wtop
, frame
.rect
.width(),
3498 frame
.rect
.height())))
3502 if (snap_to_edges
== BScreen::WindowResistance
) {
3503 int dleft
= offsetrect
.left() - wleft
,
3504 dright
= wright
- offsetrect
.right(),
3505 dtop
= offsetrect
.top() - wtop
,
3506 dbottom
= wbottom
- offsetrect
.bottom();
3509 if (dleft
> 0 && dleft
< resistance_size
)
3510 dx
= offsetrect
.left();
3512 else if (dright
> 0 && dright
< resistance_size
)
3513 dx
= offsetrect
.right() - frame
.rect
.width() + 1;
3516 if (dtop
> 0 && dtop
< resistance_size
)
3517 dy
= offsetrect
.top();
3519 else if (dbottom
> 0 && dbottom
< resistance_size
)
3520 dy
= offsetrect
.bottom() - frame
.rect
.height() + 1;
3521 } else { // BScreen::WindowSnap
3522 int dleft
= abs(wleft
- offsetrect
.left()),
3523 dright
= abs(wright
- offsetrect
.right()),
3524 dtop
= abs(wtop
- offsetrect
.top()),
3525 dbottom
= abs(wbottom
- offsetrect
.bottom());
3528 if (dleft
< snap_distance
&& dleft
<= dright
)
3529 dx
= offsetrect
.left();
3531 else if (dright
< snap_distance
)
3532 dx
= offsetrect
.right() - frame
.rect
.width() + 1;
3535 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3536 dy
= offsetrect
.top();
3538 else if (dbottom
< snap_distance
)
3539 dy
= offsetrect
.bottom() - frame
.rect
.height() + 1;
3546 void BlackboxWindow::endMove(void) {
3547 assert(flags
.moving
);
3548 assert(blackbox
->getChangingWindow() == this);
3550 flags
.moving
= False
;
3551 blackbox
->setChangingWindow(0);
3553 if (! screen
->doOpaqueMove()) {
3554 /* when drawing the rubber band, we need to make sure we only draw inside
3555 * the frame... frame.changing_* contain the new coords for the window,
3556 * so we need to subtract 1 from changing_w/changing_h every where we
3557 * draw the rubber band (for both moving and resizing)
3559 XDrawRectangle(otk::OBDisplay::display
, screen
->getRootWindow(),
3560 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3561 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3562 XUngrabServer(otk::OBDisplay::display
);
3564 configure(frame
.changing
.x(), frame
.changing
.y(),
3565 frame
.changing
.width(), frame
.changing
.height());
3567 configure(frame
.rect
.x(), frame
.rect
.y(),
3568 frame
.rect
.width(), frame
.rect
.height());
3570 screen
->hideGeometry();
3572 XUngrabPointer(otk::OBDisplay::display
, CurrentTime
);
3574 // if there are any left over motions from the move, drop them now
3575 XSync(otk::OBDisplay::display
, false); // make sure we don't miss any
3577 while (XCheckTypedWindowEvent(otk::OBDisplay::display
, frame
.window
,
3582 void BlackboxWindow::beginResize(int x_root
, int y_root
, Corner dir
) {
3583 if (! (functions
& Func_Resize
)) return;
3585 assert(! (flags
.resizing
|| flags
.moving
));
3588 Only one window can be moved/resized at a time. If another window is
3589 already being moved or resized, then stop it before whating to work with
3592 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3593 if (changing
&& changing
!= this) {
3594 if (changing
->flags
.moving
)
3595 changing
->endMove();
3596 else // if (changing->flags.resizing)
3597 changing
->endResize();
3605 switch (resize_dir
) {
3608 cursor
= blackbox
->getLowerLeftAngleCursor();
3613 cursor
= blackbox
->getLowerRightAngleCursor();
3617 anchor
= BottomRight
;
3618 cursor
= blackbox
->getUpperLeftAngleCursor();
3622 anchor
= BottomLeft
;
3623 cursor
= blackbox
->getUpperRightAngleCursor();
3627 assert(false); // unhandled Corner
3628 return; // unreachable, for the compiler
3631 XGrabServer(otk::OBDisplay::display
);
3632 XGrabPointer(otk::OBDisplay::display
, frame
.window
, False
,
3633 PointerMotionMask
| ButtonReleaseMask
,
3634 GrabModeAsync
, GrabModeAsync
, None
, cursor
, CurrentTime
);
3636 flags
.resizing
= True
;
3637 blackbox
->setChangingWindow(this);
3639 unsigned int gw
, gh
;
3640 frame
.changing
= frame
.rect
;
3642 constrain(anchor
, &gw
, &gh
);
3644 XDrawRectangle(otk::OBDisplay::display
, screen
->getRootWindow(),
3645 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3646 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3648 screen
->showGeometry(gw
, gh
);
3650 frame
.grab_x
= x_root
;
3651 frame
.grab_y
= y_root
;
3655 void BlackboxWindow::doResize(int x_root
, int y_root
) {
3656 assert(flags
.resizing
);
3657 assert(blackbox
->getChangingWindow() == this);
3659 XDrawRectangle(otk::OBDisplay::display
, screen
->getRootWindow(),
3660 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3661 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3663 unsigned int gw
, gh
;
3665 int dx
, dy
; // the amount of change in the size of the window
3667 switch (resize_dir
) {
3670 dx
= - (x_root
- frame
.grab_x
);
3671 dy
= + (y_root
- frame
.grab_y
);
3675 dx
= + (x_root
- frame
.grab_x
);
3676 dy
= + (y_root
- frame
.grab_y
);
3679 anchor
= BottomRight
;
3680 dx
= - (x_root
- frame
.grab_x
);
3681 dy
= - (y_root
- frame
.grab_y
);
3684 anchor
= BottomLeft
;
3685 dx
= + (x_root
- frame
.grab_x
);
3686 dy
= - (y_root
- frame
.grab_y
);
3690 assert(false); // unhandled Corner
3691 return; // unreachable, for the compiler
3694 // make sure the user cant resize the window smaller than 0, which makes it
3695 // wrap around and become huge
3696 if (dx
< -(signed)client
.rect
.width()) dx
= -(signed)client
.rect
.width();
3697 if (dy
< -(signed)client
.rect
.height()) dy
= -(signed)client
.rect
.height();
3699 frame
.changing
.setSize(frame
.rect
.width() + dx
, frame
.rect
.height() + dy
);
3701 constrain(anchor
, &gw
, &gh
);
3703 XDrawRectangle(otk::OBDisplay::display
, screen
->getRootWindow(),
3704 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3705 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3707 screen
->showGeometry(gw
, gh
);
3711 void BlackboxWindow::endResize(void) {
3712 assert(flags
.resizing
);
3713 assert(blackbox
->getChangingWindow() == this);
3715 XDrawRectangle(otk::OBDisplay::display
, screen
->getRootWindow(),
3716 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3717 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3718 XUngrabServer(otk::OBDisplay::display
);
3720 // unset maximized state after resized when fully maximized
3721 if (flags
.maximized
== 1)
3724 flags
.resizing
= False
;
3725 blackbox
->setChangingWindow(0);
3727 configure(frame
.changing
.x(), frame
.changing
.y(),
3728 frame
.changing
.width(), frame
.changing
.height());
3729 screen
->hideGeometry();
3731 XUngrabPointer(otk::OBDisplay::display
, CurrentTime
);
3733 // if there are any left over motions from the resize, drop them now
3734 XSync(otk::OBDisplay::display
, false); // make sure we don't miss any
3736 while (XCheckTypedWindowEvent(otk::OBDisplay::display
, frame
.window
,
3741 void BlackboxWindow::motionNotifyEvent(const XMotionEvent
*me
) {
3743 fprintf(stderr
, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n",
3748 doMove(me
->x_root
, me
->y_root
);
3749 } else if (flags
.resizing
) {
3750 doResize(me
->x_root
, me
->y_root
);
3752 if ((functions
& Func_Move
) &&
3753 (me
->state
& Button1Mask
) &&
3754 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3755 frame
.handle
== me
->window
|| frame
.window
== me
->window
)) {
3756 beginMove(me
->x_root
, me
->y_root
);
3757 } else if ((functions
& Func_Resize
) &&
3758 ((me
->state
& Button1Mask
) &&
3759 (me
->window
== frame
.right_grip
||
3760 me
->window
== frame
.left_grip
)) ||
3761 ((me
->state
& Button3Mask
) && (me
->state
& mod_mask
) &&
3762 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3763 frame
.handle
== me
->window
|| frame
.window
== me
->window
||
3764 frame
.right_grip
== me
->window
||
3765 frame
.left_grip
== me
->window
))) {
3766 unsigned int zones
= screen
->getResizeZones();
3769 if (me
->window
== frame
.left_grip
) {
3770 corner
= BottomLeft
;
3771 } else if (me
->window
== frame
.right_grip
|| zones
== 1) {
3772 corner
= BottomRight
;
3775 bool left
= (me
->x_root
- frame
.rect
.x() <=
3776 static_cast<signed>(frame
.rect
.width() / 2));
3779 else // (zones == 4)
3780 top
= (me
->y_root
- frame
.rect
.y() <=
3781 static_cast<signed>(frame
.rect
.height() / 2));
3782 corner
= (top
? (left
? TopLeft
: TopRight
) :
3783 (left
? BottomLeft
: BottomRight
));
3786 beginResize(me
->x_root
, me
->y_root
, corner
);
3792 void BlackboxWindow::enterNotifyEvent(const XCrossingEvent
* ce
) {
3793 if (! (screen
->isSloppyFocus() && isVisible() && isNormal()))
3797 bool leave
= False
, inferior
= False
;
3799 while (XCheckTypedWindowEvent(otk::OBDisplay::display
, ce
->window
,
3801 if (e
.type
== LeaveNotify
&& e
.xcrossing
.mode
== NotifyNormal
) {
3803 inferior
= (e
.xcrossing
.detail
== NotifyInferior
);
3807 if (! leave
|| inferior
) {
3808 if (! isFocused()) {
3809 bool success
= setInputFocus();
3810 if (success
) // if focus succeeded install the colormap
3811 installColormap(True
); // XXX: shouldnt we honour no install?
3814 We only auto-raise when the window wasn't focused because otherwise
3815 we run into problems with gtk+ drop-down lists. The window ends up
3816 raising over the list.
3818 if (screen
->doAutoRaise())
3825 void BlackboxWindow::leaveNotifyEvent(const XCrossingEvent
*) {
3826 if (! (screen
->isSloppyFocus() && screen
->doAutoRaise() && isNormal()))
3829 installColormap(False
);
3836 void BlackboxWindow::shapeEvent(XShapeEvent
*e
) {
3837 if (blackbox
->hasShapeExtensions()) {
3838 if (! e
->shaped
&& flags
.shaped
) {
3840 flags
.shaped
= False
;
3841 } else if (e
->shaped
) {
3843 flags
.shaped
= True
;
3850 bool BlackboxWindow::validateClient(void) const {
3851 XSync(otk::OBDisplay::display
, False
);
3854 if (XCheckTypedWindowEvent(otk::OBDisplay::display
, client
.window
,
3855 DestroyNotify
, &e
) ||
3856 XCheckTypedWindowEvent(otk::OBDisplay::display
, client
.window
,
3858 XPutBackEvent(otk::OBDisplay::display
, &e
);
3867 void BlackboxWindow::restore(bool remap
) {
3868 XChangeSaveSet(otk::OBDisplay::display
, client
.window
, SetModeDelete
);
3869 XSelectInput(otk::OBDisplay::display
, client
.window
, NoEventMask
);
3870 XSelectInput(otk::OBDisplay::display
, frame
.plate
, NoEventMask
);
3872 // do not leave a shaded window as an icon unless it was an icon
3873 if (flags
.shaded
&& ! flags
.iconic
)
3874 setState(NormalState
);
3876 // erase the netwm stuff that we read when a window maps, so that it
3877 // doesn't persist between mappings.
3878 // (these are the ones read in getNetWMFlags().)
3879 xatom
->eraseValue(client
.window
, XAtom::net_wm_desktop
);
3880 xatom
->eraseValue(client
.window
, XAtom::net_wm_state
);
3882 restoreGravity(client
.rect
);
3884 XUnmapWindow(otk::OBDisplay::display
, frame
.window
);
3885 XUnmapWindow(otk::OBDisplay::display
, client
.window
);
3887 XSetWindowBorderWidth(otk::OBDisplay::display
, client
.window
, client
.old_bw
);
3890 if (XCheckTypedWindowEvent(otk::OBDisplay::display
, client
.window
,
3891 ReparentNotify
, &ev
)) {
3894 // according to the ICCCM - if the client doesn't reparent to
3895 // root, then we have to do it for them
3896 XReparentWindow(otk::OBDisplay::display
, client
.window
,
3897 screen
->getRootWindow(),
3898 client
.rect
.x(), client
.rect
.y());
3901 if (remap
) XMapWindow(otk::OBDisplay::display
, client
.window
);
3905 // timer for autoraise
3906 void BlackboxWindow::timeout(BlackboxWindow
*t
) {
3907 t
->screen
->getWorkspace(t
->blackbox_attrib
.workspace
)->raiseWindow(t
);
3908 printf("TIMED OUT YA YAY\n");
3912 void BlackboxWindow::changeBlackboxHints(const BlackboxHints
*net
) {
3913 if ((net
->flags
& AttribShaded
) &&
3914 ((blackbox_attrib
.attrib
& AttribShaded
) !=
3915 (net
->attrib
& AttribShaded
)))
3918 if (flags
.visible
&& // watch out for requests when we can not be seen
3919 (net
->flags
& (AttribMaxVert
| AttribMaxHoriz
)) &&
3920 ((blackbox_attrib
.attrib
& (AttribMaxVert
| AttribMaxHoriz
)) !=
3921 (net
->attrib
& (AttribMaxVert
| AttribMaxHoriz
)))) {
3922 if (flags
.maximized
) {
3927 if ((net
->flags
& AttribMaxHoriz
) && (net
->flags
& AttribMaxVert
))
3928 button
= ((net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0);
3929 else if (net
->flags
& AttribMaxVert
)
3930 button
= ((net
->attrib
& AttribMaxVert
) ? 2 : 0);
3931 else if (net
->flags
& AttribMaxHoriz
)
3932 button
= ((net
->attrib
& AttribMaxHoriz
) ? 3 : 0);
3938 if ((net
->flags
& AttribOmnipresent
) &&
3939 ((blackbox_attrib
.attrib
& AttribOmnipresent
) !=
3940 (net
->attrib
& AttribOmnipresent
)))
3943 if ((net
->flags
& AttribWorkspace
) &&
3944 (blackbox_attrib
.workspace
!= net
->workspace
)) {
3945 screen
->reassociateWindow(this, net
->workspace
, True
);
3947 if (screen
->getCurrentWorkspaceID() != net
->workspace
) {
3951 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3955 if (net
->flags
& AttribDecoration
) {
3956 switch (net
->decoration
) {
3973 * Set the sizes of all components of the window frame
3974 * (the window decorations).
3975 * These values are based upon the current style settings and the client
3976 * window's dimensions.
3978 void BlackboxWindow::upsize(void) {
3979 frame
.bevel_w
= screen
->getBevelWidth();
3981 if (decorations
& Decor_Border
) {
3982 frame
.border_w
= screen
->getBorderWidth();
3983 if (! isTransient())
3984 frame
.mwm_border_w
= screen
->getFrameWidth();
3986 frame
.mwm_border_w
= 0;
3988 frame
.mwm_border_w
= frame
.border_w
= 0;
3991 if (decorations
& Decor_Titlebar
) {
3992 // the height of the titlebar is based upon the height of the font being
3993 // used to display the window's title
3994 WindowStyle
*style
= screen
->getWindowStyle();
3995 frame
.title_h
= style
->font
->height() + (frame
.bevel_w
* 2) + 2;
3997 frame
.label_h
= frame
.title_h
- (frame
.bevel_w
* 2);
3998 frame
.button_w
= (frame
.label_h
- 2);
4000 // set the top frame margin
4001 frame
.margin
.top
= frame
.border_w
+ frame
.title_h
+
4002 frame
.border_w
+ frame
.mwm_border_w
;
4008 // set the top frame margin
4009 frame
.margin
.top
= frame
.border_w
+ frame
.mwm_border_w
;
4012 // set the left/right frame margin
4013 frame
.margin
.left
= frame
.margin
.right
= frame
.border_w
+ frame
.mwm_border_w
;
4015 if (decorations
& Decor_Handle
) {
4016 frame
.grip_w
= frame
.button_w
* 2;
4017 frame
.handle_h
= screen
->getHandleWidth();
4019 // set the bottom frame margin
4020 frame
.margin
.bottom
= frame
.border_w
+ frame
.handle_h
+
4021 frame
.border_w
+ frame
.mwm_border_w
;
4026 // set the bottom frame margin
4027 frame
.margin
.bottom
= frame
.border_w
+ frame
.mwm_border_w
;
4031 We first get the normal dimensions and use this to define the inside_w/h
4032 then we modify the height if shading is in effect.
4033 If the shade state is not considered then frame.rect gets reset to the
4034 normal window size on a reconfigure() call resulting in improper
4035 dimensions appearing in move/resize and other events.
4038 height
= client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
,
4039 width
= client
.rect
.width() + frame
.margin
.left
+ frame
.margin
.right
;
4041 frame
.inside_w
= width
- (frame
.border_w
* 2);
4042 frame
.inside_h
= height
- (frame
.border_w
* 2);
4045 height
= frame
.title_h
+ (frame
.border_w
* 2);
4046 frame
.rect
.setSize(width
, height
);
4051 * Calculate the size of the client window and constrain it to the
4052 * size specified by the size hints of the client window.
4054 * The logical width and height are placed into pw and ph, if they
4055 * are non-zero. Logical size refers to the users perception of
4056 * the window size (for example an xterm resizes in cells, not in pixels).
4057 * pw and ph are then used to display the geometry during window moves, resize,
4060 * The physical geometry is placed into frame.changing_{x,y,width,height}.
4061 * Physical geometry refers to the geometry of the window in pixels.
4063 void BlackboxWindow::constrain(Corner anchor
,
4064 unsigned int *pw
, unsigned int *ph
) {
4065 // frame.changing represents the requested frame size, we need to
4066 // strip the frame margin off and constrain the client size
4067 frame
.changing
.setCoords(frame
.changing
.left() + frame
.margin
.left
,
4068 frame
.changing
.top() + frame
.margin
.top
,
4069 frame
.changing
.right() - frame
.margin
.right
,
4070 frame
.changing
.bottom() - frame
.margin
.bottom
);
4072 unsigned int dw
= frame
.changing
.width(), dh
= frame
.changing
.height(),
4073 base_width
= (client
.base_width
) ? client
.base_width
: client
.min_width
,
4074 base_height
= (client
.base_height
) ? client
.base_height
:
4077 // constrain, but only if the min/max are being used. if they aren't, then
4078 // this resize is going to be from a ConfigureRequest because the window
4079 // isn't allowed to be resized by the user. And in that case, we don't want
4080 // to limit what the app can do
4081 if (client
.max_width
> client
.min_width
||
4082 client
.max_height
> client
.min_height
) {
4083 if (dw
< client
.min_width
) dw
= client
.min_width
;
4084 if (dh
< client
.min_height
) dh
= client
.min_height
;
4085 if (dw
> client
.max_width
) dw
= client
.max_width
;
4086 if (dh
> client
.max_height
) dh
= client
.max_height
;
4089 if (client
.width_inc
> 1) {
4091 dw
/= client
.width_inc
;
4093 if (client
.height_inc
> 1) {
4095 dh
/= client
.height_inc
;
4104 if (client
.width_inc
> 1) {
4105 dw
*= client
.width_inc
;
4108 if (client
.height_inc
> 1) {
4109 dh
*= client
.height_inc
;
4113 frame
.changing
.setSize(dw
, dh
);
4115 // add the frame margin back onto frame.changing
4116 frame
.changing
.setCoords(frame
.changing
.left() - frame
.margin
.left
,
4117 frame
.changing
.top() - frame
.margin
.top
,
4118 frame
.changing
.right() + frame
.margin
.right
,
4119 frame
.changing
.bottom() + frame
.margin
.bottom
);
4121 // move frame.changing to the specified anchor
4129 dx
= frame
.rect
.right() - frame
.changing
.right();
4133 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
4137 dx
= frame
.rect
.right() - frame
.changing
.right();
4138 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
4142 assert(false); // unhandled corner
4144 frame
.changing
.setPos(frame
.changing
.x() + dx
, frame
.changing
.y() + dy
);
4148 void WindowStyle::doJustify(const std::string
&text
, int &start_pos
,
4149 unsigned int max_length
,
4150 unsigned int modifier
) const {
4151 size_t text_len
= text
.size();
4152 unsigned int length
;
4155 length
= font
->measureString(string(text
, 0, text_len
)) + modifier
;
4156 } while (length
> max_length
&& text_len
-- > 0);
4160 start_pos
+= max_length
- length
;
4164 start_pos
+= (max_length
- length
) / 2;
4174 BWindowGroup::BWindowGroup(Blackbox
*b
, Window _group
)
4175 : blackbox(b
), group(_group
) {
4176 XWindowAttributes wattrib
;
4177 if (! XGetWindowAttributes(otk::OBDisplay::display
, group
, &wattrib
)) {
4178 // group window doesn't seem to exist anymore
4183 XSelectInput(otk::OBDisplay::display
, group
,
4184 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
4186 blackbox
->saveGroupSearch(group
, this);
4190 BWindowGroup::~BWindowGroup(void) {
4191 blackbox
->removeGroupSearch(group
);
4196 BWindowGroup::find(BScreen
*screen
, bool allow_transients
) const {
4197 BlackboxWindow
*ret
= blackbox
->getFocusedWindow();
4199 // does the focus window match (or any transient_fors)?
4200 for (; ret
; ret
= ret
->getTransientFor()) {
4201 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
&&
4202 (! ret
->isTransient() || allow_transients
))
4206 if (ret
) return ret
;
4208 // the focus window didn't match, look in the group's window list
4209 BlackboxWindowList::const_iterator it
, end
= windowList
.end();
4210 for (it
= windowList
.begin(); it
!= end
; ++it
) {
4212 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
&&
4213 (! ret
->isTransient() || allow_transients
))