1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
4 # include "../config.h"
11 #include "bindings.hh"
12 #include "otk/display.hh"
13 #include "otk/property.hh"
17 #include <X11/Xutil.h>
18 #include <X11/Xatom.h>
23 #define _(str) gettext(str)
30 Client::Client(int screen
, Window window
)
31 : otk::EventHandler(),
32 WidgetBase(WidgetBase::Type_Client
),
33 frame(0), _screen(screen
), _window(window
)
40 // update EVERYTHING the first time!!
42 // we default to NormalState, visible
43 _wmstate
= NormalState
;
46 // not a transient by default of course
48 // pick a layer to start from
49 _layer
= Layer_Normal
;
50 // default to not urgent
52 // not positioned unless specified
54 // nothing is disabled unless specified
55 _disabled_decorations
= 0;
62 getType(); // this can change the mwmhints for special cases
69 getGravity(); // get the attribute gravity
70 updateNormalHints(); // this may override the attribute gravity
72 // got the type, the mwmhints, the protocols, and the normal hints (min/max
73 // sizes), so we're ready to set up
74 // the decorations/functions
75 setupDecorAndFunctions();
77 // also get the initial_state and set _iconic if we aren't "starting"
78 // when we're "starting" that means we should use whatever state was already
79 // on the window over the initial map state, because it was already mapped
80 updateWMHints(openbox
->state() != Openbox::State_Starting
);
86 // this makes sure that these windows appear on all desktops
87 if (/*_type == Type_Dock ||*/ _type
== Type_Desktop
)
88 _desktop
= 0xffffffff;
90 // set the desktop hint, to make sure that it always exists, and to reflect
91 // any changes we've made here
92 otk::Property::set(_window
, otk::Property::atoms
.net_wm_desktop
,
93 otk::Property::atoms
.cardinal
, (unsigned)_desktop
);
101 // clean up childrens' references
102 while (!_transients
.empty()) {
103 _transients
.front()->_transient_for
= 0;
104 _transients
.pop_front();
107 // clean up parents reference to this
109 _transient_for
->_transients
.remove(this); // remove from old parent
111 if (openbox
->state() != Openbox::State_Exiting
) {
112 // these values should not be persisted across a window unmapping/mapping
113 otk::Property::erase(_window
, otk::Property::atoms
.net_wm_desktop
);
114 otk::Property::erase(_window
, otk::Property::atoms
.net_wm_state
);
116 // if we're left in an iconic state, the client wont be mapped. this is
117 // bad, since we will no longer be managing the window on restart
119 XMapWindow(**otk::display
, _window
);
124 bool Client::validate() const
126 XSync(**otk::display
, false); // get all events on the server
129 if (XCheckTypedWindowEvent(**otk::display
, _window
, DestroyNotify
, &e
) ||
130 XCheckTypedWindowEvent(**otk::display
, _window
, UnmapNotify
, &e
)) {
131 XPutBackEvent(**otk::display
, &e
);
139 void Client::getGravity()
141 XWindowAttributes wattrib
;
144 ret
= XGetWindowAttributes(**otk::display
, _window
, &wattrib
);
145 assert(ret
!= BadWindow
);
146 _gravity
= wattrib
.win_gravity
;
150 void Client::getDesktop()
152 // defaults to the current desktop
153 _desktop
= openbox
->screen(_screen
)->desktop();
155 if (otk::Property::get(_window
, otk::Property::atoms
.net_wm_desktop
,
156 otk::Property::atoms
.cardinal
,
157 (long unsigned*)&_desktop
)) {
159 // printf("Window requested desktop: %ld\n", _desktop);
165 void Client::getType()
167 _type
= (WindowType
) -1;
170 unsigned long num
= (unsigned) -1;
171 if (otk::Property::get(_window
, otk::Property::atoms
.net_wm_window_type
,
172 otk::Property::atoms
.atom
, &num
, &val
)) {
173 // use the first value that we know about in the array
174 for (unsigned long i
= 0; i
< num
; ++i
) {
175 if (val
[i
] == otk::Property::atoms
.net_wm_window_type_desktop
)
176 _type
= Type_Desktop
;
177 else if (val
[i
] == otk::Property::atoms
.net_wm_window_type_dock
)
179 else if (val
[i
] == otk::Property::atoms
.net_wm_window_type_toolbar
)
180 _type
= Type_Toolbar
;
181 else if (val
[i
] == otk::Property::atoms
.net_wm_window_type_menu
)
183 else if (val
[i
] == otk::Property::atoms
.net_wm_window_type_utility
)
184 _type
= Type_Utility
;
185 else if (val
[i
] == otk::Property::atoms
.net_wm_window_type_splash
)
187 else if (val
[i
] == otk::Property::atoms
.net_wm_window_type_dialog
)
189 else if (val
[i
] == otk::Property::atoms
.net_wm_window_type_normal
)
191 else if (val
[i
] == otk::Property::atoms
.kde_net_wm_window_type_override
){
192 // prevent this window from getting any decor or functionality
193 _mwmhints
.flags
&= MwmFlag_Functions
| MwmFlag_Decorations
;
194 _mwmhints
.decorations
= 0;
195 _mwmhints
.functions
= 0;
197 if (_type
!= (WindowType
) -1)
198 break; // grab the first known type
203 if (_type
== (WindowType
) -1) {
205 * the window type hint was not set, which means we either classify ourself
206 * as a normal window or a dialog, depending on if we are a transient.
216 void Client::setupDecorAndFunctions()
218 // start with everything (cept fullscreen)
219 _decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
220 Decor_AllDesktops
| Decor_Iconify
| Decor_Maximize
;
221 _functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
|
223 if (_delete_window
) {
224 _decorations
|= Decor_Close
;
225 _functions
|= Func_Close
;
228 if (!(_min_size
.x() < _max_size
.x() || _min_size
.y() < _max_size
.y())) {
229 _decorations
&= ~(Decor_Maximize
| Decor_Handle
);
230 _functions
&= ~(Func_Resize
| Func_Maximize
);
235 // normal windows retain all of the possible decorations and
236 // functionality, and are the only windows that you can fullscreen
237 _functions
|= Func_Fullscreen
;
241 // dialogs cannot be maximized
242 _decorations
&= ~Decor_Maximize
;
243 _functions
&= ~Func_Maximize
;
249 // these windows get less functionality
250 _decorations
&= ~(Decor_Iconify
| Decor_Handle
);
251 _functions
&= ~(Func_Iconify
| Func_Resize
);
257 // none of these windows are manipulated by the window manager
263 // Mwm Hints are applied subtractively to what has already been chosen for
264 // decor and functionality
265 if (_mwmhints
.flags
& MwmFlag_Decorations
) {
266 if (! (_mwmhints
.decorations
& MwmDecor_All
)) {
267 if (! (_mwmhints
.decorations
& MwmDecor_Border
))
268 _decorations
&= ~Decor_Border
;
269 if (! (_mwmhints
.decorations
& MwmDecor_Handle
))
270 _decorations
&= ~Decor_Handle
;
271 if (! (_mwmhints
.decorations
& MwmDecor_Title
)) {
272 _decorations
&= ~Decor_Titlebar
;
273 // if we don't have a titlebar, then we cannot shade!
274 _functions
&= ~Func_Shade
;
276 if (! (_mwmhints
.decorations
& MwmDecor_Iconify
))
277 _decorations
&= ~Decor_Iconify
;
278 if (! (_mwmhints
.decorations
& MwmDecor_Maximize
))
279 _decorations
&= ~Decor_Maximize
;
283 if (_mwmhints
.flags
& MwmFlag_Functions
) {
284 if (! (_mwmhints
.functions
& MwmFunc_All
)) {
285 if (! (_mwmhints
.functions
& MwmFunc_Resize
))
286 _functions
&= ~Func_Resize
;
287 if (! (_mwmhints
.functions
& MwmFunc_Move
))
288 _functions
&= ~Func_Move
;
289 if (! (_mwmhints
.functions
& MwmFunc_Iconify
))
290 _functions
&= ~Func_Iconify
;
291 if (! (_mwmhints
.functions
& MwmFunc_Maximize
))
292 _functions
&= ~Func_Maximize
;
293 // dont let mwm hints kill the close button
294 //if (! (_mwmhints.functions & MwmFunc_Close))
295 // _functions &= ~Func_Close;
299 // finally, user specified disabled decorations are applied to subtract
301 if (_disabled_decorations
& Decor_Titlebar
)
302 _decorations
&= ~Decor_Titlebar
;
303 if (_disabled_decorations
& Decor_Handle
)
304 _decorations
&= ~Decor_Handle
;
305 if (_disabled_decorations
& Decor_Border
)
306 _decorations
&= ~Decor_Border
;
307 if (_disabled_decorations
& Decor_Iconify
)
308 _decorations
&= ~Decor_Iconify
;
309 if (_disabled_decorations
& Decor_Maximize
)
310 _decorations
&= ~Decor_Maximize
;
311 if (_disabled_decorations
& Decor_AllDesktops
)
312 _decorations
&= ~Decor_AllDesktops
;
313 if (_disabled_decorations
& Decor_Close
)
314 _decorations
&= ~Decor_Close
;
316 // You can't shade without a titlebar
317 if (!(_decorations
& Decor_Titlebar
))
318 _functions
&= ~Func_Shade
;
320 changeAllowedActions();
323 frame
->adjustSize(); // change the decors on the frame
324 frame
->adjustPosition(); // with more/less decorations, we may need to be
330 void Client::getMwmHints()
332 unsigned long num
= MwmHints::elements
;
333 unsigned long *hints
;
335 _mwmhints
.flags
= 0; // default to none
337 if (!otk::Property::get(_window
, otk::Property::atoms
.motif_wm_hints
,
338 otk::Property::atoms
.motif_wm_hints
, &num
,
339 (unsigned long **)&hints
))
342 if (num
>= MwmHints::elements
) {
343 // retrieved the hints
344 _mwmhints
.flags
= hints
[0];
345 _mwmhints
.functions
= hints
[1];
346 _mwmhints
.decorations
= hints
[2];
353 void Client::getArea()
355 XWindowAttributes wattrib
;
358 ret
= XGetWindowAttributes(**otk::display
, _window
, &wattrib
);
359 assert(ret
!= BadWindow
);
361 _area
.setRect(wattrib
.x
, wattrib
.y
, wattrib
.width
, wattrib
.height
);
362 _border_width
= wattrib
.border_width
;
366 void Client::getState()
368 _modal
= _shaded
= _max_horz
= _max_vert
= _fullscreen
= _above
= _below
=
369 _iconic
= _skip_taskbar
= _skip_pager
= false;
371 unsigned long *state
;
372 unsigned long num
= (unsigned) -1;
374 if (otk::Property::get(_window
, otk::Property::atoms
.net_wm_state
,
375 otk::Property::atoms
.atom
, &num
, &state
)) {
376 for (unsigned long i
= 0; i
< num
; ++i
) {
377 if (state
[i
] == otk::Property::atoms
.net_wm_state_modal
)
379 else if (state
[i
] == otk::Property::atoms
.net_wm_state_shaded
)
381 else if (state
[i
] == otk::Property::atoms
.net_wm_state_hidden
)
383 else if (state
[i
] == otk::Property::atoms
.net_wm_state_skip_taskbar
)
384 _skip_taskbar
= true;
385 else if (state
[i
] == otk::Property::atoms
.net_wm_state_skip_pager
)
387 else if (state
[i
] == otk::Property::atoms
.net_wm_state_fullscreen
)
389 else if (state
[i
] == otk::Property::atoms
.net_wm_state_maximized_vert
)
391 else if (state
[i
] == otk::Property::atoms
.net_wm_state_maximized_horz
)
393 else if (state
[i
] == otk::Property::atoms
.net_wm_state_above
)
395 else if (state
[i
] == otk::Property::atoms
.net_wm_state_below
)
404 void Client::getShaped()
408 if (otk::display
->shape()) {
413 XShapeSelectInput(**otk::display
, _window
, ShapeNotifyMask
);
415 XShapeQueryExtents(**otk::display
, _window
, &s
, &foo
,
416 &foo
, &ufoo
, &ufoo
, &foo
, &foo
, &foo
, &ufoo
, &ufoo
);
423 void Client::calcLayer() {
426 if (_iconic
) l
= Layer_Icon
;
427 else if (_fullscreen
) l
= Layer_Fullscreen
;
428 else if (_type
== Type_Desktop
) l
= Layer_Desktop
;
429 else if (_type
== Type_Dock
) {
430 if (!_below
) l
= Layer_Top
;
431 else l
= Layer_Normal
;
433 else if (_above
) l
= Layer_Above
;
434 else if (_below
) l
= Layer_Below
;
435 else l
= Layer_Normal
;
441 if we don't have a frame, then we aren't mapped yet (and this would
444 openbox
->screen(_screen
)->raiseWindow(this);
450 void Client::updateProtocols()
455 _focus_notify
= false;
456 _delete_window
= false;
458 if (XGetWMProtocols(**otk::display
, _window
, &proto
, &num_return
)) {
459 for (int i
= 0; i
< num_return
; ++i
) {
460 if (proto
[i
] == otk::Property::atoms
.wm_delete_window
) {
461 // this means we can request the window to close
462 _delete_window
= true;
463 } else if (proto
[i
] == otk::Property::atoms
.wm_take_focus
)
464 // if this protocol is requested, then the window will be notified
465 // by the window manager whenever it receives focus
466 _focus_notify
= true;
473 void Client::updateNormalHints()
477 int oldgravity
= _gravity
;
482 _size_inc
.setPoint(1, 1);
483 _base_size
.setPoint(0, 0);
484 _min_size
.setPoint(0, 0);
485 _max_size
.setPoint(INT_MAX
, INT_MAX
);
487 // XXX: might want to cancel any interactive resizing of the window at this
490 // get the hints from the window
491 if (XGetWMNormalHints(**otk::display
, _window
, &size
, &ret
)) {
492 _positioned
= (size
.flags
& (PPosition
|USPosition
));
494 if (size
.flags
& PWinGravity
) {
495 _gravity
= size
.win_gravity
;
497 // if the client has a frame, i.e. has already been mapped and is
498 // changing its gravity
499 if (frame
&& _gravity
!= oldgravity
) {
500 // move our idea of the client's position based on its new gravity
501 int x
= frame
->rect().x(), y
= frame
->rect().y();
502 frame
->frameGravity(x
, y
);
507 if (size
.flags
& PAspect
) {
508 if (size
.min_aspect
.y
) _min_ratio
= size
.min_aspect
.x
/size
.min_aspect
.y
;
509 if (size
.max_aspect
.y
) _max_ratio
= size
.max_aspect
.x
/size
.max_aspect
.y
;
512 if (size
.flags
& PMinSize
)
513 _min_size
.setPoint(size
.min_width
, size
.min_height
);
515 if (size
.flags
& PMaxSize
)
516 _max_size
.setPoint(size
.max_width
, size
.max_height
);
518 if (size
.flags
& PBaseSize
)
519 _base_size
.setPoint(size
.base_width
, size
.base_height
);
521 if (size
.flags
& PResizeInc
)
522 _size_inc
.setPoint(size
.width_inc
, size
.height_inc
);
527 void Client::updateWMHints(bool initstate
)
531 // assume a window takes input if it doesnt specify
535 if ((hints
= XGetWMHints(**otk::display
, _window
)) != NULL
) {
536 if (hints
->flags
& InputHint
)
537 _can_focus
= hints
->input
;
539 // only do this when initstate is true!
540 if (initstate
&& (hints
->flags
& StateHint
))
541 _iconic
= hints
->initial_state
== IconicState
;
543 if (hints
->flags
& XUrgencyHint
)
546 if (hints
->flags
& WindowGroupHint
) {
547 if (hints
->window_group
!= _group
) {
548 // XXX: remove from the old group if there was one
549 _group
= hints
->window_group
;
550 // XXX: do stuff with the group
561 printf("DEBUG: Urgent Hint for 0x%lx: %s\n",
562 (long)_window
, _urgent
? "ON" : "OFF");
564 // fire the urgent callback if we're mapped, otherwise, wait until after
572 void Client::updateTitle()
577 if (!otk::Property::get(_window
, otk::Property::atoms
.net_wm_name
,
578 otk::Property::utf8
, &_title
)) {
580 otk::Property::get(_window
, otk::Property::atoms
.wm_name
,
581 otk::Property::ascii
, &_title
);
585 _title
= _("Unnamed Window");
588 frame
->setTitle(_title
);
592 void Client::updateIconTitle()
597 if (!otk::Property::get(_window
, otk::Property::atoms
.net_wm_icon_name
,
598 otk::Property::utf8
, &_icon_title
)) {
600 otk::Property::get(_window
, otk::Property::atoms
.wm_icon_name
,
601 otk::Property::ascii
, &_icon_title
);
605 _icon_title
= _("Unnamed Window");
609 void Client::updateClass()
612 _app_name
= _app_class
= _role
= "";
614 otk::Property::StringVect v
;
615 unsigned long num
= 2;
617 if (otk::Property::get(_window
, otk::Property::atoms
.wm_class
,
618 otk::Property::ascii
, &num
, &v
)) {
619 if (num
> 0) _app_name
= v
[0].c_str();
620 if (num
> 1) _app_class
= v
[1].c_str();
625 if (otk::Property::get(_window
, otk::Property::atoms
.wm_window_role
,
626 otk::Property::ascii
, &num
, &v
)) {
627 if (num
> 0) _role
= v
[0].c_str();
632 void Client::updateStrut()
634 unsigned long num
= 4;
636 if (!otk::Property::get(_window
, otk::Property::atoms
.net_wm_strut
,
637 otk::Property::atoms
.cardinal
, &num
, &data
))
641 _strut
.left
= data
[0];
642 _strut
.right
= data
[1];
643 _strut
.top
= data
[2];
644 _strut
.bottom
= data
[3];
646 // updating here is pointless while we're being mapped cuz we're not in
647 // the screen's client list yet
649 openbox
->screen(_screen
)->updateStrut();
656 void Client::updateTransientFor()
661 if (XGetTransientForHint(**otk::display
, _window
, &t
) &&
662 t
!= _window
) { // cant be transient to itself!
663 c
= openbox
->findClient(t
);
664 assert(c
!= this); // if this happens then we need to check for it
666 if (!c
/*XXX: && _group*/) {
667 // not transient to a client, see if it is transient for a group
668 if (//t == _group->leader() ||
670 t
== otk::display
->screenInfo(_screen
)->rootWindow()) {
671 // window is a transient for its group!
672 // XXX: for now this is treated as non-transient.
673 // this needs to be fixed!
678 // if anything has changed...
679 if (c
!= _transient_for
) {
681 _transient_for
->_transients
.remove(this); // remove from old parent
684 _transient_for
->_transients
.push_back(this); // add to new parent
686 // XXX: change decor status?
691 void Client::propertyHandler(const XPropertyEvent
&e
)
693 otk::EventHandler::propertyHandler(e
);
695 // validate cuz we query stuff off the client here
696 if (!validate()) return;
698 // compress changes to a single property into a single change
700 while (XCheckTypedEvent(**otk::display
, e
.type
, &ce
)) {
701 // XXX: it would be nice to compress ALL changes to a property, not just
702 // changes in a row without other props between.
703 if (ce
.xproperty
.atom
!= e
.atom
) {
704 XPutBackEvent(**otk::display
, &ce
);
709 if (e
.atom
== XA_WM_NORMAL_HINTS
) {
711 setupDecorAndFunctions(); // normal hints can make a window non-resizable
712 } else if (e
.atom
== XA_WM_HINTS
)
714 else if (e
.atom
== XA_WM_TRANSIENT_FOR
) {
715 updateTransientFor();
717 calcLayer(); // type may have changed, so update the layer
718 setupDecorAndFunctions();
720 else if (e
.atom
== otk::Property::atoms
.net_wm_name
||
721 e
.atom
== otk::Property::atoms
.wm_name
)
723 else if (e
.atom
== otk::Property::atoms
.net_wm_icon_name
||
724 e
.atom
== otk::Property::atoms
.wm_icon_name
)
726 else if (e
.atom
== otk::Property::atoms
.wm_class
)
728 else if (e
.atom
== otk::Property::atoms
.wm_protocols
) {
730 setupDecorAndFunctions();
732 else if (e
.atom
== otk::Property::atoms
.net_wm_strut
)
737 void Client::setWMState(long state
)
739 if (state
== _wmstate
) return; // no change
743 setDesktop(ICONIC_DESKTOP
);
746 setDesktop(openbox
->screen(_screen
)->desktop());
752 void Client::setDesktop(long target
)
754 if (target
== _desktop
) return;
756 printf("Setting desktop %ld\n", target
);
758 if (!(target
>= 0 || target
== (signed)0xffffffff ||
759 target
== ICONIC_DESKTOP
))
764 // set the desktop hint, but not if we're iconifying
765 if (_desktop
!= ICONIC_DESKTOP
)
766 otk::Property::set(_window
, otk::Property::atoms
.net_wm_desktop
,
767 otk::Property::atoms
.cardinal
, (unsigned)_desktop
);
769 // 'move' the window to the new desktop
770 if (_desktop
== openbox
->screen(_screen
)->desktop() ||
771 _desktop
== (signed)0xffffffff)
776 // Handle Iconic state. Iconic state is maintained by the client being a
777 // member of the ICONIC_DESKTOP, so this is where we make iconifying and
778 // uniconifying happen.
779 bool i
= _desktop
== ICONIC_DESKTOP
;
780 if (i
!= _iconic
) { // has the state changed?
783 _wmstate
= IconicState
;
785 // we unmap the client itself so that we can get MapRequest events, and
786 // because the ICCCM tells us to!
787 XUnmapWindow(**otk::display
, _window
);
789 _wmstate
= NormalState
;
790 XMapWindow(**otk::display
, _window
);
795 frame
->adjustState();
799 void Client::setState(StateAction action
, long data1
, long data2
)
801 bool shadestate
= _shaded
;
802 bool fsstate
= _fullscreen
;
803 bool maxh
= _max_horz
;
804 bool maxv
= _max_vert
;
806 if (!(action
== State_Add
|| action
== State_Remove
||
807 action
== State_Toggle
))
808 return; // an invalid action was passed to the client message, ignore it
810 for (int i
= 0; i
< 2; ++i
) {
811 Atom state
= i
== 0 ? data1
: data2
;
813 if (! state
) continue;
815 // if toggling, then pick whether we're adding or removing
816 if (action
== State_Toggle
) {
817 if (state
== otk::Property::atoms
.net_wm_state_modal
)
818 action
= _modal
? State_Remove
: State_Add
;
819 else if (state
== otk::Property::atoms
.net_wm_state_maximized_vert
)
820 action
= _max_vert
? State_Remove
: State_Add
;
821 else if (state
== otk::Property::atoms
.net_wm_state_maximized_horz
)
822 action
= _max_horz
? State_Remove
: State_Add
;
823 else if (state
== otk::Property::atoms
.net_wm_state_shaded
)
824 action
= _shaded
? State_Remove
: State_Add
;
825 else if (state
== otk::Property::atoms
.net_wm_state_skip_taskbar
)
826 action
= _skip_taskbar
? State_Remove
: State_Add
;
827 else if (state
== otk::Property::atoms
.net_wm_state_skip_pager
)
828 action
= _skip_pager
? State_Remove
: State_Add
;
829 else if (state
== otk::Property::atoms
.net_wm_state_fullscreen
)
830 action
= _fullscreen
? State_Remove
: State_Add
;
831 else if (state
== otk::Property::atoms
.net_wm_state_above
)
832 action
= _above
? State_Remove
: State_Add
;
833 else if (state
== otk::Property::atoms
.net_wm_state_below
)
834 action
= _below
? State_Remove
: State_Add
;
837 if (action
== State_Add
) {
838 if (state
== otk::Property::atoms
.net_wm_state_modal
) {
839 if (_modal
) continue;
841 // XXX: give it focus if another window has focus that shouldnt now
842 } else if (state
== otk::Property::atoms
.net_wm_state_maximized_vert
) {
844 } else if (state
== otk::Property::atoms
.net_wm_state_maximized_horz
) {
845 if (_max_horz
) continue;
847 // XXX: resize the window etc
848 } else if (state
== otk::Property::atoms
.net_wm_state_shaded
) {
850 } else if (state
== otk::Property::atoms
.net_wm_state_skip_taskbar
) {
851 _skip_taskbar
= true;
852 } else if (state
== otk::Property::atoms
.net_wm_state_skip_pager
) {
854 } else if (state
== otk::Property::atoms
.net_wm_state_fullscreen
) {
856 } else if (state
== otk::Property::atoms
.net_wm_state_above
) {
857 if (_above
) continue;
859 } else if (state
== otk::Property::atoms
.net_wm_state_below
) {
860 if (_below
) continue;
864 } else { // action == State_Remove
865 if (state
== otk::Property::atoms
.net_wm_state_modal
) {
866 if (!_modal
) continue;
868 } else if (state
== otk::Property::atoms
.net_wm_state_maximized_vert
) {
870 } else if (state
== otk::Property::atoms
.net_wm_state_maximized_horz
) {
872 } else if (state
== otk::Property::atoms
.net_wm_state_shaded
) {
874 } else if (state
== otk::Property::atoms
.net_wm_state_skip_taskbar
) {
875 _skip_taskbar
= false;
876 } else if (state
== otk::Property::atoms
.net_wm_state_skip_pager
) {
878 } else if (state
== otk::Property::atoms
.net_wm_state_fullscreen
) {
880 } else if (state
== otk::Property::atoms
.net_wm_state_above
) {
881 if (!_above
) continue;
883 } else if (state
== otk::Property::atoms
.net_wm_state_below
) {
884 if (!_below
) continue;
889 if (maxh
!= _max_horz
|| maxv
!= _max_vert
) {
890 if (maxh
!= _max_horz
&& maxv
!= _max_vert
) { // toggling both
891 if (maxh
== maxv
) { // both going the same way
892 maximize(maxh
, 0, true);
894 maximize(maxh
, 1, true);
895 maximize(maxv
, 2, true);
897 } else { // toggling one
898 if (maxh
!= _max_horz
)
899 maximize(maxh
, 1, true);
901 maximize(maxv
, 2, true);
904 // change fullscreen state before shading, as it will affect if the window
906 if (fsstate
!= _fullscreen
)
907 fullscreen(fsstate
, true);
908 if (shadestate
!= _shaded
)
911 changeState(); // change the hint to relect these changes
915 void Client::toggleClientBorder(bool addborder
)
917 // adjust our idea of where the client is, based on its border. When the
918 // border is removed, the client should now be considered to be in a
919 // different position.
920 // when re-adding the border to the client, the same operation needs to be
922 int oldx
= _area
.x(), oldy
= _area
.y();
923 int x
= oldx
, y
= oldy
;
926 case NorthWestGravity
:
928 case SouthWestGravity
:
930 case NorthEastGravity
:
932 case SouthEastGravity
:
933 if (addborder
) x
-= _border_width
* 2;
934 else x
+= _border_width
* 2;
941 if (addborder
) x
-= _border_width
;
942 else x
+= _border_width
;
947 case NorthWestGravity
:
949 case NorthEastGravity
:
951 case SouthWestGravity
:
953 case SouthEastGravity
:
954 if (addborder
) y
-= _border_width
* 2;
955 else y
+= _border_width
* 2;
962 if (addborder
) y
-= _border_width
;
963 else y
+= _border_width
;
969 XSetWindowBorderWidth(**otk::display
, _window
, _border_width
);
971 // move the client so it is back it the right spot _with_ its border!
972 if (x
!= oldx
|| y
!= oldy
)
973 XMoveWindow(**otk::display
, _window
, x
, y
);
975 XSetWindowBorderWidth(**otk::display
, _window
, 0);
979 void Client::clientMessageHandler(const XClientMessageEvent
&e
)
981 otk::EventHandler::clientMessageHandler(e
);
983 // validate cuz we query stuff off the client here
984 if (!validate()) return;
986 if (e
.format
!= 32) return;
988 if (e
.message_type
== otk::Property::atoms
.wm_change_state
) {
989 // compress changes into a single change
990 bool compress
= false;
992 while (XCheckTypedEvent(**otk::display
, e
.type
, &ce
)) {
993 // XXX: it would be nice to compress ALL messages of a type, not just
994 // messages in a row without other message types between.
995 if (ce
.xclient
.message_type
!= e
.message_type
) {
996 XPutBackEvent(**otk::display
, &ce
);
1002 setWMState(ce
.xclient
.data
.l
[0]); // use the found event
1004 setWMState(e
.data
.l
[0]); // use the original event
1005 } else if (e
.message_type
== otk::Property::atoms
.net_wm_desktop
) {
1006 // compress changes into a single change
1007 bool compress
= false;
1009 while (XCheckTypedEvent(**otk::display
, e
.type
, &ce
)) {
1010 // XXX: it would be nice to compress ALL messages of a type, not just
1011 // messages in a row without other message types between.
1012 if (ce
.xclient
.message_type
!= e
.message_type
) {
1013 XPutBackEvent(**otk::display
, &ce
);
1019 setDesktop(e
.data
.l
[0]); // use the found event
1021 setDesktop(e
.data
.l
[0]); // use the original event
1022 } else if (e
.message_type
== otk::Property::atoms
.net_wm_state
) {
1023 // can't compress these
1025 printf("net_wm_state %s %ld %ld for 0x%lx\n",
1026 (e
.data
.l
[0] == 0 ? "Remove" : e
.data
.l
[0] == 1 ? "Add" :
1027 e
.data
.l
[0] == 2 ? "Toggle" : "INVALID"),
1028 e
.data
.l
[1], e
.data
.l
[2], _window
);
1030 setState((StateAction
)e
.data
.l
[0], e
.data
.l
[1], e
.data
.l
[2]);
1031 } else if (e
.message_type
== otk::Property::atoms
.net_close_window
) {
1033 printf("net_close_window for 0x%lx\n", _window
);
1036 } else if (e
.message_type
== otk::Property::atoms
.net_active_window
) {
1038 printf("net_active_window for 0x%lx\n", _window
);
1041 setDesktop(openbox
->screen(_screen
)->desktop());
1046 openbox
->screen(_screen
)->raiseWindow(this);
1052 void Client::shapeHandler(const XShapeEvent
&e
)
1054 otk::EventHandler::shapeHandler(e
);
1056 if (e
.kind
== ShapeBounding
) {
1058 frame
->adjustShape();
1064 void Client::resize(Corner anchor
, int w
, int h
)
1066 if (!(_functions
& Func_Resize
)) return;
1067 internal_resize(anchor
, w
, h
);
1071 void Client::internal_resize(Corner anchor
, int w
, int h
, bool user
,
1074 w
-= _base_size
.x();
1075 h
-= _base_size
.y();
1078 // for interactive resizing. have to move half an increment in each
1080 int mw
= w
% _size_inc
.x(); // how far we are towards the next size inc
1081 int mh
= h
% _size_inc
.y();
1082 int aw
= _size_inc
.x() / 2; // amount to add
1083 int ah
= _size_inc
.y() / 2;
1084 // don't let us move into a new size increment
1085 if (mw
+ aw
>= _size_inc
.x()) aw
= _size_inc
.x() - mw
- 1;
1086 if (mh
+ ah
>= _size_inc
.y()) ah
= _size_inc
.y() - mh
- 1;
1090 // if this is a user-requested resize, then check against min/max sizes
1091 // and aspect ratios
1093 // smaller than min size or bigger than max size?
1094 if (w
< _min_size
.x()) w
= _min_size
.x();
1095 else if (w
> _max_size
.x()) w
= _max_size
.x();
1096 if (h
< _min_size
.y()) h
= _min_size
.y();
1097 else if (h
> _max_size
.y()) h
= _max_size
.y();
1099 // adjust the height ot match the width for the aspect ratios
1101 if (h
* _min_ratio
> w
) h
= static_cast<int>(w
/ _min_ratio
);
1103 if (h
* _max_ratio
< w
) h
= static_cast<int>(w
/ _max_ratio
);
1106 // keep to the increments
1110 // you cannot resize to nothing
1114 // store the logical size
1115 _logical_size
.setPoint(w
, h
);
1120 w
+= _base_size
.x();
1121 h
+= _base_size
.y();
1123 if (x
== INT_MIN
|| y
== INT_MIN
) {
1130 x
-= w
- _area
.width();
1133 y
-= h
- _area
.height();
1136 x
-= w
- _area
.width();
1137 y
-= h
- _area
.height();
1142 _area
.setSize(w
, h
);
1144 XResizeWindow(**otk::display
, _window
, w
, h
);
1146 // resize the frame to match the request
1147 frame
->adjustSize();
1148 internal_move(x
, y
);
1152 void Client::move(int x
, int y
)
1154 if (!(_functions
& Func_Move
)) return;
1155 frame
->frameGravity(x
, y
); // get the client's position based on x,y for the
1157 internal_move(x
, y
);
1161 void Client::internal_move(int x
, int y
)
1165 // move the frame to be in the requested position
1166 if (frame
) { // this can be called while mapping, before frame exists
1167 frame
->adjustPosition();
1169 // send synthetic configure notify (we don't need to if we aren't mapped
1172 event
.type
= ConfigureNotify
;
1173 event
.xconfigure
.display
= **otk::display
;
1174 event
.xconfigure
.event
= _window
;
1175 event
.xconfigure
.window
= _window
;
1177 // root window coords with border in mind
1178 event
.xconfigure
.x
= x
- _border_width
+ frame
->size().left
;
1179 event
.xconfigure
.y
= y
- _border_width
+ frame
->size().top
;
1181 event
.xconfigure
.width
= _area
.width();
1182 event
.xconfigure
.height
= _area
.height();
1183 event
.xconfigure
.border_width
= _border_width
;
1184 event
.xconfigure
.above
= frame
->plate();
1185 event
.xconfigure
.override_redirect
= False
;
1186 XSendEvent(event
.xconfigure
.display
, event
.xconfigure
.window
, False
,
1187 StructureNotifyMask
, &event
);
1189 printf("Sent synthetic ConfigureNotify %d,%d %d,%d to 0x%lx\n",
1190 event
.xconfigure
.x
, event
.xconfigure
.y
, event
.xconfigure
.width
,
1191 event
.xconfigure
.height
, event
.xconfigure
.window
);
1197 void Client::close()
1201 if (!(_functions
& Func_Close
)) return;
1203 // XXX: itd be cool to do timeouts and shit here for killing the client's
1205 // like... if the window is around after 5 seconds, then the close button
1206 // turns a nice red, and if this function is called again, the client is
1207 // explicitly killed.
1209 ce
.xclient
.type
= ClientMessage
;
1210 ce
.xclient
.message_type
= otk::Property::atoms
.wm_protocols
;
1211 ce
.xclient
.display
= **otk::display
;
1212 ce
.xclient
.window
= _window
;
1213 ce
.xclient
.format
= 32;
1214 ce
.xclient
.data
.l
[0] = otk::Property::atoms
.wm_delete_window
;
1215 ce
.xclient
.data
.l
[1] = CurrentTime
;
1216 ce
.xclient
.data
.l
[2] = 0l;
1217 ce
.xclient
.data
.l
[3] = 0l;
1218 ce
.xclient
.data
.l
[4] = 0l;
1219 XSendEvent(**otk::display
, _window
, false, NoEventMask
, &ce
);
1223 void Client::changeState()
1225 unsigned long state
[2];
1226 state
[0] = _wmstate
;
1228 otk::Property::set(_window
, otk::Property::atoms
.wm_state
,
1229 otk::Property::atoms
.wm_state
, state
, 2);
1234 netstate
[num
++] = otk::Property::atoms
.net_wm_state_modal
;
1236 netstate
[num
++] = otk::Property::atoms
.net_wm_state_shaded
;
1238 netstate
[num
++] = otk::Property::atoms
.net_wm_state_hidden
;
1240 netstate
[num
++] = otk::Property::atoms
.net_wm_state_skip_taskbar
;
1242 netstate
[num
++] = otk::Property::atoms
.net_wm_state_skip_pager
;
1244 netstate
[num
++] = otk::Property::atoms
.net_wm_state_fullscreen
;
1246 netstate
[num
++] = otk::Property::atoms
.net_wm_state_maximized_vert
;
1248 netstate
[num
++] = otk::Property::atoms
.net_wm_state_maximized_horz
;
1250 netstate
[num
++] = otk::Property::atoms
.net_wm_state_above
;
1252 netstate
[num
++] = otk::Property::atoms
.net_wm_state_below
;
1253 otk::Property::set(_window
, otk::Property::atoms
.net_wm_state
,
1254 otk::Property::atoms
.atom
, netstate
, num
);
1259 frame
->adjustState();
1263 void Client::changeAllowedActions(void)
1268 actions
[num
++] = otk::Property::atoms
.net_wm_action_change_desktop
;
1270 if (_functions
& Func_Shade
)
1271 actions
[num
++] = otk::Property::atoms
.net_wm_action_shade
;
1272 if (_functions
& Func_Close
)
1273 actions
[num
++] = otk::Property::atoms
.net_wm_action_close
;
1274 if (_functions
& Func_Move
)
1275 actions
[num
++] = otk::Property::atoms
.net_wm_action_move
;
1276 if (_functions
& Func_Iconify
)
1277 actions
[num
++] = otk::Property::atoms
.net_wm_action_minimize
;
1278 if (_functions
& Func_Resize
)
1279 actions
[num
++] = otk::Property::atoms
.net_wm_action_resize
;
1280 if (_functions
& Func_Fullscreen
)
1281 actions
[num
++] = otk::Property::atoms
.net_wm_action_fullscreen
;
1282 if (_functions
& Func_Maximize
) {
1283 actions
[num
++] = otk::Property::atoms
.net_wm_action_maximize_horz
;
1284 actions
[num
++] = otk::Property::atoms
.net_wm_action_maximize_vert
;
1287 otk::Property::set(_window
, otk::Property::atoms
.net_wm_allowed_actions
,
1288 otk::Property::atoms
.atom
, actions
, num
);
1292 void Client::remaximize()
1295 if (_max_horz
&& _max_vert
)
1302 return; // not maximized
1303 _max_horz
= _max_vert
= false;
1304 maximize(true, dir
, false);
1308 void Client::applyStartupState()
1310 // these are in a carefully crafted order..
1314 setDesktop(ICONIC_DESKTOP
);
1317 _fullscreen
= false;
1318 fullscreen(true, false);
1327 if (_max_vert
&& _max_horz
) {
1328 _max_vert
= _max_horz
= false;
1329 maximize(true, 0, false);
1330 } else if (_max_vert
) {
1332 maximize(true, 2, false);
1333 } else if (_max_horz
) {
1335 maximize(true, 1, false);
1338 if (_skip_taskbar
); // nothing to do for this
1339 if (_skip_pager
); // nothing to do for this
1340 if (_modal
); // nothing to do for this
1341 if (_above
); // nothing to do for this
1342 if (_below
); // nothing to do for this
1346 void Client::fireUrgent()
1348 // call the python UrgentWindow callbacks
1349 EventData
data(_screen
, this, EventAction::UrgentWindow
, 0);
1350 openbox
->bindings()->fireEvent(&data
);
1354 void Client::shade(bool shade
)
1356 if (!(_functions
& Func_Shade
) || // can't
1357 _shaded
== shade
) return; // already done
1359 // when we're iconic, don't change the wmstate
1361 _wmstate
= shade
? IconicState
: NormalState
;
1364 frame
->adjustSize();
1368 void Client::maximize(bool max
, int dir
, bool savearea
)
1370 assert(dir
== 0 || dir
== 1 || dir
== 2);
1371 if (!(_functions
& Func_Maximize
)) return; // can't
1373 // check if already done
1375 if (dir
== 0 && _max_horz
&& _max_vert
) return;
1376 if (dir
== 1 && _max_horz
) return;
1377 if (dir
== 2 && _max_vert
) return;
1379 if (dir
== 0 && !_max_horz
&& !_max_vert
) return;
1380 if (dir
== 1 && !_max_horz
) return;
1381 if (dir
== 2 && !_max_vert
) return;
1384 const otk::Rect
&a
= openbox
->screen(_screen
)->area();
1385 int x
= frame
->rect().x(), y
= frame
->rect().y(),
1386 w
= _area
.width(), h
= _area
.height();
1392 unsigned long n
= 4;
1399 // get the property off the window and use it for the dimentions we are
1401 if (otk::Property::get(_window
, otk::Property::atoms
.openbox_premax
,
1402 otk::Property::atoms
.cardinal
, &n
,
1403 (long unsigned**) &readdim
)) {
1406 dimensions
[0] = readdim
[0];
1407 dimensions
[2] = readdim
[2];
1410 dimensions
[1] = readdim
[1];
1411 dimensions
[3] = readdim
[3];
1417 otk::Property::set(_window
, otk::Property::atoms
.openbox_premax
,
1418 otk::Property::atoms
.cardinal
,
1419 (long unsigned*)dimensions
, 4);
1421 if (dir
== 0 || dir
== 1) { // horz
1425 if (dir
== 0 || dir
== 2) { // vert
1427 h
= a
.height() - frame
->size().top
- frame
->size().bottom
;
1431 long unsigned n
= 4;
1433 if (otk::Property::get(_window
, otk::Property::atoms
.openbox_premax
,
1434 otk::Property::atoms
.cardinal
, &n
,
1435 (long unsigned**) &dimensions
)) {
1437 if (dir
== 0 || dir
== 1) { // horz
1438 x
= (signed int)dimensions
[0];
1439 w
= (signed int)dimensions
[2];
1441 if (dir
== 0 || dir
== 2) { // vert
1442 y
= (signed int)dimensions
[1];
1443 h
= (signed int)dimensions
[3];
1448 // pick some fallbacks...
1449 if (dir
== 0 || dir
== 1) { // horz
1450 x
= a
.x() + a
.width() / 4;
1453 if (dir
== 0 || dir
== 2) { // vert
1454 y
= a
.y() + a
.height() / 4;
1460 if (dir
== 0 || dir
== 1) // horz
1462 if (dir
== 0 || dir
== 2) // vert
1465 if (!_max_horz
&& !_max_vert
)
1466 otk::Property::erase(_window
, otk::Property::atoms
.openbox_premax
);
1468 changeState(); // change the state hints on the client
1470 frame
->frameGravity(x
, y
); // figure out where the client should be going
1471 internal_resize(TopLeft
, w
, h
, true, x
, y
);
1475 void Client::fullscreen(bool fs
, bool savearea
)
1477 static FunctionFlags saved_func
;
1478 static DecorationFlags saved_decor
;
1480 if (!(_functions
& Func_Fullscreen
) || // can't
1481 _fullscreen
== fs
) return; // already done
1484 changeState(); // change the state hints on the client
1486 int x
= _area
.x(), y
= _area
.y(), w
= _area
.width(), h
= _area
.height();
1489 // save the functions and remove them
1490 saved_func
= _functions
;
1491 _functions
= _functions
& (Func_Close
| Func_Fullscreen
| Func_Iconify
);
1492 // save the decorations and remove them
1493 saved_decor
= _decorations
;
1497 dimensions
[0] = _area
.x();
1498 dimensions
[1] = _area
.y();
1499 dimensions
[2] = _area
.width();
1500 dimensions
[3] = _area
.height();
1501 otk::Property::set(_window
, otk::Property::atoms
.openbox_premax
,
1502 otk::Property::atoms
.cardinal
,
1503 (long unsigned*)dimensions
, 4);
1505 const otk::ScreenInfo
*info
= otk::display
->screenInfo(_screen
);
1511 _functions
= saved_func
;
1512 _decorations
= saved_decor
;
1515 long unsigned n
= 4;
1517 if (otk::Property::get(_window
, otk::Property::atoms
.openbox_premax
,
1518 otk::Property::atoms
.cardinal
, &n
,
1519 (long unsigned**) &dimensions
)) {
1528 // pick some fallbacks...
1529 const otk::Rect
&a
= openbox
->screen(_screen
)->area();
1530 x
= a
.x() + a
.width() / 4;
1531 y
= a
.y() + a
.height() / 4;
1537 changeAllowedActions(); // based on the new _functions
1539 // when fullscreening, don't obey things like increments, fill the screen
1540 internal_resize(TopLeft
, w
, h
, !fs
, x
, y
);
1542 // raise (back) into our stacking layer
1543 openbox
->screen(_screen
)->raiseWindow(this);
1545 // try focus us when we go into fullscreen mode
1550 void Client::disableDecorations(DecorationFlags flags
)
1552 _disabled_decorations
= flags
;
1553 setupDecorAndFunctions();
1557 bool Client::focus()
1559 // won't try focus if the client doesn't want it, or if the window isn't
1560 // visible on the screen
1561 if (!(frame
->isVisible() && (_can_focus
|| _focus_notify
))) return false;
1563 if (_focused
) return true;
1565 // do a check to see if the window has already been unmapped or destroyed
1566 // do this intelligently while watching out for unmaps we've generated
1567 // (ignore_unmaps > 0)
1569 if (XCheckTypedWindowEvent(**otk::display
, _window
, DestroyNotify
, &ev
)) {
1570 XPutBackEvent(**otk::display
, &ev
);
1573 while (XCheckTypedWindowEvent(**otk::display
, _window
, UnmapNotify
, &ev
)) {
1574 if (ignore_unmaps
) {
1575 unmapHandler(ev
.xunmap
);
1577 XPutBackEvent(**otk::display
, &ev
);
1583 XSetInputFocus(**otk::display
, _window
,
1584 RevertToNone
, CurrentTime
);
1586 if (_focus_notify
) {
1588 ce
.xclient
.type
= ClientMessage
;
1589 ce
.xclient
.message_type
= otk::Property::atoms
.wm_protocols
;
1590 ce
.xclient
.display
= **otk::display
;
1591 ce
.xclient
.window
= _window
;
1592 ce
.xclient
.format
= 32;
1593 ce
.xclient
.data
.l
[0] = otk::Property::atoms
.wm_take_focus
;
1594 ce
.xclient
.data
.l
[1] = openbox
->lastTime();
1595 ce
.xclient
.data
.l
[2] = 0l;
1596 ce
.xclient
.data
.l
[3] = 0l;
1597 ce
.xclient
.data
.l
[4] = 0l;
1598 XSendEvent(**otk::display
, _window
, False
, NoEventMask
, &ce
);
1601 XSync(**otk::display
, False
);
1606 void Client::unfocus() const
1608 if (!_focused
) return;
1610 assert(openbox
->focusedClient() == this);
1611 openbox
->setFocusedClient(0);
1615 void Client::focusHandler(const XFocusChangeEvent
&e
)
1618 // printf("FocusIn for 0x%lx\n", e.window);
1621 otk::EventHandler::focusHandler(e
);
1626 openbox
->setFocusedClient(this);
1630 void Client::unfocusHandler(const XFocusChangeEvent
&e
)
1633 // printf("FocusOut for 0x%lx\n", e.window);
1636 otk::EventHandler::unfocusHandler(e
);
1641 if (openbox
->focusedClient() == this)
1642 openbox
->setFocusedClient(0);
1646 void Client::configureRequestHandler(const XConfigureRequestEvent
&e
)
1649 printf("ConfigureRequest for 0x%lx\n", e
.window
);
1652 otk::EventHandler::configureRequestHandler(e
);
1654 // if we are iconic (or shaded (fvwm does this)) ignore the event
1655 if (_iconic
|| _shaded
) return;
1657 if (e
.value_mask
& CWBorderWidth
)
1658 _border_width
= e
.border_width
;
1660 // resize, then move, as specified in the EWMH section 7.7
1661 if (e
.value_mask
& (CWWidth
| CWHeight
)) {
1662 int w
= (e
.value_mask
& CWWidth
) ? e
.width
: _area
.width();
1663 int h
= (e
.value_mask
& CWHeight
) ? e
.height
: _area
.height();
1667 case NorthEastGravity
:
1671 case SouthWestGravity
:
1673 corner
= BottomLeft
;
1675 case SouthEastGravity
:
1676 corner
= BottomRight
;
1678 default: // NorthWest, Static, etc
1682 // if moving AND resizing ...
1683 if (e
.value_mask
& (CWX
| CWY
)) {
1684 int x
= (e
.value_mask
& CWX
) ? e
.x
: _area
.x();
1685 int y
= (e
.value_mask
& CWY
) ? e
.y
: _area
.y();
1686 internal_resize(corner
, w
, h
, false, x
, y
);
1687 } else // if JUST resizing...
1688 internal_resize(corner
, w
, h
, false);
1689 } else if (e
.value_mask
& (CWX
| CWY
)) { // if JUST moving...
1690 int x
= (e
.value_mask
& CWX
) ? e
.x
: _area
.x();
1691 int y
= (e
.value_mask
& CWY
) ? e
.y
: _area
.y();
1692 internal_move(x
, y
);
1695 if (e
.value_mask
& CWStackMode
) {
1699 openbox
->screen(_screen
)->lowerWindow(this);
1705 openbox
->screen(_screen
)->raiseWindow(this);
1712 void Client::unmapHandler(const XUnmapEvent
&e
)
1714 if (ignore_unmaps
) {
1716 // printf("Ignored UnmapNotify for 0x%lx (event 0x%lx)\n", e.window, e.event);
1723 printf("UnmapNotify for 0x%lx\n", e
.window
);
1726 otk::EventHandler::unmapHandler(e
);
1728 // this deletes us etc
1729 openbox
->screen(_screen
)->unmanageWindow(this);
1733 void Client::destroyHandler(const XDestroyWindowEvent
&e
)
1736 printf("DestroyNotify for 0x%lx\n", e
.window
);
1739 otk::EventHandler::destroyHandler(e
);
1741 // this deletes us etc
1742 openbox
->screen(_screen
)->unmanageWindow(this);
1746 void Client::reparentHandler(const XReparentEvent
&e
)
1748 // this is when the client is first taken captive in the frame
1749 if (e
.parent
== frame
->plate()) return;
1752 printf("ReparentNotify for 0x%lx\n", e
.window
);
1755 otk::EventHandler::reparentHandler(e
);
1758 This event is quite rare and is usually handled in unmapHandler.
1759 However, if the window is unmapped when the reparent event occurs,
1760 the window manager never sees it because an unmap event is not sent
1761 to an already unmapped window.
1764 // we don't want the reparent event, put it back on the stack for the X
1765 // server to deal with after we unmanage the window
1768 XPutBackEvent(**otk::display
, &ev
);
1770 // this deletes us etc
1771 openbox
->screen(_screen
)->unmanageWindow(this);
1774 void Client::mapRequestHandler(const XMapRequestEvent
&e
)
1777 printf("MapRequest for already managed 0x%lx\n", e
.window
);
1780 assert(_iconic
); // we shouldn't be able to get this unless we're iconic
1782 // move to the current desktop (uniconify)
1783 setDesktop(openbox
->screen(_screen
)->desktop());
1784 // XXX: should we focus/raise the window? (basically a net_wm_active_window)