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 (and set root property)
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
771 } else if (e
.message_type
== property
->atom(otk::OBProperty::net_wm_state
)) {
772 // can't compress these
773 setState((StateAction
)e
.data
.l
[0], e
.data
.l
[1], e
.data
.l
[2]);
774 } else if (e
.message_type
==
775 property
->atom(otk::OBProperty::net_close_window
)) {
777 } else if (e
.message_type
==
778 property
->atom(otk::OBProperty::net_active_window
)) {
784 #if defined(SHAPE) || defined(DOXYGEN_IGNORE)
785 void OBClient::shapeHandler(const XShapeEvent
&e
)
787 otk::OtkEventHandler::shapeHandler(e
);
794 void OBClient::resize(Corner anchor
, int w
, int h
)
799 // for interactive resizing. have to move half an increment in each
801 w
+= _size_inc
.x() / 2;
802 h
+= _size_inc
.y() / 2;
804 // is the window resizable? if it is not, then don't check its sizes, the
805 // client can do what it wants and the user can't change it anyhow
806 if (_min_size
.x() <= _max_size
.x() && _min_size
.y() <= _max_size
.y()) {
807 // smaller than min size or bigger than max size?
808 if (w
< _min_size
.x()) w
= _min_size
.x();
809 else if (w
> _max_size
.x()) w
= _max_size
.x();
810 if (h
< _min_size
.y()) h
= _min_size
.y();
811 else if (h
> _max_size
.y()) h
= _max_size
.y();
814 // keep to the increments
818 // store the logical size
819 _logical_size
.setPoint(w
, h
);
827 int x
= _area
.x(), y
= _area
.y();
832 x
-= w
- _area
.width();
835 y
-= h
- _area
.height();
838 x
-= w
- _area
.width();
839 y
-= h
- _area
.height();
844 XResizeWindow(otk::OBDisplay::display
, _window
, w
, h
);
846 // resize the frame to match the request
852 void OBClient::move(int x
, int y
)
855 // move the frame to be in the requested position
856 frame
->adjustPosition();
860 void OBClient::close()
863 const otk::OBProperty
*property
= Openbox::instance
->property();
865 if (!(_functions
& Func_Close
)) return;
867 // XXX: itd be cool to do timeouts and shit here for killing the client's
870 ce
.xclient
.type
= ClientMessage
;
871 ce
.xclient
.message_type
= property
->atom(otk::OBProperty::wm_protocols
);
872 ce
.xclient
.display
= otk::OBDisplay::display
;
873 ce
.xclient
.window
= _window
;
874 ce
.xclient
.format
= 32;
875 ce
.xclient
.data
.l
[0] = property
->atom(otk::OBProperty::wm_delete_window
);
876 ce
.xclient
.data
.l
[1] = CurrentTime
;
877 ce
.xclient
.data
.l
[2] = 0l;
878 ce
.xclient
.data
.l
[3] = 0l;
879 ce
.xclient
.data
.l
[4] = 0l;
880 XSendEvent(otk::OBDisplay::display
, _window
, False
, NoEventMask
, &ce
);
884 void OBClient::changeState()
886 const otk::OBProperty
*property
= Openbox::instance
->property();
888 unsigned long state
[2];
891 property
->set(_window
, otk::OBProperty::wm_state
, otk::OBProperty::wm_state
,
897 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_modal
);
899 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_shaded
);
901 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_hidden
);
904 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
);
906 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_skip_pager
);
908 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_fullscreen
);
911 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
);
914 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
);
916 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_above
);
918 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_below
);
919 property
->set(_window
, otk::OBProperty::net_wm_state
,
920 otk::OBProperty::Atom_Atom
, netstate
, num
);
924 void OBClient::shade(bool shade
)
926 if (shade
== _shaded
) return; // already done
928 _wmstate
= shade
? IconicState
: NormalState
;
935 bool OBClient::focus()
937 if (!_can_focus
|| _focused
) return false;
939 XSetInputFocus(otk::OBDisplay::display
, _window
, RevertToNone
, CurrentTime
);
944 void OBClient::unfocus()
946 if (!_focused
) return;
948 assert(Openbox::instance
->focusedClient() == this);
949 Openbox::instance
->setFocusedClient(0);
953 void OBClient::focusHandler(const XFocusChangeEvent
&e
)
956 printf("FocusIn for 0x%lx\n", e
.window
);
959 OtkEventHandler::focusHandler(e
);
964 Openbox::instance
->setFocusedClient(this);
968 void OBClient::unfocusHandler(const XFocusChangeEvent
&e
)
971 printf("FocusOut for 0x%lx\n", e
.window
);
974 OtkEventHandler::unfocusHandler(e
);
979 if (Openbox::instance
->focusedClient() == this) {
980 printf("UNFOCUSED!\n");
981 Openbox::instance
->setFocusedClient(this);
986 void OBClient::configureRequestHandler(const XConfigureRequestEvent
&e
)
989 printf("ConfigureRequest for 0x%lx\n", e
.window
);
992 OtkEventHandler::configureRequestHandler(e
);
994 // XXX: if we are iconic (or shaded? (fvwm does that)) ignore the event
996 if (e
.value_mask
& CWBorderWidth
)
997 _border_width
= e
.border_width
;
999 // resize, then move, as specified in the EWMH section 7.7
1000 if (e
.value_mask
& (CWWidth
| CWHeight
)) {
1001 int w
= (e
.value_mask
& CWWidth
) ? e
.width
: _area
.width();
1002 int h
= (e
.value_mask
& CWHeight
) ? e
.height
: _area
.height();
1006 case NorthEastGravity
:
1010 case SouthWestGravity
:
1012 corner
= BottomLeft
;
1014 case SouthEastGravity
:
1015 corner
= BottomRight
;
1017 default: // NorthWest, Static, etc
1021 resize(corner
, w
, h
);
1024 if (e
.value_mask
& (CWX
| CWY
)) {
1025 int x
= (e
.value_mask
& CWX
) ? e
.x
: _area
.x();
1026 int y
= (e
.value_mask
& CWY
) ? e
.y
: _area
.y();
1030 if (e
.value_mask
& CWStackMode
) {
1034 // XXX: lower the window
1040 // XXX: raise the window
1047 void OBClient::unmapHandler(const XUnmapEvent
&e
)
1050 printf("UnmapNotify for 0x%lx\n", e
.window
);
1053 if (ignore_unmaps
) {
1058 OtkEventHandler::unmapHandler(e
);
1060 // this deletes us etc
1061 Openbox::instance
->screen(_screen
)->unmanageWindow(this);
1065 void OBClient::destroyHandler(const XDestroyWindowEvent
&e
)
1068 printf("DestroyNotify for 0x%lx\n", e
.window
);
1071 OtkEventHandler::destroyHandler(e
);
1073 // this deletes us etc
1074 Openbox::instance
->screen(_screen
)->unmanageWindow(this);
1078 void OBClient::reparentHandler(const XReparentEvent
&e
)
1080 // this is when the client is first taken captive in the frame
1081 if (e
.parent
== frame
->plate()) return;
1084 printf("ReparentNotify for 0x%lx\n", e
.window
);
1087 OtkEventHandler::reparentHandler(e
);
1090 This event is quite rare and is usually handled in unmapHandler.
1091 However, if the window is unmapped when the reparent event occurs,
1092 the window manager never sees it because an unmap event is not sent
1093 to an already unmapped window.
1096 // this deletes us etc
1097 Openbox::instance
->screen(_screen
)->unmanageWindow(this);