1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
4 # include "../config.h"
11 #include "otk/display.hh"
12 #include "otk/property.hh"
16 #include <X11/Xutil.h>
21 #define _(str) gettext(str)
26 OBClient::OBClient(int screen
, Window window
)
27 : otk::OtkEventHandler(),
28 OBWidget(OBWidget::Type_Client
),
29 frame(0), _screen(screen
), _window(window
)
36 // update EVERYTHING the first time!!
38 // the state is kinda assumed to be normal. is this right? XXX
39 _wmstate
= NormalState
; _iconic
= false;
40 // no default decors or functions, each has to be enabled
41 _decorations
= _functions
= 0;
49 // set the decorations and functions
52 // normal windows retain all of the possible decorations and
54 _decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
55 Decor_Iconify
| Decor_Maximize
;
56 _functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
59 // dialogs cannot be maximized
60 _decorations
&= ~Decor_Maximize
;
61 _functions
&= ~Func_Maximize
;
67 // these windows get less functionality
68 _decorations
&= ~(Decor_Iconify
| Decor_Handle
);
69 _functions
&= ~(Func_Iconify
| Func_Resize
);
75 // none of these windows are manipulated by the window manager
81 getMwmHints(); // this fucks (in good ways) with the decors and functions
88 // XXX: updateTransientFor();
99 const otk::OBProperty
*property
= Openbox::instance
->property();
101 if (Openbox::instance
->state() != Openbox::State_Exiting
) {
102 // these values should not be persisted across a window unmapping/mapping
103 property
->erase(_window
, otk::OBProperty::net_wm_desktop
);
104 property
->erase(_window
, otk::OBProperty::net_wm_state
);
109 void OBClient::getDesktop()
111 const otk::OBProperty
*property
= Openbox::instance
->property();
113 // defaults to the current desktop
114 _desktop
= 0; // XXX: change this to the current desktop!
116 property
->get(_window
, otk::OBProperty::net_wm_desktop
,
117 otk::OBProperty::Atom_Cardinal
,
122 void OBClient::getType()
124 const otk::OBProperty
*property
= Openbox::instance
->property();
126 _type
= (WindowType
) -1;
129 unsigned long num
= (unsigned) -1;
130 if (property
->get(_window
, otk::OBProperty::net_wm_window_type
,
131 otk::OBProperty::Atom_Atom
,
133 // use the first value that we know about in the array
134 for (unsigned long i
= 0; i
< num
; ++i
) {
136 property
->atom(otk::OBProperty::net_wm_window_type_desktop
))
137 _type
= Type_Desktop
;
139 property
->atom(otk::OBProperty::net_wm_window_type_dock
))
142 property
->atom(otk::OBProperty::net_wm_window_type_toolbar
))
143 _type
= Type_Toolbar
;
145 property
->atom(otk::OBProperty::net_wm_window_type_menu
))
148 property
->atom(otk::OBProperty::net_wm_window_type_utility
))
149 _type
= Type_Utility
;
151 property
->atom(otk::OBProperty::net_wm_window_type_splash
))
154 property
->atom(otk::OBProperty::net_wm_window_type_dialog
))
157 property
->atom(otk::OBProperty::net_wm_window_type_normal
))
159 // else if (val[i] ==
160 // property->atom(otk::OBProperty::kde_net_wm_window_type_override))
161 // mwm_decorations = 0; // prevent this window from getting any decor
162 // XXX: make this work again
167 if (_type
== (WindowType
) -1) {
169 * the window type hint was not set, which means we either classify ourself
170 * as a normal window or a dialog, depending on if we are a transient.
172 // XXX: make this code work!
174 // _type = Type_Dialog;
181 void OBClient::getMwmHints()
183 const otk::OBProperty
*property
= Openbox::instance
->property();
188 num
= MwmHints::elements
;
189 if (!property
->get(_window
, otk::OBProperty::motif_wm_hints
,
190 otk::OBProperty::motif_wm_hints
, &num
,
191 (unsigned long **)&hints
))
194 if (num
< MwmHints::elements
) {
199 // retrieved the hints
200 // Mwm Hints are applied subtractively to what has already been chosen for
201 // decor and functionality
203 if (hints
->flags
& MwmFlag_Decorations
) {
204 if (! (hints
->decorations
& MwmDecor_All
)) {
205 if (! (hints
->decorations
& MwmDecor_Border
))
206 _decorations
&= ~Decor_Border
;
207 if (! (hints
->decorations
& MwmDecor_Handle
))
208 _decorations
&= ~Decor_Handle
;
209 if (! (hints
->decorations
& MwmDecor_Title
))
210 _decorations
&= ~Decor_Titlebar
;
211 if (! (hints
->decorations
& MwmDecor_Iconify
))
212 _decorations
&= ~Decor_Iconify
;
213 if (! (hints
->decorations
& MwmDecor_Maximize
))
214 _decorations
&= ~Decor_Maximize
;
218 if (hints
->flags
& MwmFlag_Functions
) {
219 if (! (hints
->functions
& MwmFunc_All
)) {
220 if (! (hints
->functions
& MwmFunc_Resize
))
221 _functions
&= ~Func_Resize
;
222 if (! (hints
->functions
& MwmFunc_Move
))
223 _functions
&= ~Func_Move
;
224 if (! (hints
->functions
& MwmFunc_Iconify
))
225 _functions
&= ~Func_Iconify
;
226 if (! (hints
->functions
& MwmFunc_Maximize
))
227 _functions
&= ~Func_Maximize
;
228 //if (! (hints->functions & MwmFunc_Close))
229 // _functions &= ~Func_Close;
236 void OBClient::getArea()
238 XWindowAttributes wattrib
;
241 ret
= XGetWindowAttributes(otk::OBDisplay::display
, _window
, &wattrib
);
242 assert(ret
!= BadWindow
);
244 _area
.setRect(wattrib
.x
, wattrib
.y
, wattrib
.width
, wattrib
.height
);
245 _border_width
= wattrib
.border_width
;
249 void OBClient::getState()
251 const otk::OBProperty
*property
= Openbox::instance
->property();
253 _modal
= _shaded
= _max_horz
= _max_vert
= _fullscreen
= _above
= _below
=
254 _skip_taskbar
= _skip_pager
= false;
256 unsigned long *state
;
257 unsigned long num
= (unsigned) -1;
259 if (property
->get(_window
, otk::OBProperty::net_wm_state
,
260 otk::OBProperty::Atom_Atom
, &num
, &state
)) {
261 for (unsigned long i
= 0; i
< num
; ++i
) {
262 if (state
[i
] == property
->atom(otk::OBProperty::net_wm_state_modal
))
265 property
->atom(otk::OBProperty::net_wm_state_shaded
))
268 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
))
269 _skip_taskbar
= true;
271 property
->atom(otk::OBProperty::net_wm_state_skip_pager
))
274 property
->atom(otk::OBProperty::net_wm_state_fullscreen
))
277 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
))
280 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
))
283 property
->atom(otk::OBProperty::net_wm_state_above
))
286 property
->atom(otk::OBProperty::net_wm_state_below
))
295 void OBClient::getShaped()
299 if (otk::OBDisplay::shape()) {
304 XShapeSelectInput(otk::OBDisplay::display
, _window
, ShapeNotifyMask
);
306 XShapeQueryExtents(otk::OBDisplay::display
, _window
, &s
, &foo
,
307 &foo
, &ufoo
, &ufoo
, &foo
, &foo
, &foo
, &ufoo
, &ufoo
);
314 void OBClient::calcLayer() {
315 if (_iconic
) _layer
= OBScreen::Layer_Icon
;
316 else if (_type
== Type_Desktop
) _layer
= OBScreen::Layer_Desktop
;
317 else if (_type
== Type_Dock
) _layer
= OBScreen::Layer_Top
;
318 else if (_fullscreen
) _layer
= OBScreen::Layer_Fullscreen
;
319 else if (_above
) _layer
= OBScreen::Layer_Above
;
320 else if (_below
) _layer
= OBScreen::Layer_Below
;
321 else _layer
= OBScreen::Layer_Normal
;
325 void OBClient::updateProtocols()
327 const otk::OBProperty
*property
= Openbox::instance
->property();
332 _focus_notify
= false;
333 _decorations
&= ~Decor_Close
;
334 _functions
&= ~Func_Close
;
336 if (XGetWMProtocols(otk::OBDisplay::display
, _window
, &proto
, &num_return
)) {
337 for (int i
= 0; i
< num_return
; ++i
) {
338 if (proto
[i
] == property
->atom(otk::OBProperty::wm_delete_window
)) {
339 _decorations
|= Decor_Close
;
340 _functions
|= Func_Close
;
341 // XXX: update the decor?
342 } else if (proto
[i
] == property
->atom(otk::OBProperty::wm_take_focus
))
343 // if this protocol is requested, then the window will be notified
344 // by the window manager whenever it receives focus
345 _focus_notify
= true;
352 void OBClient::updateNormalHints()
356 int oldgravity
= _gravity
;
359 _gravity
= NorthWestGravity
;
360 _size_inc
.setPoint(1, 1);
361 _base_size
.setPoint(0, 0);
362 _min_size
.setPoint(0, 0);
363 _max_size
.setPoint(INT_MAX
, INT_MAX
);
365 // XXX: might want to cancel any interactive resizing of the window at this
368 // get the hints from the window
369 if (XGetWMNormalHints(otk::OBDisplay::display
, _window
, &size
, &ret
)) {
370 _positioned
= (size
.flags
& (PPosition
|USPosition
));
372 if (size
.flags
& PWinGravity
)
373 _gravity
= size
.win_gravity
;
375 if (size
.flags
& PMinSize
)
376 _min_size
.setPoint(size
.min_width
, size
.min_height
);
378 if (size
.flags
& PMaxSize
)
379 _max_size
.setPoint(size
.max_width
, size
.max_height
);
381 if (size
.flags
& PBaseSize
)
382 _base_size
.setPoint(size
.base_width
, size
.base_height
);
384 if (size
.flags
& PResizeInc
)
385 _size_inc
.setPoint(size
.width_inc
, size
.height_inc
);
388 // if the client has a frame, i.e. has already been mapped and is
389 // changing its gravity
390 if (frame
&& _gravity
!= oldgravity
) {
391 // move our idea of the client's position based on its new gravity
393 frame
->frameGravity(x
, y
);
399 void OBClient::updateWMHints()
403 // assume a window takes input if it doesnt specify
407 if ((hints
= XGetWMHints(otk::OBDisplay::display
, _window
)) != NULL
) {
408 if (hints
->flags
& InputHint
)
409 _can_focus
= hints
->input
;
411 if (hints
->flags
& XUrgencyHint
)
414 if (hints
->flags
& WindowGroupHint
) {
415 if (hints
->window_group
!= _group
) {
416 // XXX: remove from the old group if there was one
417 _group
= hints
->window_group
;
418 // XXX: do stuff with the group
428 void OBClient::updateTitle()
430 const otk::OBProperty
*property
= Openbox::instance
->property();
435 if (! property
->get(_window
, otk::OBProperty::net_wm_name
,
436 otk::OBProperty::utf8
, &_title
)) {
438 property
->get(_window
, otk::OBProperty::wm_name
,
439 otk::OBProperty::ascii
, &_title
);
443 _title
= _("Unnamed Window");
446 frame
->setTitle(_title
);
450 void OBClient::updateIconTitle()
452 const otk::OBProperty
*property
= Openbox::instance
->property();
457 if (! property
->get(_window
, otk::OBProperty::net_wm_icon_name
,
458 otk::OBProperty::utf8
, &_icon_title
)) {
460 property
->get(_window
, otk::OBProperty::wm_icon_name
,
461 otk::OBProperty::ascii
, &_icon_title
);
465 _icon_title
= _("Unnamed Window");
469 void OBClient::updateClass()
471 const otk::OBProperty
*property
= Openbox::instance
->property();
474 _app_name
= _app_class
= "";
476 otk::OBProperty::StringVect v
;
477 unsigned long num
= 2;
479 if (! property
->get(_window
, otk::OBProperty::wm_class
,
480 otk::OBProperty::ascii
, &num
, &v
))
483 if (num
> 0) _app_name
= v
[0];
484 if (num
> 1) _app_class
= v
[1];
488 void OBClient::propertyHandler(const XPropertyEvent
&e
)
490 otk::OtkEventHandler::propertyHandler(e
);
492 const otk::OBProperty
*property
= Openbox::instance
->property();
494 // compress changes to a single property into a single change
496 while (XCheckTypedEvent(otk::OBDisplay::display
, e
.type
, &ce
)) {
497 // XXX: it would be nice to compress ALL changes to a property, not just
498 // changes in a row without other props between.
499 if (ce
.xproperty
.atom
!= e
.atom
) {
500 XPutBackEvent(otk::OBDisplay::display
, &ce
);
505 if (e
.atom
== XA_WM_NORMAL_HINTS
)
507 else if (e
.atom
== XA_WM_HINTS
)
509 else if (e
.atom
== property
->atom(otk::OBProperty::net_wm_name
) ||
510 e
.atom
== property
->atom(otk::OBProperty::wm_name
))
512 else if (e
.atom
== property
->atom(otk::OBProperty::net_wm_icon_name
) ||
513 e
.atom
== property
->atom(otk::OBProperty::wm_icon_name
))
515 else if (e
.atom
== property
->atom(otk::OBProperty::wm_class
))
517 else if (e
.atom
== property
->atom(otk::OBProperty::wm_protocols
))
519 // XXX: transient for hint
524 void OBClient::setWMState(long state
)
526 if (state
== _wmstate
) return; // no change
530 // XXX: cause it to iconify
533 // XXX: cause it to uniconify
540 void OBClient::setDesktop(long target
)
543 //assert(target == 0xffffffff || target < MAX);
545 // XXX: move the window to the new desktop
550 void OBClient::setState(StateAction action
, long data1
, long data2
)
552 const otk::OBProperty
*property
= Openbox::instance
->property();
554 if (!(action
== State_Add
|| action
== State_Remove
||
555 action
== State_Toggle
))
556 return; // an invalid action was passed to the client message, ignore it
558 for (int i
= 0; i
< 2; ++i
) {
559 Atom state
= i
== 0 ? data1
: data2
;
561 if (! state
) continue;
563 // if toggling, then pick whether we're adding or removing
564 if (action
== State_Toggle
) {
565 if (state
== property
->atom(otk::OBProperty::net_wm_state_modal
))
566 action
= _modal
? State_Remove
: State_Add
;
568 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
))
569 action
= _max_vert
? State_Remove
: State_Add
;
571 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
))
572 action
= _max_horz
? State_Remove
: State_Add
;
573 else if (state
== property
->atom(otk::OBProperty::net_wm_state_shaded
))
574 action
= _shaded
? State_Remove
: State_Add
;
576 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
))
577 action
= _skip_taskbar
? State_Remove
: State_Add
;
579 property
->atom(otk::OBProperty::net_wm_state_skip_pager
))
580 action
= _skip_pager
? State_Remove
: State_Add
;
582 property
->atom(otk::OBProperty::net_wm_state_fullscreen
))
583 action
= _fullscreen
? State_Remove
: State_Add
;
584 else if (state
== property
->atom(otk::OBProperty::net_wm_state_above
))
585 action
= _above
? State_Remove
: State_Add
;
586 else if (state
== property
->atom(otk::OBProperty::net_wm_state_below
))
587 action
= _below
? State_Remove
: State_Add
;
590 if (action
== State_Add
) {
591 if (state
== property
->atom(otk::OBProperty::net_wm_state_modal
)) {
592 if (_modal
) continue;
594 // XXX: give it focus if another window has focus that shouldnt now
596 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
)){
597 if (_max_vert
) continue;
599 // XXX: resize the window etc
601 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
)){
602 if (_max_horz
) continue;
604 // XXX: resize the window etc
606 property
->atom(otk::OBProperty::net_wm_state_shaded
)) {
607 if (_shaded
) continue;
609 // XXX: hide the client window
611 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
)) {
612 _skip_taskbar
= true;
614 property
->atom(otk::OBProperty::net_wm_state_skip_pager
)) {
617 property
->atom(otk::OBProperty::net_wm_state_fullscreen
)) {
618 if (_fullscreen
) continue;
620 // XXX: raise the window n shit
622 property
->atom(otk::OBProperty::net_wm_state_above
)) {
623 if (_above
) continue;
625 // XXX: raise the window n shit
627 property
->atom(otk::OBProperty::net_wm_state_below
)) {
628 if (_below
) continue;
630 // XXX: lower the window n shit
633 } else { // action == State_Remove
634 if (state
== property
->atom(otk::OBProperty::net_wm_state_modal
)) {
635 if (!_modal
) continue;
638 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
)){
639 if (!_max_vert
) continue;
641 // XXX: resize the window etc
643 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
)){
644 if (!_max_horz
) continue;
646 // XXX: resize the window etc
648 property
->atom(otk::OBProperty::net_wm_state_shaded
)) {
649 if (!_shaded
) continue;
651 // XXX: show the client window
653 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
)) {
654 _skip_taskbar
= false;
656 property
->atom(otk::OBProperty::net_wm_state_skip_pager
)) {
659 property
->atom(otk::OBProperty::net_wm_state_fullscreen
)) {
660 if (!_fullscreen
) continue;
662 // XXX: lower the window to its proper layer
664 property
->atom(otk::OBProperty::net_wm_state_above
)) {
665 if (!_above
) continue;
667 // XXX: lower the window to its proper layer
669 property
->atom(otk::OBProperty::net_wm_state_below
)) {
670 if (!_below
) continue;
672 // XXX: raise the window to its proper layer
677 Openbox::instance
->screen(_screen
)->restack(true, this); // raise
681 void OBClient::toggleClientBorder(bool addborder
)
683 // adjust our idea of where the client is, based on its border. When the
684 // border is removed, the client should now be considered to be in a
685 // different position.
686 // when re-adding the border to the client, the same operation needs to be
688 int x
= _area
.x(), y
= _area
.y();
690 case NorthWestGravity
:
692 case SouthWestGravity
:
694 case NorthEastGravity
:
696 case SouthEastGravity
:
697 if (addborder
) x
-= _border_width
* 2;
698 else x
+= _border_width
* 2;
702 case NorthWestGravity
:
704 case NorthEastGravity
:
706 case SouthWestGravity
:
708 case SouthEastGravity
:
709 if (addborder
) y
-= _border_width
* 2;
710 else y
+= _border_width
* 2;
713 // no change for StaticGravity etc.
719 XSetWindowBorderWidth(otk::OBDisplay::display
, _window
, _border_width
);
721 // move the client so it is back it the right spot _with_ its border!
722 XMoveWindow(otk::OBDisplay::display
, _window
, x
, y
);
724 XSetWindowBorderWidth(otk::OBDisplay::display
, _window
, 0);
728 void OBClient::clientMessageHandler(const XClientMessageEvent
&e
)
730 otk::OtkEventHandler::clientMessageHandler(e
);
732 if (e
.format
!= 32) return;
734 const otk::OBProperty
*property
= Openbox::instance
->property();
736 if (e
.message_type
== property
->atom(otk::OBProperty::wm_change_state
)) {
737 // compress changes into a single change
738 bool compress
= false;
740 while (XCheckTypedEvent(otk::OBDisplay::display
, e
.type
, &ce
)) {
741 // XXX: it would be nice to compress ALL messages of a type, not just
742 // messages in a row without other message types between.
743 if (ce
.xclient
.message_type
!= e
.message_type
) {
744 XPutBackEvent(otk::OBDisplay::display
, &ce
);
750 setWMState(ce
.xclient
.data
.l
[0]); // use the found event
752 setWMState(e
.data
.l
[0]); // use the original event
753 } else if (e
.message_type
==
754 property
->atom(otk::OBProperty::net_wm_desktop
)) {
755 // compress changes into a single change
756 bool compress
= false;
758 while (XCheckTypedEvent(otk::OBDisplay::display
, e
.type
, &ce
)) {
759 // XXX: it would be nice to compress ALL messages of a type, not just
760 // messages in a row without other message types between.
761 if (ce
.xclient
.message_type
!= e
.message_type
) {
762 XPutBackEvent(otk::OBDisplay::display
, &ce
);
768 setDesktop(e
.data
.l
[0]); // use the found event
770 setDesktop(e
.data
.l
[0]); // use the original event
772 else if (e
.message_type
== property
->atom(otk::OBProperty::net_wm_state
))
773 // can't compress these
774 setState((StateAction
)e
.data
.l
[0], e
.data
.l
[1], e
.data
.l
[2]);
778 #if defined(SHAPE) || defined(DOXYGEN_IGNORE)
779 void OBClient::shapeHandler(const XShapeEvent
&e
)
781 otk::OtkEventHandler::shapeHandler(e
);
788 void OBClient::resize(Corner anchor
, int w
, int h
)
793 // for interactive resizing. have to move half an increment in each
795 w
+= _size_inc
.x() / 2;
796 h
+= _size_inc
.y() / 2;
798 // is the window resizable? if it is not, then don't check its sizes, the
799 // client can do what it wants and the user can't change it anyhow
800 if (_min_size
.x() <= _max_size
.x() && _min_size
.y() <= _max_size
.y()) {
801 // smaller than min size or bigger than max size?
802 if (w
< _min_size
.x()) w
= _min_size
.x();
803 else if (w
> _max_size
.x()) w
= _max_size
.x();
804 if (h
< _min_size
.y()) h
= _min_size
.y();
805 else if (h
> _max_size
.y()) h
= _max_size
.y();
808 // keep to the increments
812 // store the logical size
813 _logical_size
.setPoint(w
, h
);
821 int x
= _area
.x(), y
= _area
.y();
826 x
-= w
- _area
.width();
829 y
-= h
- _area
.height();
832 x
-= w
- _area
.width();
833 y
-= h
- _area
.height();
838 XResizeWindow(otk::OBDisplay::display
, _window
, w
, h
);
840 // resize the frame to match the request
846 void OBClient::move(int x
, int y
)
849 // move the frame to be in the requested position
850 frame
->adjustPosition();
854 void OBClient::close()
857 const otk::OBProperty
*property
= Openbox::instance
->property();
859 if (!(_functions
& Func_Close
)) return;
861 // XXX: itd be cool to do timeouts and shit here for killing the client's
864 ce
.xclient
.type
= ClientMessage
;
865 ce
.xclient
.message_type
= property
->atom(otk::OBProperty::wm_protocols
);
866 ce
.xclient
.display
= otk::OBDisplay::display
;
867 ce
.xclient
.window
= _window
;
868 ce
.xclient
.format
= 32;
869 ce
.xclient
.data
.l
[0] = property
->atom(otk::OBProperty::wm_delete_window
);
870 ce
.xclient
.data
.l
[1] = CurrentTime
;
871 ce
.xclient
.data
.l
[2] = 0l;
872 ce
.xclient
.data
.l
[3] = 0l;
873 ce
.xclient
.data
.l
[4] = 0l;
874 XSendEvent(otk::OBDisplay::display
, _window
, False
, NoEventMask
, &ce
);
878 void OBClient::changeState()
880 const otk::OBProperty
*property
= Openbox::instance
->property();
882 unsigned long state
[2];
885 property
->set(_window
, otk::OBProperty::wm_state
, otk::OBProperty::wm_state
,
891 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_modal
);
893 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_shaded
);
895 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_hidden
);
898 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
);
900 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_skip_pager
);
902 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_fullscreen
);
905 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
);
908 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
);
910 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_above
);
912 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_below
);
913 property
->set(_window
, otk::OBProperty::net_wm_state
,
914 otk::OBProperty::Atom_Atom
, netstate
, num
);
918 void OBClient::shade(bool shade
)
920 if (shade
== _shaded
) return; // already done
922 _wmstate
= shade
? IconicState
: NormalState
;
929 bool OBClient::focus()
931 if (!_can_focus
|| _focused
) return false;
933 XSetInputFocus(otk::OBDisplay::display
, _window
, RevertToNone
, CurrentTime
);
938 void OBClient::unfocus()
940 if (!_focused
) return;
942 assert(Openbox::instance
->focusedClient() == this);
943 Openbox::instance
->setFocusedClient(0);
947 void OBClient::focusHandler(const XFocusChangeEvent
&e
)
950 printf("FocusIn for 0x%lx\n", e
.window
);
953 OtkEventHandler::focusHandler(e
);
958 Openbox::instance
->setFocusedClient(this);
962 void OBClient::unfocusHandler(const XFocusChangeEvent
&e
)
965 printf("FocusOut for 0x%lx\n", e
.window
);
968 OtkEventHandler::unfocusHandler(e
);
973 if (Openbox::instance
->focusedClient() == this) {
974 printf("UNFOCUSED!\n");
975 Openbox::instance
->setFocusedClient(this);
980 void OBClient::configureRequestHandler(const XConfigureRequestEvent
&e
)
983 printf("ConfigureRequest for 0x%lx\n", e
.window
);
986 OtkEventHandler::configureRequestHandler(e
);
988 // XXX: if we are iconic (or shaded? (fvwm does that)) ignore the event
990 if (e
.value_mask
& CWBorderWidth
)
991 _border_width
= e
.border_width
;
993 // resize, then move, as specified in the EWMH section 7.7
994 if (e
.value_mask
& (CWWidth
| CWHeight
)) {
995 int w
= (e
.value_mask
& CWWidth
) ? e
.width
: _area
.width();
996 int h
= (e
.value_mask
& CWHeight
) ? e
.height
: _area
.height();
1000 case NorthEastGravity
:
1004 case SouthWestGravity
:
1006 corner
= BottomLeft
;
1008 case SouthEastGravity
:
1009 corner
= BottomRight
;
1011 default: // NorthWest, Static, etc
1015 resize(corner
, w
, h
);
1018 if (e
.value_mask
& (CWX
| CWY
)) {
1019 int x
= (e
.value_mask
& CWX
) ? e
.x
: _area
.x();
1020 int y
= (e
.value_mask
& CWY
) ? e
.y
: _area
.y();
1024 if (e
.value_mask
& CWStackMode
) {
1028 // XXX: lower the window
1034 // XXX: raise the window
1041 void OBClient::unmapHandler(const XUnmapEvent
&e
)
1044 printf("UnmapNotify for 0x%lx\n", e
.window
);
1047 if (ignore_unmaps
) {
1052 OtkEventHandler::unmapHandler(e
);
1054 // this deletes us etc
1055 Openbox::instance
->screen(_screen
)->unmanageWindow(this);
1059 void OBClient::destroyHandler(const XDestroyWindowEvent
&e
)
1062 printf("DestroyNotify for 0x%lx\n", e
.window
);
1065 OtkEventHandler::destroyHandler(e
);
1067 // this deletes us etc
1068 Openbox::instance
->screen(_screen
)->unmanageWindow(this);
1072 void OBClient::reparentHandler(const XReparentEvent
&e
)
1074 // this is when the client is first taken captive in the frame
1075 if (e
.parent
== frame
->plate()) return;
1078 printf("ReparentNotify for 0x%lx\n", e
.window
);
1081 OtkEventHandler::reparentHandler(e
);
1084 This event is quite rare and is usually handled in unmapHandler.
1085 However, if the window is unmapped when the reparent event occurs,
1086 the window manager never sees it because an unmap event is not sent
1087 to an already unmapped window.
1090 // this deletes us etc
1091 Openbox::instance
->screen(_screen
)->unmanageWindow(this);