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;
56 // no modal children until they set themselves
64 getType(); // this can change the mwmhints for special cases
71 getGravity(); // get the attribute gravity
72 updateNormalHints(); // this may override the attribute gravity
74 // got the type, the mwmhints, the protocols, and the normal hints (min/max
75 // sizes), so we're ready to set up
76 // the decorations/functions
77 setupDecorAndFunctions();
79 // also get the initial_state and set _iconic if we aren't "starting"
80 // when we're "starting" that means we should use whatever state was already
81 // on the window over the initial map state, because it was already mapped
82 updateWMHints(openbox
->state() != Openbox::State_Starting
);
88 // this makes sure that these windows appear on all desktops
89 if (/*_type == Type_Dock ||*/ _type
== Type_Desktop
)
90 _desktop
= 0xffffffff;
92 // set the desktop hint, to make sure that it always exists, and to reflect
93 // any changes we've made here
94 otk::Property::set(_window
, otk::Property::atoms
.net_wm_desktop
,
95 otk::Property::atoms
.cardinal
, (unsigned)_desktop
);
103 // clean up childrens' references
104 while (!_transients
.empty()) {
105 _transients
.front()->_transient_for
= 0;
106 _transients
.pop_front();
109 // clean up parents reference to this
113 _transient_for
->_transients
.remove(this); // remove from old parent
115 if (openbox
->state() != Openbox::State_Exiting
) {
116 // these values should not be persisted across a window unmapping/mapping
117 otk::Property::erase(_window
, otk::Property::atoms
.net_wm_desktop
);
118 otk::Property::erase(_window
, otk::Property::atoms
.net_wm_state
);
120 // if we're left in an iconic state, the client wont be mapped. this is
121 // bad, since we will no longer be managing the window on restart
123 XMapWindow(**otk::display
, _window
);
128 bool Client::validate() const
130 XSync(**otk::display
, false); // get all events on the server
133 if (XCheckTypedWindowEvent(**otk::display
, _window
, DestroyNotify
, &e
) ||
134 XCheckTypedWindowEvent(**otk::display
, _window
, UnmapNotify
, &e
)) {
135 XPutBackEvent(**otk::display
, &e
);
143 void Client::getGravity()
145 XWindowAttributes wattrib
;
148 ret
= XGetWindowAttributes(**otk::display
, _window
, &wattrib
);
149 assert(ret
!= BadWindow
);
150 _gravity
= wattrib
.win_gravity
;
154 void Client::getDesktop()
156 // defaults to the current desktop
157 _desktop
= openbox
->screen(_screen
)->desktop();
159 if (otk::Property::get(_window
, otk::Property::atoms
.net_wm_desktop
,
160 otk::Property::atoms
.cardinal
,
161 (long unsigned*)&_desktop
)) {
163 // printf("Window requested desktop: %ld\n", _desktop);
169 void Client::getType()
171 _type
= (WindowType
) -1;
174 unsigned long num
= (unsigned) -1;
175 if (otk::Property::get(_window
, otk::Property::atoms
.net_wm_window_type
,
176 otk::Property::atoms
.atom
, &num
, &val
)) {
177 // use the first value that we know about in the array
178 for (unsigned long i
= 0; i
< num
; ++i
) {
179 if (val
[i
] == otk::Property::atoms
.net_wm_window_type_desktop
)
180 _type
= Type_Desktop
;
181 else if (val
[i
] == otk::Property::atoms
.net_wm_window_type_dock
)
183 else if (val
[i
] == otk::Property::atoms
.net_wm_window_type_toolbar
)
184 _type
= Type_Toolbar
;
185 else if (val
[i
] == otk::Property::atoms
.net_wm_window_type_menu
)
187 else if (val
[i
] == otk::Property::atoms
.net_wm_window_type_utility
)
188 _type
= Type_Utility
;
189 else if (val
[i
] == otk::Property::atoms
.net_wm_window_type_splash
)
191 else if (val
[i
] == otk::Property::atoms
.net_wm_window_type_dialog
)
193 else if (val
[i
] == otk::Property::atoms
.net_wm_window_type_normal
)
195 else if (val
[i
] == otk::Property::atoms
.kde_net_wm_window_type_override
){
196 // prevent this window from getting any decor or functionality
197 _mwmhints
.flags
&= MwmFlag_Functions
| MwmFlag_Decorations
;
198 _mwmhints
.decorations
= 0;
199 _mwmhints
.functions
= 0;
201 if (_type
!= (WindowType
) -1)
202 break; // grab the first known type
207 if (_type
== (WindowType
) -1) {
209 * the window type hint was not set, which means we either classify ourself
210 * as a normal window or a dialog, depending on if we are a transient.
220 void Client::setupDecorAndFunctions()
222 // start with everything (cept fullscreen)
223 _decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
224 Decor_AllDesktops
| Decor_Iconify
| Decor_Maximize
;
225 _functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
|
227 if (_delete_window
) {
228 _decorations
|= Decor_Close
;
229 _functions
|= Func_Close
;
232 if (!(_min_size
.x() < _max_size
.x() || _min_size
.y() < _max_size
.y())) {
233 _decorations
&= ~(Decor_Maximize
| Decor_Handle
);
234 _functions
&= ~(Func_Resize
| Func_Maximize
);
239 // normal windows retain all of the possible decorations and
240 // functionality, and are the only windows that you can fullscreen
241 _functions
|= Func_Fullscreen
;
245 // dialogs cannot be maximized
246 _decorations
&= ~Decor_Maximize
;
247 _functions
&= ~Func_Maximize
;
253 // these windows get less functionality
254 _decorations
&= ~(Decor_Iconify
| Decor_Handle
);
255 _functions
&= ~(Func_Iconify
| Func_Resize
);
261 // none of these windows are manipulated by the window manager
267 // Mwm Hints are applied subtractively to what has already been chosen for
268 // decor and functionality
269 if (_mwmhints
.flags
& MwmFlag_Decorations
) {
270 if (! (_mwmhints
.decorations
& MwmDecor_All
)) {
271 if (! (_mwmhints
.decorations
& MwmDecor_Border
))
272 _decorations
&= ~Decor_Border
;
273 if (! (_mwmhints
.decorations
& MwmDecor_Handle
))
274 _decorations
&= ~Decor_Handle
;
275 if (! (_mwmhints
.decorations
& MwmDecor_Title
)) {
276 _decorations
&= ~Decor_Titlebar
;
277 // if we don't have a titlebar, then we cannot shade!
278 _functions
&= ~Func_Shade
;
280 if (! (_mwmhints
.decorations
& MwmDecor_Iconify
))
281 _decorations
&= ~Decor_Iconify
;
282 if (! (_mwmhints
.decorations
& MwmDecor_Maximize
))
283 _decorations
&= ~Decor_Maximize
;
287 if (_mwmhints
.flags
& MwmFlag_Functions
) {
288 if (! (_mwmhints
.functions
& MwmFunc_All
)) {
289 if (! (_mwmhints
.functions
& MwmFunc_Resize
))
290 _functions
&= ~Func_Resize
;
291 if (! (_mwmhints
.functions
& MwmFunc_Move
))
292 _functions
&= ~Func_Move
;
293 if (! (_mwmhints
.functions
& MwmFunc_Iconify
))
294 _functions
&= ~Func_Iconify
;
295 if (! (_mwmhints
.functions
& MwmFunc_Maximize
))
296 _functions
&= ~Func_Maximize
;
297 // dont let mwm hints kill the close button
298 //if (! (_mwmhints.functions & MwmFunc_Close))
299 // _functions &= ~Func_Close;
303 // finally, user specified disabled decorations are applied to subtract
305 if (_disabled_decorations
& Decor_Titlebar
)
306 _decorations
&= ~Decor_Titlebar
;
307 if (_disabled_decorations
& Decor_Handle
)
308 _decorations
&= ~Decor_Handle
;
309 if (_disabled_decorations
& Decor_Border
)
310 _decorations
&= ~Decor_Border
;
311 if (_disabled_decorations
& Decor_Iconify
)
312 _decorations
&= ~Decor_Iconify
;
313 if (_disabled_decorations
& Decor_Maximize
)
314 _decorations
&= ~Decor_Maximize
;
315 if (_disabled_decorations
& Decor_AllDesktops
)
316 _decorations
&= ~Decor_AllDesktops
;
317 if (_disabled_decorations
& Decor_Close
)
318 _decorations
&= ~Decor_Close
;
320 // You can't shade without a titlebar
321 if (!(_decorations
& Decor_Titlebar
))
322 _functions
&= ~Func_Shade
;
324 changeAllowedActions();
327 frame
->adjustSize(); // change the decors on the frame
328 frame
->adjustPosition(); // with more/less decorations, we may need to be
334 void Client::getMwmHints()
336 unsigned long num
= MwmHints::elements
;
337 unsigned long *hints
;
339 _mwmhints
.flags
= 0; // default to none
341 if (!otk::Property::get(_window
, otk::Property::atoms
.motif_wm_hints
,
342 otk::Property::atoms
.motif_wm_hints
, &num
,
343 (unsigned long **)&hints
))
346 if (num
>= MwmHints::elements
) {
347 // retrieved the hints
348 _mwmhints
.flags
= hints
[0];
349 _mwmhints
.functions
= hints
[1];
350 _mwmhints
.decorations
= hints
[2];
357 void Client::getArea()
359 XWindowAttributes wattrib
;
362 ret
= XGetWindowAttributes(**otk::display
, _window
, &wattrib
);
363 assert(ret
!= BadWindow
);
365 _area
.setRect(wattrib
.x
, wattrib
.y
, wattrib
.width
, wattrib
.height
);
366 _border_width
= wattrib
.border_width
;
370 void Client::getState()
372 _modal
= _shaded
= _max_horz
= _max_vert
= _fullscreen
= _above
= _below
=
373 _iconic
= _skip_taskbar
= _skip_pager
= false;
375 unsigned long *state
;
376 unsigned long num
= (unsigned) -1;
378 if (otk::Property::get(_window
, otk::Property::atoms
.net_wm_state
,
379 otk::Property::atoms
.atom
, &num
, &state
)) {
380 for (unsigned long i
= 0; i
< num
; ++i
) {
381 if (state
[i
] == otk::Property::atoms
.net_wm_state_modal
)
383 else if (state
[i
] == otk::Property::atoms
.net_wm_state_shaded
)
385 else if (state
[i
] == otk::Property::atoms
.net_wm_state_hidden
)
387 else if (state
[i
] == otk::Property::atoms
.net_wm_state_skip_taskbar
)
388 _skip_taskbar
= true;
389 else if (state
[i
] == otk::Property::atoms
.net_wm_state_skip_pager
)
391 else if (state
[i
] == otk::Property::atoms
.net_wm_state_fullscreen
)
393 else if (state
[i
] == otk::Property::atoms
.net_wm_state_maximized_vert
)
395 else if (state
[i
] == otk::Property::atoms
.net_wm_state_maximized_horz
)
397 else if (state
[i
] == otk::Property::atoms
.net_wm_state_above
)
399 else if (state
[i
] == otk::Property::atoms
.net_wm_state_below
)
408 void Client::getShaped()
412 if (otk::display
->shape()) {
417 XShapeSelectInput(**otk::display
, _window
, ShapeNotifyMask
);
419 XShapeQueryExtents(**otk::display
, _window
, &s
, &foo
,
420 &foo
, &ufoo
, &ufoo
, &foo
, &foo
, &foo
, &ufoo
, &ufoo
);
427 void Client::calcLayer() {
430 if (_iconic
) l
= Layer_Icon
;
431 else if (_fullscreen
) l
= Layer_Fullscreen
;
432 else if (_type
== Type_Desktop
) l
= Layer_Desktop
;
433 else if (_type
== Type_Dock
) {
434 if (!_below
) l
= Layer_Top
;
435 else l
= Layer_Normal
;
437 else if (_above
) l
= Layer_Above
;
438 else if (_below
) l
= Layer_Below
;
439 else l
= Layer_Normal
;
445 if we don't have a frame, then we aren't mapped yet (and this would
448 openbox
->screen(_screen
)->raiseWindow(this);
454 void Client::updateProtocols()
459 _focus_notify
= false;
460 _delete_window
= false;
462 if (XGetWMProtocols(**otk::display
, _window
, &proto
, &num_return
)) {
463 for (int i
= 0; i
< num_return
; ++i
) {
464 if (proto
[i
] == otk::Property::atoms
.wm_delete_window
) {
465 // this means we can request the window to close
466 _delete_window
= true;
467 } else if (proto
[i
] == otk::Property::atoms
.wm_take_focus
)
468 // if this protocol is requested, then the window will be notified
469 // by the window manager whenever it receives focus
470 _focus_notify
= true;
477 void Client::updateNormalHints()
481 int oldgravity
= _gravity
;
486 _size_inc
.setPoint(1, 1);
487 _base_size
.setPoint(0, 0);
488 _min_size
.setPoint(0, 0);
489 _max_size
.setPoint(INT_MAX
, INT_MAX
);
491 // get the hints from the window
492 if (XGetWMNormalHints(**otk::display
, _window
, &size
, &ret
)) {
493 _positioned
= (size
.flags
& (PPosition
|USPosition
));
495 if (size
.flags
& PWinGravity
) {
496 _gravity
= size
.win_gravity
;
498 // if the client has a frame, i.e. has already been mapped and is
499 // changing its gravity
500 if (frame
&& _gravity
!= oldgravity
) {
501 // move our idea of the client's position based on its new gravity
502 int x
= frame
->rect().x(), y
= frame
->rect().y();
503 frame
->frameGravity(x
, y
);
508 if (size
.flags
& PAspect
) {
509 if (size
.min_aspect
.y
) _min_ratio
= size
.min_aspect
.x
/size
.min_aspect
.y
;
510 if (size
.max_aspect
.y
) _max_ratio
= size
.max_aspect
.x
/size
.max_aspect
.y
;
513 if (size
.flags
& PMinSize
)
514 _min_size
.setPoint(size
.min_width
, size
.min_height
);
516 if (size
.flags
& PMaxSize
)
517 _max_size
.setPoint(size
.max_width
, size
.max_height
);
519 if (size
.flags
& PBaseSize
)
520 _base_size
.setPoint(size
.base_width
, size
.base_height
);
522 if (size
.flags
& PResizeInc
)
523 _size_inc
.setPoint(size
.width_inc
, size
.height_inc
);
528 void Client::updateWMHints(bool initstate
)
532 // assume a window takes input if it doesnt specify
536 if ((hints
= XGetWMHints(**otk::display
, _window
)) != NULL
) {
537 if (hints
->flags
& InputHint
)
538 _can_focus
= hints
->input
;
540 // only do this when initstate is true!
541 if (initstate
&& (hints
->flags
& StateHint
))
542 _iconic
= hints
->initial_state
== IconicState
;
544 if (hints
->flags
& XUrgencyHint
)
547 if (hints
->flags
& WindowGroupHint
) {
548 if (hints
->window_group
!= _group
) {
549 // XXX: remove from the old group if there was one
550 _group
= hints
->window_group
;
551 // XXX: do stuff with the group
562 printf("DEBUG: Urgent Hint for 0x%lx: %s\n",
563 (long)_window
, _urgent
? "ON" : "OFF");
565 // fire the urgent callback if we're mapped, otherwise, wait until after
573 void Client::updateTitle()
578 if (!otk::Property::get(_window
, otk::Property::atoms
.net_wm_name
,
579 otk::Property::utf8
, &_title
)) {
581 otk::Property::get(_window
, otk::Property::atoms
.wm_name
,
582 otk::Property::ascii
, &_title
);
586 _title
= _("Unnamed Window");
589 frame
->setTitle(_title
);
593 void Client::updateIconTitle()
598 if (!otk::Property::get(_window
, otk::Property::atoms
.net_wm_icon_name
,
599 otk::Property::utf8
, &_icon_title
)) {
601 otk::Property::get(_window
, otk::Property::atoms
.wm_icon_name
,
602 otk::Property::ascii
, &_icon_title
);
606 _icon_title
= _("Unnamed Window");
610 void Client::updateClass()
613 _app_name
= _app_class
= _role
= "";
615 otk::Property::StringVect v
;
616 unsigned long num
= 2;
618 if (otk::Property::get(_window
, otk::Property::atoms
.wm_class
,
619 otk::Property::ascii
, &num
, &v
)) {
620 if (num
> 0) _app_name
= v
[0].c_str();
621 if (num
> 1) _app_class
= v
[1].c_str();
626 if (otk::Property::get(_window
, otk::Property::atoms
.wm_window_role
,
627 otk::Property::ascii
, &num
, &v
)) {
628 if (num
> 0) _role
= v
[0].c_str();
633 void Client::updateStrut()
635 unsigned long num
= 4;
637 if (!otk::Property::get(_window
, otk::Property::atoms
.net_wm_strut
,
638 otk::Property::atoms
.cardinal
, &num
, &data
))
642 _strut
.left
= data
[0];
643 _strut
.right
= data
[1];
644 _strut
.top
= data
[2];
645 _strut
.bottom
= data
[3];
647 // updating here is pointless while we're being mapped cuz we're not in
648 // the screen's client list yet
650 openbox
->screen(_screen
)->updateStrut();
657 void Client::updateTransientFor()
662 if (XGetTransientForHint(**otk::display
, _window
, &t
) &&
663 t
!= _window
) { // cant be transient to itself!
664 c
= openbox
->findClient(t
);
665 assert(c
!= this); // if this happens then we need to check for it
667 if (!c
/*XXX: && _group*/) {
668 // not transient to a client, see if it is transient for a group
669 if (//t == _group->leader() ||
671 t
== otk::display
->screenInfo(_screen
)->rootWindow()) {
672 // window is a transient for its group!
673 // XXX: for now this is treated as non-transient.
674 // this needs to be fixed!
679 // if anything has changed...
680 if (c
!= _transient_for
) {
686 _transient_for
->_transients
.remove(this); // remove from old parent
689 _transient_for
->_transients
.push_back(this); // add to new parent
697 void Client::propertyHandler(const XPropertyEvent
&e
)
699 otk::EventHandler::propertyHandler(e
);
701 // validate cuz we query stuff off the client here
702 if (!validate()) return;
704 // compress changes to a single property into a single change
706 while (XCheckTypedEvent(**otk::display
, e
.type
, &ce
)) {
707 // XXX: it would be nice to compress ALL changes to a property, not just
708 // changes in a row without other props between.
709 if (ce
.xproperty
.atom
!= e
.atom
) {
710 XPutBackEvent(**otk::display
, &ce
);
715 if (e
.atom
== XA_WM_NORMAL_HINTS
) {
717 setupDecorAndFunctions(); // normal hints can make a window non-resizable
718 } else if (e
.atom
== XA_WM_HINTS
)
720 else if (e
.atom
== XA_WM_TRANSIENT_FOR
) {
721 updateTransientFor();
723 calcLayer(); // type may have changed, so update the layer
724 setupDecorAndFunctions();
726 else if (e
.atom
== otk::Property::atoms
.net_wm_name
||
727 e
.atom
== otk::Property::atoms
.wm_name
)
729 else if (e
.atom
== otk::Property::atoms
.net_wm_icon_name
||
730 e
.atom
== otk::Property::atoms
.wm_icon_name
)
732 else if (e
.atom
== otk::Property::atoms
.wm_class
)
734 else if (e
.atom
== otk::Property::atoms
.wm_protocols
) {
736 setupDecorAndFunctions();
738 else if (e
.atom
== otk::Property::atoms
.net_wm_strut
)
743 void Client::setWMState(long state
)
745 if (state
== _wmstate
) return; // no change
749 setDesktop(ICONIC_DESKTOP
);
752 setDesktop(openbox
->screen(_screen
)->desktop());
758 void Client::setDesktop(long target
)
760 if (target
== _desktop
) return;
762 printf("Setting desktop %ld\n", target
);
764 if (!(target
>= 0 || target
== (signed)0xffffffff ||
765 target
== ICONIC_DESKTOP
))
770 // set the desktop hint, but not if we're iconifying
771 if (_desktop
!= ICONIC_DESKTOP
)
772 otk::Property::set(_window
, otk::Property::atoms
.net_wm_desktop
,
773 otk::Property::atoms
.cardinal
, (unsigned)_desktop
);
775 // 'move' the window to the new desktop
776 if (_desktop
== openbox
->screen(_screen
)->desktop() ||
777 _desktop
== (signed)0xffffffff)
782 // Handle Iconic state. Iconic state is maintained by the client being a
783 // member of the ICONIC_DESKTOP, so this is where we make iconifying and
784 // uniconifying happen.
785 bool i
= _desktop
== ICONIC_DESKTOP
;
786 if (i
!= _iconic
) { // has the state changed?
789 _wmstate
= IconicState
;
791 // we unmap the client itself so that we can get MapRequest events, and
792 // because the ICCCM tells us to!
793 XUnmapWindow(**otk::display
, _window
);
795 _wmstate
= NormalState
;
796 XMapWindow(**otk::display
, _window
);
801 frame
->adjustState();
805 Client
*Client::findModalChild(Client
*skip
) const
809 // find a modal child recursively and try focus it
810 List::const_iterator it
, end
= _transients
.end();
811 for (it
= _transients
.begin(); it
!= end
; ++it
)
812 if ((*it
)->_modal
&& *it
!= skip
)
813 return *it
; // got one
814 // none of our direct children are modal, let them try check
815 for (it
= _transients
.begin(); it
!= end
; ++it
)
816 if ((ret
= (*it
)->findModalChild()))
817 return ret
; // got one
822 void Client::setModal(bool modal
)
826 while (c
->_transient_for
) {
827 c
= c
->_transient_for
;
828 if (c
->_modal_child
) break; // already has a modal child
829 c
->_modal_child
= this;
832 // try find a replacement modal dialog
833 Client
*replacement
= 0;
836 while (c
->_transient_for
) // go up the tree
837 c
= c
->_transient_for
;
838 replacement
= c
->findModalChild(this); // find a modal child, skipping this
841 while (c
->_transient_for
) {
842 c
= c
->_transient_for
;
843 if (c
->_modal_child
!= this) break; // has a different modal child
844 c
->_modal_child
= replacement
;
851 void Client::setState(StateAction action
, long data1
, long data2
)
853 bool shadestate
= _shaded
;
854 bool fsstate
= _fullscreen
;
855 bool maxh
= _max_horz
;
856 bool maxv
= _max_vert
;
859 if (!(action
== State_Add
|| action
== State_Remove
||
860 action
== State_Toggle
))
861 return; // an invalid action was passed to the client message, ignore it
863 for (int i
= 0; i
< 2; ++i
) {
864 Atom state
= i
== 0 ? data1
: data2
;
866 if (! state
) continue;
868 // if toggling, then pick whether we're adding or removing
869 if (action
== State_Toggle
) {
870 if (state
== otk::Property::atoms
.net_wm_state_modal
)
871 action
= _modal
? State_Remove
: State_Add
;
872 else if (state
== otk::Property::atoms
.net_wm_state_maximized_vert
)
873 action
= _max_vert
? State_Remove
: State_Add
;
874 else if (state
== otk::Property::atoms
.net_wm_state_maximized_horz
)
875 action
= _max_horz
? State_Remove
: State_Add
;
876 else if (state
== otk::Property::atoms
.net_wm_state_shaded
)
877 action
= _shaded
? State_Remove
: State_Add
;
878 else if (state
== otk::Property::atoms
.net_wm_state_skip_taskbar
)
879 action
= _skip_taskbar
? State_Remove
: State_Add
;
880 else if (state
== otk::Property::atoms
.net_wm_state_skip_pager
)
881 action
= _skip_pager
? State_Remove
: State_Add
;
882 else if (state
== otk::Property::atoms
.net_wm_state_fullscreen
)
883 action
= _fullscreen
? State_Remove
: State_Add
;
884 else if (state
== otk::Property::atoms
.net_wm_state_above
)
885 action
= _above
? State_Remove
: State_Add
;
886 else if (state
== otk::Property::atoms
.net_wm_state_below
)
887 action
= _below
? State_Remove
: State_Add
;
890 if (action
== State_Add
) {
891 if (state
== otk::Property::atoms
.net_wm_state_modal
) {
892 if (_modal
) continue;
894 } else if (state
== otk::Property::atoms
.net_wm_state_maximized_vert
) {
896 } else if (state
== otk::Property::atoms
.net_wm_state_maximized_horz
) {
897 if (_max_horz
) continue;
899 } else if (state
== otk::Property::atoms
.net_wm_state_shaded
) {
901 } else if (state
== otk::Property::atoms
.net_wm_state_skip_taskbar
) {
902 _skip_taskbar
= true;
903 } else if (state
== otk::Property::atoms
.net_wm_state_skip_pager
) {
905 } else if (state
== otk::Property::atoms
.net_wm_state_fullscreen
) {
907 } else if (state
== otk::Property::atoms
.net_wm_state_above
) {
908 if (_above
) continue;
910 } else if (state
== otk::Property::atoms
.net_wm_state_below
) {
911 if (_below
) continue;
915 } else { // action == State_Remove
916 if (state
== otk::Property::atoms
.net_wm_state_modal
) {
917 if (!_modal
) continue;
919 } else if (state
== otk::Property::atoms
.net_wm_state_maximized_vert
) {
921 } else if (state
== otk::Property::atoms
.net_wm_state_maximized_horz
) {
923 } else if (state
== otk::Property::atoms
.net_wm_state_shaded
) {
925 } else if (state
== otk::Property::atoms
.net_wm_state_skip_taskbar
) {
926 _skip_taskbar
= false;
927 } else if (state
== otk::Property::atoms
.net_wm_state_skip_pager
) {
929 } else if (state
== otk::Property::atoms
.net_wm_state_fullscreen
) {
931 } else if (state
== otk::Property::atoms
.net_wm_state_above
) {
932 if (!_above
) continue;
934 } else if (state
== otk::Property::atoms
.net_wm_state_below
) {
935 if (!_below
) continue;
940 if (maxh
!= _max_horz
|| maxv
!= _max_vert
) {
941 if (maxh
!= _max_horz
&& maxv
!= _max_vert
) { // toggling both
942 if (maxh
== maxv
) { // both going the same way
943 maximize(maxh
, 0, true);
945 maximize(maxh
, 1, true);
946 maximize(maxv
, 2, true);
948 } else { // toggling one
949 if (maxh
!= _max_horz
)
950 maximize(maxh
, 1, true);
952 maximize(maxv
, 2, true);
957 // change fullscreen state before shading, as it will affect if the window
959 if (fsstate
!= _fullscreen
)
960 fullscreen(fsstate
, true);
961 if (shadestate
!= _shaded
)
964 changeState(); // change the hint to relect these changes
968 void Client::toggleClientBorder(bool addborder
)
970 // adjust our idea of where the client is, based on its border. When the
971 // border is removed, the client should now be considered to be in a
972 // different position.
973 // when re-adding the border to the client, the same operation needs to be
975 int oldx
= _area
.x(), oldy
= _area
.y();
976 int x
= oldx
, y
= oldy
;
979 case NorthWestGravity
:
981 case SouthWestGravity
:
983 case NorthEastGravity
:
985 case SouthEastGravity
:
986 if (addborder
) x
-= _border_width
* 2;
987 else x
+= _border_width
* 2;
994 if (addborder
) x
-= _border_width
;
995 else x
+= _border_width
;
1000 case NorthWestGravity
:
1002 case NorthEastGravity
:
1004 case SouthWestGravity
:
1006 case SouthEastGravity
:
1007 if (addborder
) y
-= _border_width
* 2;
1008 else y
+= _border_width
* 2;
1015 if (addborder
) y
-= _border_width
;
1016 else y
+= _border_width
;
1022 XSetWindowBorderWidth(**otk::display
, _window
, _border_width
);
1024 // move the client so it is back it the right spot _with_ its border!
1025 if (x
!= oldx
|| y
!= oldy
)
1026 XMoveWindow(**otk::display
, _window
, x
, y
);
1028 XSetWindowBorderWidth(**otk::display
, _window
, 0);
1032 void Client::clientMessageHandler(const XClientMessageEvent
&e
)
1034 otk::EventHandler::clientMessageHandler(e
);
1036 // validate cuz we query stuff off the client here
1037 if (!validate()) return;
1039 if (e
.format
!= 32) return;
1041 if (e
.message_type
== otk::Property::atoms
.wm_change_state
) {
1042 // compress changes into a single change
1043 bool compress
= false;
1045 while (XCheckTypedEvent(**otk::display
, e
.type
, &ce
)) {
1046 // XXX: it would be nice to compress ALL messages of a type, not just
1047 // messages in a row without other message types between.
1048 if (ce
.xclient
.message_type
!= e
.message_type
) {
1049 XPutBackEvent(**otk::display
, &ce
);
1055 setWMState(ce
.xclient
.data
.l
[0]); // use the found event
1057 setWMState(e
.data
.l
[0]); // use the original event
1058 } else if (e
.message_type
== otk::Property::atoms
.net_wm_desktop
) {
1059 // compress changes into a single change
1060 bool compress
= false;
1062 while (XCheckTypedEvent(**otk::display
, e
.type
, &ce
)) {
1063 // XXX: it would be nice to compress ALL messages of a type, not just
1064 // messages in a row without other message types between.
1065 if (ce
.xclient
.message_type
!= e
.message_type
) {
1066 XPutBackEvent(**otk::display
, &ce
);
1072 setDesktop(e
.data
.l
[0]); // use the found event
1074 setDesktop(e
.data
.l
[0]); // use the original event
1075 } else if (e
.message_type
== otk::Property::atoms
.net_wm_state
) {
1076 // can't compress these
1078 printf("net_wm_state %s %ld %ld for 0x%lx\n",
1079 (e
.data
.l
[0] == 0 ? "Remove" : e
.data
.l
[0] == 1 ? "Add" :
1080 e
.data
.l
[0] == 2 ? "Toggle" : "INVALID"),
1081 e
.data
.l
[1], e
.data
.l
[2], _window
);
1083 setState((StateAction
)e
.data
.l
[0], e
.data
.l
[1], e
.data
.l
[2]);
1084 } else if (e
.message_type
== otk::Property::atoms
.net_close_window
) {
1086 printf("net_close_window for 0x%lx\n", _window
);
1089 } else if (e
.message_type
== otk::Property::atoms
.net_active_window
) {
1091 printf("net_active_window for 0x%lx\n", _window
);
1094 setDesktop(openbox
->screen(_screen
)->desktop());
1099 openbox
->screen(_screen
)->raiseWindow(this);
1105 void Client::shapeHandler(const XShapeEvent
&e
)
1107 otk::EventHandler::shapeHandler(e
);
1109 if (e
.kind
== ShapeBounding
) {
1111 frame
->adjustShape();
1117 void Client::resize(Corner anchor
, int w
, int h
)
1119 if (!(_functions
& Func_Resize
)) return;
1120 internal_resize(anchor
, w
, h
);
1124 void Client::internal_resize(Corner anchor
, int w
, int h
, bool user
,
1127 w
-= _base_size
.x();
1128 h
-= _base_size
.y();
1131 // for interactive resizing. have to move half an increment in each
1133 int mw
= w
% _size_inc
.x(); // how far we are towards the next size inc
1134 int mh
= h
% _size_inc
.y();
1135 int aw
= _size_inc
.x() / 2; // amount to add
1136 int ah
= _size_inc
.y() / 2;
1137 // don't let us move into a new size increment
1138 if (mw
+ aw
>= _size_inc
.x()) aw
= _size_inc
.x() - mw
- 1;
1139 if (mh
+ ah
>= _size_inc
.y()) ah
= _size_inc
.y() - mh
- 1;
1143 // if this is a user-requested resize, then check against min/max sizes
1144 // and aspect ratios
1146 // smaller than min size or bigger than max size?
1147 if (w
< _min_size
.x()) w
= _min_size
.x();
1148 else if (w
> _max_size
.x()) w
= _max_size
.x();
1149 if (h
< _min_size
.y()) h
= _min_size
.y();
1150 else if (h
> _max_size
.y()) h
= _max_size
.y();
1152 // adjust the height ot match the width for the aspect ratios
1154 if (h
* _min_ratio
> w
) h
= static_cast<int>(w
/ _min_ratio
);
1156 if (h
* _max_ratio
< w
) h
= static_cast<int>(w
/ _max_ratio
);
1159 // keep to the increments
1163 // you cannot resize to nothing
1167 // store the logical size
1168 _logical_size
.setPoint(w
, h
);
1173 w
+= _base_size
.x();
1174 h
+= _base_size
.y();
1176 if (x
== INT_MIN
|| y
== INT_MIN
) {
1183 x
-= w
- _area
.width();
1186 y
-= h
- _area
.height();
1189 x
-= w
- _area
.width();
1190 y
-= h
- _area
.height();
1195 _area
.setSize(w
, h
);
1197 XResizeWindow(**otk::display
, _window
, w
, h
);
1199 // resize the frame to match the request
1200 frame
->adjustSize();
1201 internal_move(x
, y
);
1205 void Client::move(int x
, int y
)
1207 if (!(_functions
& Func_Move
)) return;
1208 frame
->frameGravity(x
, y
); // get the client's position based on x,y for the
1210 internal_move(x
, y
);
1214 void Client::internal_move(int x
, int y
)
1218 // move the frame to be in the requested position
1219 if (frame
) { // this can be called while mapping, before frame exists
1220 frame
->adjustPosition();
1222 // send synthetic configure notify (we don't need to if we aren't mapped
1225 event
.type
= ConfigureNotify
;
1226 event
.xconfigure
.display
= **otk::display
;
1227 event
.xconfigure
.event
= _window
;
1228 event
.xconfigure
.window
= _window
;
1230 // root window coords with border in mind
1231 event
.xconfigure
.x
= x
- _border_width
+ frame
->size().left
;
1232 event
.xconfigure
.y
= y
- _border_width
+ frame
->size().top
;
1234 event
.xconfigure
.width
= _area
.width();
1235 event
.xconfigure
.height
= _area
.height();
1236 event
.xconfigure
.border_width
= _border_width
;
1237 event
.xconfigure
.above
= frame
->plate();
1238 event
.xconfigure
.override_redirect
= False
;
1239 XSendEvent(event
.xconfigure
.display
, event
.xconfigure
.window
, False
,
1240 StructureNotifyMask
, &event
);
1242 printf("Sent synthetic ConfigureNotify %d,%d %d,%d to 0x%lx\n",
1243 event
.xconfigure
.x
, event
.xconfigure
.y
, event
.xconfigure
.width
,
1244 event
.xconfigure
.height
, event
.xconfigure
.window
);
1250 void Client::close()
1254 if (!(_functions
& Func_Close
)) return;
1256 // XXX: itd be cool to do timeouts and shit here for killing the client's
1258 // like... if the window is around after 5 seconds, then the close button
1259 // turns a nice red, and if this function is called again, the client is
1260 // explicitly killed.
1262 ce
.xclient
.type
= ClientMessage
;
1263 ce
.xclient
.message_type
= otk::Property::atoms
.wm_protocols
;
1264 ce
.xclient
.display
= **otk::display
;
1265 ce
.xclient
.window
= _window
;
1266 ce
.xclient
.format
= 32;
1267 ce
.xclient
.data
.l
[0] = otk::Property::atoms
.wm_delete_window
;
1268 ce
.xclient
.data
.l
[1] = CurrentTime
;
1269 ce
.xclient
.data
.l
[2] = 0l;
1270 ce
.xclient
.data
.l
[3] = 0l;
1271 ce
.xclient
.data
.l
[4] = 0l;
1272 XSendEvent(**otk::display
, _window
, false, NoEventMask
, &ce
);
1276 void Client::changeState()
1278 unsigned long state
[2];
1279 state
[0] = _wmstate
;
1281 otk::Property::set(_window
, otk::Property::atoms
.wm_state
,
1282 otk::Property::atoms
.wm_state
, state
, 2);
1287 netstate
[num
++] = otk::Property::atoms
.net_wm_state_modal
;
1289 netstate
[num
++] = otk::Property::atoms
.net_wm_state_shaded
;
1291 netstate
[num
++] = otk::Property::atoms
.net_wm_state_hidden
;
1293 netstate
[num
++] = otk::Property::atoms
.net_wm_state_skip_taskbar
;
1295 netstate
[num
++] = otk::Property::atoms
.net_wm_state_skip_pager
;
1297 netstate
[num
++] = otk::Property::atoms
.net_wm_state_fullscreen
;
1299 netstate
[num
++] = otk::Property::atoms
.net_wm_state_maximized_vert
;
1301 netstate
[num
++] = otk::Property::atoms
.net_wm_state_maximized_horz
;
1303 netstate
[num
++] = otk::Property::atoms
.net_wm_state_above
;
1305 netstate
[num
++] = otk::Property::atoms
.net_wm_state_below
;
1306 otk::Property::set(_window
, otk::Property::atoms
.net_wm_state
,
1307 otk::Property::atoms
.atom
, netstate
, num
);
1312 frame
->adjustState();
1316 void Client::changeAllowedActions(void)
1321 actions
[num
++] = otk::Property::atoms
.net_wm_action_change_desktop
;
1323 if (_functions
& Func_Shade
)
1324 actions
[num
++] = otk::Property::atoms
.net_wm_action_shade
;
1325 if (_functions
& Func_Close
)
1326 actions
[num
++] = otk::Property::atoms
.net_wm_action_close
;
1327 if (_functions
& Func_Move
)
1328 actions
[num
++] = otk::Property::atoms
.net_wm_action_move
;
1329 if (_functions
& Func_Iconify
)
1330 actions
[num
++] = otk::Property::atoms
.net_wm_action_minimize
;
1331 if (_functions
& Func_Resize
)
1332 actions
[num
++] = otk::Property::atoms
.net_wm_action_resize
;
1333 if (_functions
& Func_Fullscreen
)
1334 actions
[num
++] = otk::Property::atoms
.net_wm_action_fullscreen
;
1335 if (_functions
& Func_Maximize
) {
1336 actions
[num
++] = otk::Property::atoms
.net_wm_action_maximize_horz
;
1337 actions
[num
++] = otk::Property::atoms
.net_wm_action_maximize_vert
;
1340 otk::Property::set(_window
, otk::Property::atoms
.net_wm_allowed_actions
,
1341 otk::Property::atoms
.atom
, actions
, num
);
1345 void Client::remaximize()
1348 if (_max_horz
&& _max_vert
)
1355 return; // not maximized
1356 _max_horz
= _max_vert
= false;
1357 maximize(true, dir
, false);
1361 void Client::applyStartupState()
1363 // these are in a carefully crafted order..
1372 setDesktop(ICONIC_DESKTOP
);
1375 _fullscreen
= false;
1376 fullscreen(true, false);
1385 if (_max_vert
&& _max_horz
) {
1386 _max_vert
= _max_horz
= false;
1387 maximize(true, 0, false);
1388 } else if (_max_vert
) {
1390 maximize(true, 2, false);
1391 } else if (_max_horz
) {
1393 maximize(true, 1, false);
1396 if (_skip_taskbar
); // nothing to do for this
1397 if (_skip_pager
); // nothing to do for this
1398 if (_modal
); // nothing to do for this
1399 if (_above
); // nothing to do for this
1400 if (_below
); // nothing to do for this
1404 void Client::fireUrgent()
1406 // call the python UrgentWindow callbacks
1407 EventData
data(_screen
, this, EventAction::UrgentWindow
, 0);
1408 openbox
->bindings()->fireEvent(&data
);
1412 void Client::shade(bool shade
)
1414 if (!(_functions
& Func_Shade
) || // can't
1415 _shaded
== shade
) return; // already done
1417 // when we're iconic, don't change the wmstate
1419 _wmstate
= shade
? IconicState
: NormalState
;
1422 frame
->adjustSize();
1426 void Client::maximize(bool max
, int dir
, bool savearea
)
1428 assert(dir
== 0 || dir
== 1 || dir
== 2);
1429 if (!(_functions
& Func_Maximize
)) return; // can't
1431 // check if already done
1433 if (dir
== 0 && _max_horz
&& _max_vert
) return;
1434 if (dir
== 1 && _max_horz
) return;
1435 if (dir
== 2 && _max_vert
) return;
1437 if (dir
== 0 && !_max_horz
&& !_max_vert
) return;
1438 if (dir
== 1 && !_max_horz
) return;
1439 if (dir
== 2 && !_max_vert
) return;
1442 const otk::Rect
&a
= openbox
->screen(_screen
)->area();
1443 int x
= frame
->rect().x(), y
= frame
->rect().y(),
1444 w
= _area
.width(), h
= _area
.height();
1450 unsigned long n
= 4;
1457 // get the property off the window and use it for the dimentions we are
1459 if (otk::Property::get(_window
, otk::Property::atoms
.openbox_premax
,
1460 otk::Property::atoms
.cardinal
, &n
,
1461 (long unsigned**) &readdim
)) {
1464 dimensions
[0] = readdim
[0];
1465 dimensions
[2] = readdim
[2];
1468 dimensions
[1] = readdim
[1];
1469 dimensions
[3] = readdim
[3];
1475 otk::Property::set(_window
, otk::Property::atoms
.openbox_premax
,
1476 otk::Property::atoms
.cardinal
,
1477 (long unsigned*)dimensions
, 4);
1479 if (dir
== 0 || dir
== 1) { // horz
1483 if (dir
== 0 || dir
== 2) { // vert
1485 h
= a
.height() - frame
->size().top
- frame
->size().bottom
;
1489 long unsigned n
= 4;
1491 if (otk::Property::get(_window
, otk::Property::atoms
.openbox_premax
,
1492 otk::Property::atoms
.cardinal
, &n
,
1493 (long unsigned**) &dimensions
)) {
1495 if (dir
== 0 || dir
== 1) { // horz
1496 x
= (signed int)dimensions
[0];
1497 w
= (signed int)dimensions
[2];
1499 if (dir
== 0 || dir
== 2) { // vert
1500 y
= (signed int)dimensions
[1];
1501 h
= (signed int)dimensions
[3];
1506 // pick some fallbacks...
1507 if (dir
== 0 || dir
== 1) { // horz
1508 x
= a
.x() + a
.width() / 4;
1511 if (dir
== 0 || dir
== 2) { // vert
1512 y
= a
.y() + a
.height() / 4;
1518 if (dir
== 0 || dir
== 1) // horz
1520 if (dir
== 0 || dir
== 2) // vert
1523 if (!_max_horz
&& !_max_vert
)
1524 otk::Property::erase(_window
, otk::Property::atoms
.openbox_premax
);
1526 changeState(); // change the state hints on the client
1528 frame
->frameGravity(x
, y
); // figure out where the client should be going
1529 internal_resize(TopLeft
, w
, h
, true, x
, y
);
1533 void Client::fullscreen(bool fs
, bool savearea
)
1535 static FunctionFlags saved_func
;
1536 static DecorationFlags saved_decor
;
1538 if (!(_functions
& Func_Fullscreen
) || // can't
1539 _fullscreen
== fs
) return; // already done
1542 changeState(); // change the state hints on the client
1544 int x
= _area
.x(), y
= _area
.y(), w
= _area
.width(), h
= _area
.height();
1547 // save the functions and remove them
1548 saved_func
= _functions
;
1549 _functions
= _functions
& (Func_Close
| Func_Fullscreen
| Func_Iconify
);
1550 // save the decorations and remove them
1551 saved_decor
= _decorations
;
1555 dimensions
[0] = _area
.x();
1556 dimensions
[1] = _area
.y();
1557 dimensions
[2] = _area
.width();
1558 dimensions
[3] = _area
.height();
1559 otk::Property::set(_window
, otk::Property::atoms
.openbox_premax
,
1560 otk::Property::atoms
.cardinal
,
1561 (long unsigned*)dimensions
, 4);
1563 const otk::ScreenInfo
*info
= otk::display
->screenInfo(_screen
);
1569 _functions
= saved_func
;
1570 _decorations
= saved_decor
;
1573 long unsigned n
= 4;
1575 if (otk::Property::get(_window
, otk::Property::atoms
.openbox_premax
,
1576 otk::Property::atoms
.cardinal
, &n
,
1577 (long unsigned**) &dimensions
)) {
1586 // pick some fallbacks...
1587 const otk::Rect
&a
= openbox
->screen(_screen
)->area();
1588 x
= a
.x() + a
.width() / 4;
1589 y
= a
.y() + a
.height() / 4;
1595 changeAllowedActions(); // based on the new _functions
1597 // when fullscreening, don't obey things like increments, fill the screen
1598 internal_resize(TopLeft
, w
, h
, !fs
, x
, y
);
1600 // raise (back) into our stacking layer
1601 openbox
->screen(_screen
)->raiseWindow(this);
1603 // try focus us when we go into fullscreen mode
1608 void Client::disableDecorations(DecorationFlags flags
)
1610 _disabled_decorations
= flags
;
1611 setupDecorAndFunctions();
1615 bool Client::focus()
1617 // if we have a modal child, then focus it, not us
1619 return _modal_child
->focus();
1621 // won't try focus if the client doesn't want it, or if the window isn't
1622 // visible on the screen
1623 if (!(frame
->isVisible() && (_can_focus
|| _focus_notify
))) return false;
1625 if (_focused
) return true;
1627 // do a check to see if the window has already been unmapped or destroyed
1628 // do this intelligently while watching out for unmaps we've generated
1629 // (ignore_unmaps > 0)
1631 if (XCheckTypedWindowEvent(**otk::display
, _window
, DestroyNotify
, &ev
)) {
1632 XPutBackEvent(**otk::display
, &ev
);
1635 while (XCheckTypedWindowEvent(**otk::display
, _window
, UnmapNotify
, &ev
)) {
1636 if (ignore_unmaps
) {
1637 unmapHandler(ev
.xunmap
);
1639 XPutBackEvent(**otk::display
, &ev
);
1645 XSetInputFocus(**otk::display
, _window
,
1646 RevertToNone
, CurrentTime
);
1648 if (_focus_notify
) {
1650 ce
.xclient
.type
= ClientMessage
;
1651 ce
.xclient
.message_type
= otk::Property::atoms
.wm_protocols
;
1652 ce
.xclient
.display
= **otk::display
;
1653 ce
.xclient
.window
= _window
;
1654 ce
.xclient
.format
= 32;
1655 ce
.xclient
.data
.l
[0] = otk::Property::atoms
.wm_take_focus
;
1656 ce
.xclient
.data
.l
[1] = openbox
->lastTime();
1657 ce
.xclient
.data
.l
[2] = 0l;
1658 ce
.xclient
.data
.l
[3] = 0l;
1659 ce
.xclient
.data
.l
[4] = 0l;
1660 XSendEvent(**otk::display
, _window
, False
, NoEventMask
, &ce
);
1663 XSync(**otk::display
, False
);
1668 void Client::unfocus() const
1670 if (!_focused
) return;
1672 assert(openbox
->focusedClient() == this);
1673 openbox
->setFocusedClient(0);
1677 void Client::focusHandler(const XFocusChangeEvent
&e
)
1680 // printf("FocusIn for 0x%lx\n", e.window);
1683 otk::EventHandler::focusHandler(e
);
1688 openbox
->setFocusedClient(this);
1692 void Client::unfocusHandler(const XFocusChangeEvent
&e
)
1695 // printf("FocusOut for 0x%lx\n", e.window);
1698 otk::EventHandler::unfocusHandler(e
);
1703 if (openbox
->focusedClient() == this)
1704 openbox
->setFocusedClient(0);
1708 void Client::configureRequestHandler(const XConfigureRequestEvent
&e
)
1711 printf("ConfigureRequest for 0x%lx\n", e
.window
);
1714 otk::EventHandler::configureRequestHandler(e
);
1716 // if we are iconic (or shaded (fvwm does this)) ignore the event
1717 if (_iconic
|| _shaded
) return;
1719 if (e
.value_mask
& CWBorderWidth
)
1720 _border_width
= e
.border_width
;
1722 // resize, then move, as specified in the EWMH section 7.7
1723 if (e
.value_mask
& (CWWidth
| CWHeight
)) {
1724 int w
= (e
.value_mask
& CWWidth
) ? e
.width
: _area
.width();
1725 int h
= (e
.value_mask
& CWHeight
) ? e
.height
: _area
.height();
1729 case NorthEastGravity
:
1733 case SouthWestGravity
:
1735 corner
= BottomLeft
;
1737 case SouthEastGravity
:
1738 corner
= BottomRight
;
1740 default: // NorthWest, Static, etc
1744 // if moving AND resizing ...
1745 if (e
.value_mask
& (CWX
| CWY
)) {
1746 int x
= (e
.value_mask
& CWX
) ? e
.x
: _area
.x();
1747 int y
= (e
.value_mask
& CWY
) ? e
.y
: _area
.y();
1748 internal_resize(corner
, w
, h
, false, x
, y
);
1749 } else // if JUST resizing...
1750 internal_resize(corner
, w
, h
, false);
1751 } else if (e
.value_mask
& (CWX
| CWY
)) { // if JUST moving...
1752 int x
= (e
.value_mask
& CWX
) ? e
.x
: _area
.x();
1753 int y
= (e
.value_mask
& CWY
) ? e
.y
: _area
.y();
1754 internal_move(x
, y
);
1757 if (e
.value_mask
& CWStackMode
) {
1761 openbox
->screen(_screen
)->lowerWindow(this);
1767 openbox
->screen(_screen
)->raiseWindow(this);
1774 void Client::unmapHandler(const XUnmapEvent
&e
)
1776 if (ignore_unmaps
) {
1778 // printf("Ignored UnmapNotify for 0x%lx (event 0x%lx)\n", e.window, e.event);
1785 printf("UnmapNotify for 0x%lx\n", e
.window
);
1788 otk::EventHandler::unmapHandler(e
);
1790 // this deletes us etc
1791 openbox
->screen(_screen
)->unmanageWindow(this);
1795 void Client::destroyHandler(const XDestroyWindowEvent
&e
)
1798 printf("DestroyNotify for 0x%lx\n", e
.window
);
1801 otk::EventHandler::destroyHandler(e
);
1803 // this deletes us etc
1804 openbox
->screen(_screen
)->unmanageWindow(this);
1808 void Client::reparentHandler(const XReparentEvent
&e
)
1810 // this is when the client is first taken captive in the frame
1811 if (e
.parent
== frame
->plate()) return;
1814 printf("ReparentNotify for 0x%lx\n", e
.window
);
1817 otk::EventHandler::reparentHandler(e
);
1820 This event is quite rare and is usually handled in unmapHandler.
1821 However, if the window is unmapped when the reparent event occurs,
1822 the window manager never sees it because an unmap event is not sent
1823 to an already unmapped window.
1826 // we don't want the reparent event, put it back on the stack for the X
1827 // server to deal with after we unmanage the window
1830 XPutBackEvent(**otk::display
, &ev
);
1832 // this deletes us etc
1833 openbox
->screen(_screen
)->unmanageWindow(this);
1836 void Client::mapRequestHandler(const XMapRequestEvent
&e
)
1839 printf("MapRequest for already managed 0x%lx\n", e
.window
);
1842 assert(_iconic
); // we shouldn't be able to get this unless we're iconic
1844 // move to the current desktop (uniconify)
1845 setDesktop(openbox
->screen(_screen
)->desktop());
1846 // XXX: should we focus/raise the window? (basically a net_wm_active_window)