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;
47 // XXX: updateTransientFor();
50 // set the decorations and functions
53 // normal windows retain all of the possible decorations and
55 _decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
56 Decor_Iconify
| Decor_Maximize
;
57 _functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
60 // dialogs cannot be maximized
61 _decorations
&= ~Decor_Maximize
;
62 _functions
&= ~Func_Maximize
;
68 // these windows get less functionality
69 _decorations
&= ~(Decor_Iconify
| Decor_Handle
);
70 _functions
&= ~(Func_Iconify
| Func_Resize
);
76 // none of these windows are manipulated by the window manager
82 getMwmHints(); // this fucks (in good ways) with the decors and functions
100 const otk::OBProperty
*property
= Openbox::instance
->property();
102 if (Openbox::instance
->state() != Openbox::State_Exiting
) {
103 // these values should not be persisted across a window unmapping/mapping
104 property
->erase(_window
, otk::OBProperty::net_wm_desktop
);
105 property
->erase(_window
, otk::OBProperty::net_wm_state
);
110 void OBClient::getDesktop()
112 const otk::OBProperty
*property
= Openbox::instance
->property();
114 // defaults to the current desktop
115 _desktop
= 0; // XXX: change this to the current desktop!
117 property
->get(_window
, otk::OBProperty::net_wm_desktop
,
118 otk::OBProperty::Atom_Cardinal
,
123 void OBClient::getType()
125 const otk::OBProperty
*property
= Openbox::instance
->property();
127 _type
= (WindowType
) -1;
130 unsigned long num
= (unsigned) -1;
131 if (property
->get(_window
, otk::OBProperty::net_wm_window_type
,
132 otk::OBProperty::Atom_Atom
,
134 // use the first value that we know about in the array
135 for (unsigned long i
= 0; i
< num
; ++i
) {
137 property
->atom(otk::OBProperty::net_wm_window_type_desktop
))
138 _type
= Type_Desktop
;
140 property
->atom(otk::OBProperty::net_wm_window_type_dock
))
143 property
->atom(otk::OBProperty::net_wm_window_type_toolbar
))
144 _type
= Type_Toolbar
;
146 property
->atom(otk::OBProperty::net_wm_window_type_menu
))
149 property
->atom(otk::OBProperty::net_wm_window_type_utility
))
150 _type
= Type_Utility
;
152 property
->atom(otk::OBProperty::net_wm_window_type_splash
))
155 property
->atom(otk::OBProperty::net_wm_window_type_dialog
))
158 property
->atom(otk::OBProperty::net_wm_window_type_normal
))
160 // else if (val[i] ==
161 // property->atom(otk::OBProperty::kde_net_wm_window_type_override))
162 // mwm_decorations = 0; // prevent this window from getting any decor
163 // XXX: make this work again
168 if (_type
== (WindowType
) -1) {
170 * the window type hint was not set, which means we either classify ourself
171 * as a normal window or a dialog, depending on if we are a transient.
173 // XXX: make this code work!
175 // _type = Type_Dialog;
182 void OBClient::getMwmHints()
184 const otk::OBProperty
*property
= Openbox::instance
->property();
189 num
= MwmHints::elements
;
190 if (!property
->get(_window
, otk::OBProperty::motif_wm_hints
,
191 otk::OBProperty::motif_wm_hints
, &num
,
192 (unsigned long **)&hints
))
195 if (num
< MwmHints::elements
) {
200 // retrieved the hints
201 // Mwm Hints are applied subtractively to what has already been chosen for
202 // decor and functionality
204 if (hints
->flags
& MwmFlag_Decorations
) {
205 if (! (hints
->decorations
& MwmDecor_All
)) {
206 if (! (hints
->decorations
& MwmDecor_Border
))
207 _decorations
&= ~Decor_Border
;
208 if (! (hints
->decorations
& MwmDecor_Handle
))
209 _decorations
&= ~Decor_Handle
;
210 if (! (hints
->decorations
& MwmDecor_Title
))
211 _decorations
&= ~Decor_Titlebar
;
212 if (! (hints
->decorations
& MwmDecor_Iconify
))
213 _decorations
&= ~Decor_Iconify
;
214 if (! (hints
->decorations
& MwmDecor_Maximize
))
215 _decorations
&= ~Decor_Maximize
;
219 if (hints
->flags
& MwmFlag_Functions
) {
220 if (! (hints
->functions
& MwmFunc_All
)) {
221 if (! (hints
->functions
& MwmFunc_Resize
))
222 _functions
&= ~Func_Resize
;
223 if (! (hints
->functions
& MwmFunc_Move
))
224 _functions
&= ~Func_Move
;
225 if (! (hints
->functions
& MwmFunc_Iconify
))
226 _functions
&= ~Func_Iconify
;
227 if (! (hints
->functions
& MwmFunc_Maximize
))
228 _functions
&= ~Func_Maximize
;
229 //if (! (hints->functions & MwmFunc_Close))
230 // _functions &= ~Func_Close;
237 void OBClient::getArea()
239 XWindowAttributes wattrib
;
242 ret
= XGetWindowAttributes(otk::OBDisplay::display
, _window
, &wattrib
);
243 assert(ret
!= BadWindow
);
245 _area
.setRect(wattrib
.x
, wattrib
.y
, wattrib
.width
, wattrib
.height
);
246 _border_width
= wattrib
.border_width
;
250 void OBClient::getState()
252 const otk::OBProperty
*property
= Openbox::instance
->property();
254 _modal
= _shaded
= _max_horz
= _max_vert
= _fullscreen
= _above
= _below
=
255 _skip_taskbar
= _skip_pager
= false;
257 unsigned long *state
;
258 unsigned long num
= (unsigned) -1;
260 if (property
->get(_window
, otk::OBProperty::net_wm_state
,
261 otk::OBProperty::Atom_Atom
, &num
, &state
)) {
262 for (unsigned long i
= 0; i
< num
; ++i
) {
263 if (state
[i
] == property
->atom(otk::OBProperty::net_wm_state_modal
))
266 property
->atom(otk::OBProperty::net_wm_state_shaded
))
269 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
))
270 _skip_taskbar
= true;
272 property
->atom(otk::OBProperty::net_wm_state_skip_pager
))
275 property
->atom(otk::OBProperty::net_wm_state_fullscreen
))
278 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
))
281 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
))
284 property
->atom(otk::OBProperty::net_wm_state_above
))
287 property
->atom(otk::OBProperty::net_wm_state_below
))
296 void OBClient::getShaped()
300 if (otk::OBDisplay::shape()) {
305 XShapeSelectInput(otk::OBDisplay::display
, _window
, ShapeNotifyMask
);
307 XShapeQueryExtents(otk::OBDisplay::display
, _window
, &s
, &foo
,
308 &foo
, &ufoo
, &ufoo
, &foo
, &foo
, &foo
, &ufoo
, &ufoo
);
315 void OBClient::calcLayer() {
316 if (_iconic
) _layer
= OBScreen::Layer_Icon
;
317 else if (_type
== Type_Desktop
) _layer
= OBScreen::Layer_Desktop
;
318 else if (_type
== Type_Dock
) _layer
= OBScreen::Layer_Top
;
319 else if (_fullscreen
) _layer
= OBScreen::Layer_Fullscreen
;
320 else if (_above
) _layer
= OBScreen::Layer_Above
;
321 else if (_below
) _layer
= OBScreen::Layer_Below
;
322 else _layer
= OBScreen::Layer_Normal
;
326 void OBClient::updateProtocols()
328 const otk::OBProperty
*property
= Openbox::instance
->property();
333 _focus_notify
= false;
334 _decorations
&= ~Decor_Close
;
335 _functions
&= ~Func_Close
;
337 if (XGetWMProtocols(otk::OBDisplay::display
, _window
, &proto
, &num_return
)) {
338 for (int i
= 0; i
< num_return
; ++i
) {
339 if (proto
[i
] == property
->atom(otk::OBProperty::wm_delete_window
)) {
340 _decorations
|= Decor_Close
;
341 _functions
|= Func_Close
;
342 // XXX: update the decor?
343 } else if (proto
[i
] == property
->atom(otk::OBProperty::wm_take_focus
))
344 // if this protocol is requested, then the window will be notified
345 // by the window manager whenever it receives focus
346 _focus_notify
= true;
353 void OBClient::updateNormalHints()
357 int oldgravity
= _gravity
;
360 _gravity
= NorthWestGravity
;
361 _size_inc
.setPoint(1, 1);
362 _base_size
.setPoint(0, 0);
363 _min_size
.setPoint(0, 0);
364 _max_size
.setPoint(INT_MAX
, INT_MAX
);
366 // XXX: might want to cancel any interactive resizing of the window at this
369 // get the hints from the window
370 if (XGetWMNormalHints(otk::OBDisplay::display
, _window
, &size
, &ret
)) {
371 _positioned
= (size
.flags
& (PPosition
|USPosition
));
373 if (size
.flags
& PWinGravity
)
374 _gravity
= size
.win_gravity
;
376 if (size
.flags
& PMinSize
)
377 _min_size
.setPoint(size
.min_width
, size
.min_height
);
379 if (size
.flags
& PMaxSize
)
380 _max_size
.setPoint(size
.max_width
, size
.max_height
);
382 if (size
.flags
& PBaseSize
)
383 _base_size
.setPoint(size
.base_width
, size
.base_height
);
385 if (size
.flags
& PResizeInc
)
386 _size_inc
.setPoint(size
.width_inc
, size
.height_inc
);
389 // if the client has a frame, i.e. has already been mapped and is
390 // changing its gravity
391 if (frame
&& _gravity
!= oldgravity
) {
392 // move our idea of the client's position based on its new gravity
394 frame
->frameGravity(x
, y
);
400 void OBClient::updateWMHints()
404 // assume a window takes input if it doesnt specify
408 if ((hints
= XGetWMHints(otk::OBDisplay::display
, _window
)) != NULL
) {
409 if (hints
->flags
& InputHint
)
410 _can_focus
= hints
->input
;
412 if (hints
->flags
& XUrgencyHint
)
415 if (hints
->flags
& WindowGroupHint
) {
416 if (hints
->window_group
!= _group
) {
417 // XXX: remove from the old group if there was one
418 _group
= hints
->window_group
;
419 // XXX: do stuff with the group
429 void OBClient::updateTitle()
431 const otk::OBProperty
*property
= Openbox::instance
->property();
436 if (! property
->get(_window
, otk::OBProperty::net_wm_name
,
437 otk::OBProperty::utf8
, &_title
)) {
439 property
->get(_window
, otk::OBProperty::wm_name
,
440 otk::OBProperty::ascii
, &_title
);
444 _title
= _("Unnamed Window");
447 frame
->setTitle(_title
);
451 void OBClient::updateIconTitle()
453 const otk::OBProperty
*property
= Openbox::instance
->property();
458 if (! property
->get(_window
, otk::OBProperty::net_wm_icon_name
,
459 otk::OBProperty::utf8
, &_icon_title
)) {
461 property
->get(_window
, otk::OBProperty::wm_icon_name
,
462 otk::OBProperty::ascii
, &_icon_title
);
466 _icon_title
= _("Unnamed Window");
470 void OBClient::updateClass()
472 const otk::OBProperty
*property
= Openbox::instance
->property();
475 _app_name
= _app_class
= "";
477 otk::OBProperty::StringVect v
;
478 unsigned long num
= 2;
480 if (! property
->get(_window
, otk::OBProperty::wm_class
,
481 otk::OBProperty::ascii
, &num
, &v
))
484 if (num
> 0) _app_name
= v
[0];
485 if (num
> 1) _app_class
= v
[1];
489 void OBClient::propertyHandler(const XPropertyEvent
&e
)
491 otk::OtkEventHandler::propertyHandler(e
);
493 const otk::OBProperty
*property
= Openbox::instance
->property();
495 // compress changes to a single property into a single change
497 while (XCheckTypedEvent(otk::OBDisplay::display
, e
.type
, &ce
)) {
498 // XXX: it would be nice to compress ALL changes to a property, not just
499 // changes in a row without other props between.
500 if (ce
.xproperty
.atom
!= e
.atom
) {
501 XPutBackEvent(otk::OBDisplay::display
, &ce
);
506 if (e
.atom
== XA_WM_NORMAL_HINTS
)
508 else if (e
.atom
== XA_WM_HINTS
)
510 else if (e
.atom
== property
->atom(otk::OBProperty::net_wm_name
) ||
511 e
.atom
== property
->atom(otk::OBProperty::wm_name
))
513 else if (e
.atom
== property
->atom(otk::OBProperty::net_wm_icon_name
) ||
514 e
.atom
== property
->atom(otk::OBProperty::wm_icon_name
))
516 else if (e
.atom
== property
->atom(otk::OBProperty::wm_class
))
518 else if (e
.atom
== property
->atom(otk::OBProperty::wm_protocols
))
520 // XXX: transient for hint
525 void OBClient::setWMState(long state
)
527 if (state
== _wmstate
) return; // no change
531 // XXX: cause it to iconify
534 // XXX: cause it to uniconify
541 void OBClient::setDesktop(long target
)
543 printf("Setting desktop %ld\n", target
);
544 assert(target
>= 0 || target
== (signed)0xffffffff);
545 //assert(target == 0xffffffff || target < MAX);
547 // XXX: move the window to the new desktop (and set root property)
552 void OBClient::setState(StateAction action
, long data1
, long data2
)
554 const otk::OBProperty
*property
= Openbox::instance
->property();
555 bool restack
= false, shadestate
= _shaded
;
557 if (!(action
== State_Add
|| action
== State_Remove
||
558 action
== State_Toggle
))
559 return; // an invalid action was passed to the client message, ignore it
561 for (int i
= 0; i
< 2; ++i
) {
562 Atom state
= i
== 0 ? data1
: data2
;
564 if (! state
) continue;
566 // if toggling, then pick whether we're adding or removing
567 if (action
== State_Toggle
) {
568 if (state
== property
->atom(otk::OBProperty::net_wm_state_modal
))
569 action
= _modal
? State_Remove
: State_Add
;
571 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
))
572 action
= _max_vert
? State_Remove
: State_Add
;
574 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
))
575 action
= _max_horz
? State_Remove
: State_Add
;
576 else if (state
== property
->atom(otk::OBProperty::net_wm_state_shaded
))
577 action
= _shaded
? State_Remove
: State_Add
;
579 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
))
580 action
= _skip_taskbar
? State_Remove
: State_Add
;
582 property
->atom(otk::OBProperty::net_wm_state_skip_pager
))
583 action
= _skip_pager
? State_Remove
: State_Add
;
585 property
->atom(otk::OBProperty::net_wm_state_fullscreen
))
586 action
= _fullscreen
? State_Remove
: State_Add
;
587 else if (state
== property
->atom(otk::OBProperty::net_wm_state_above
))
588 action
= _above
? State_Remove
: State_Add
;
589 else if (state
== property
->atom(otk::OBProperty::net_wm_state_below
))
590 action
= _below
? State_Remove
: State_Add
;
593 if (action
== State_Add
) {
594 if (state
== property
->atom(otk::OBProperty::net_wm_state_modal
)) {
595 if (_modal
) continue;
597 // XXX: give it focus if another window has focus that shouldnt now
599 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
)){
600 if (_max_vert
) continue;
602 // XXX: resize the window etc
604 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
)){
605 if (_max_horz
) continue;
607 // XXX: resize the window etc
609 property
->atom(otk::OBProperty::net_wm_state_shaded
)) {
610 if (_shaded
) continue;
611 // shade when we're all thru here
614 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
)) {
615 _skip_taskbar
= true;
617 property
->atom(otk::OBProperty::net_wm_state_skip_pager
)) {
620 property
->atom(otk::OBProperty::net_wm_state_fullscreen
)) {
621 if (_fullscreen
) continue;
625 property
->atom(otk::OBProperty::net_wm_state_above
)) {
626 if (_above
) continue;
630 property
->atom(otk::OBProperty::net_wm_state_below
)) {
631 if (_below
) continue;
636 } else { // action == State_Remove
637 if (state
== property
->atom(otk::OBProperty::net_wm_state_modal
)) {
638 if (!_modal
) continue;
641 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
)){
642 if (!_max_vert
) continue;
644 // XXX: resize the window etc
646 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
)){
647 if (!_max_horz
) continue;
649 // XXX: resize the window etc
651 property
->atom(otk::OBProperty::net_wm_state_shaded
)) {
652 if (!_shaded
) continue;
653 // unshade when we're all thru here
656 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
)) {
657 _skip_taskbar
= false;
659 property
->atom(otk::OBProperty::net_wm_state_skip_pager
)) {
662 property
->atom(otk::OBProperty::net_wm_state_fullscreen
)) {
663 if (!_fullscreen
) continue;
667 property
->atom(otk::OBProperty::net_wm_state_above
)) {
668 if (!_above
) continue;
672 property
->atom(otk::OBProperty::net_wm_state_below
)) {
673 if (!_below
) continue;
679 if (shadestate
!= _shaded
)
683 Openbox::instance
->screen(_screen
)->restack(true, this); // raise
688 void OBClient::toggleClientBorder(bool addborder
)
690 // adjust our idea of where the client is, based on its border. When the
691 // border is removed, the client should now be considered to be in a
692 // different position.
693 // when re-adding the border to the client, the same operation needs to be
695 int x
= _area
.x(), y
= _area
.y();
697 case NorthWestGravity
:
699 case SouthWestGravity
:
701 case NorthEastGravity
:
703 case SouthEastGravity
:
704 if (addborder
) x
-= _border_width
* 2;
705 else x
+= _border_width
* 2;
709 case NorthWestGravity
:
711 case NorthEastGravity
:
713 case SouthWestGravity
:
715 case SouthEastGravity
:
716 if (addborder
) y
-= _border_width
* 2;
717 else y
+= _border_width
* 2;
720 // no change for StaticGravity etc.
726 XSetWindowBorderWidth(otk::OBDisplay::display
, _window
, _border_width
);
728 // move the client so it is back it the right spot _with_ its border!
729 XMoveWindow(otk::OBDisplay::display
, _window
, x
, y
);
731 XSetWindowBorderWidth(otk::OBDisplay::display
, _window
, 0);
735 void OBClient::clientMessageHandler(const XClientMessageEvent
&e
)
737 otk::OtkEventHandler::clientMessageHandler(e
);
739 if (e
.format
!= 32) return;
741 const otk::OBProperty
*property
= Openbox::instance
->property();
743 if (e
.message_type
== property
->atom(otk::OBProperty::wm_change_state
)) {
744 // compress changes into a single change
745 bool compress
= false;
747 while (XCheckTypedEvent(otk::OBDisplay::display
, e
.type
, &ce
)) {
748 // XXX: it would be nice to compress ALL messages of a type, not just
749 // messages in a row without other message types between.
750 if (ce
.xclient
.message_type
!= e
.message_type
) {
751 XPutBackEvent(otk::OBDisplay::display
, &ce
);
757 setWMState(ce
.xclient
.data
.l
[0]); // use the found event
759 setWMState(e
.data
.l
[0]); // use the original event
760 } else if (e
.message_type
==
761 property
->atom(otk::OBProperty::net_wm_desktop
)) {
762 // compress changes into a single change
763 bool compress
= false;
765 while (XCheckTypedEvent(otk::OBDisplay::display
, e
.type
, &ce
)) {
766 // XXX: it would be nice to compress ALL messages of a type, not just
767 // messages in a row without other message types between.
768 if (ce
.xclient
.message_type
!= e
.message_type
) {
769 XPutBackEvent(otk::OBDisplay::display
, &ce
);
775 setDesktop(e
.data
.l
[0]); // use the found event
777 setDesktop(e
.data
.l
[0]); // use the original event
778 } else if (e
.message_type
== property
->atom(otk::OBProperty::net_wm_state
)) {
779 // can't compress these
780 setState((StateAction
)e
.data
.l
[0], e
.data
.l
[1], e
.data
.l
[2]);
781 } else if (e
.message_type
==
782 property
->atom(otk::OBProperty::net_close_window
)) {
784 } else if (e
.message_type
==
785 property
->atom(otk::OBProperty::net_active_window
)) {
787 Openbox::instance
->screen(_screen
)->restack(true, this); // raise
792 #if defined(SHAPE) || defined(DOXYGEN_IGNORE)
793 void OBClient::shapeHandler(const XShapeEvent
&e
)
795 otk::OtkEventHandler::shapeHandler(e
);
802 void OBClient::resize(Corner anchor
, int w
, int h
)
807 // for interactive resizing. have to move half an increment in each
809 w
+= _size_inc
.x() / 2;
810 h
+= _size_inc
.y() / 2;
812 // is the window resizable? if it is not, then don't check its sizes, the
813 // client can do what it wants and the user can't change it anyhow
814 if (_min_size
.x() <= _max_size
.x() && _min_size
.y() <= _max_size
.y()) {
815 // smaller than min size or bigger than max size?
816 if (w
< _min_size
.x()) w
= _min_size
.x();
817 else if (w
> _max_size
.x()) w
= _max_size
.x();
818 if (h
< _min_size
.y()) h
= _min_size
.y();
819 else if (h
> _max_size
.y()) h
= _max_size
.y();
822 // keep to the increments
826 // store the logical size
827 _logical_size
.setPoint(w
, h
);
835 int x
= _area
.x(), y
= _area
.y();
840 x
-= w
- _area
.width();
843 y
-= h
- _area
.height();
846 x
-= w
- _area
.width();
847 y
-= h
- _area
.height();
852 XResizeWindow(otk::OBDisplay::display
, _window
, w
, h
);
854 // resize the frame to match the request
860 void OBClient::move(int x
, int y
)
863 // move the frame to be in the requested position
864 frame
->adjustPosition();
868 void OBClient::close()
871 const otk::OBProperty
*property
= Openbox::instance
->property();
873 if (!(_functions
& Func_Close
)) return;
875 // XXX: itd be cool to do timeouts and shit here for killing the client's
878 ce
.xclient
.type
= ClientMessage
;
879 ce
.xclient
.message_type
= property
->atom(otk::OBProperty::wm_protocols
);
880 ce
.xclient
.display
= otk::OBDisplay::display
;
881 ce
.xclient
.window
= _window
;
882 ce
.xclient
.format
= 32;
883 ce
.xclient
.data
.l
[0] = property
->atom(otk::OBProperty::wm_delete_window
);
884 ce
.xclient
.data
.l
[1] = CurrentTime
;
885 ce
.xclient
.data
.l
[2] = 0l;
886 ce
.xclient
.data
.l
[3] = 0l;
887 ce
.xclient
.data
.l
[4] = 0l;
888 XSendEvent(otk::OBDisplay::display
, _window
, False
, NoEventMask
, &ce
);
892 void OBClient::changeState()
894 const otk::OBProperty
*property
= Openbox::instance
->property();
896 unsigned long state
[2];
899 property
->set(_window
, otk::OBProperty::wm_state
, otk::OBProperty::wm_state
,
905 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_modal
);
907 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_shaded
);
909 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_hidden
);
912 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
);
914 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_skip_pager
);
916 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_fullscreen
);
919 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
);
922 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
);
924 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_above
);
926 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_below
);
927 property
->set(_window
, otk::OBProperty::net_wm_state
,
928 otk::OBProperty::Atom_Atom
, netstate
, num
);
932 void OBClient::shade(bool shade
)
934 if (shade
== _shaded
) return; // already done
936 _wmstate
= shade
? IconicState
: NormalState
;
943 bool OBClient::focus()
945 if (!(_can_focus
|| _focus_notify
) || _focused
) return false;
948 XSetInputFocus(otk::OBDisplay::display
, _window
, RevertToNone
, CurrentTime
);
952 const otk::OBProperty
*property
= Openbox::instance
->property();
954 ce
.xclient
.type
= ClientMessage
;
955 ce
.xclient
.message_type
= property
->atom(otk::OBProperty::wm_protocols
);
956 ce
.xclient
.display
= otk::OBDisplay::display
;
957 ce
.xclient
.window
= _window
;
958 ce
.xclient
.format
= 32;
959 ce
.xclient
.data
.l
[0] = property
->atom(otk::OBProperty::wm_take_focus
);
960 ce
.xclient
.data
.l
[1] = Openbox::instance
->lastTime();
961 ce
.xclient
.data
.l
[2] = 0l;
962 ce
.xclient
.data
.l
[3] = 0l;
963 ce
.xclient
.data
.l
[4] = 0l;
964 XSendEvent(otk::OBDisplay::display
, _window
, False
, NoEventMask
, &ce
);
971 void OBClient::unfocus()
973 if (!_focused
) return;
975 assert(Openbox::instance
->focusedClient() == this);
976 Openbox::instance
->setFocusedClient(0);
980 void OBClient::focusHandler(const XFocusChangeEvent
&e
)
983 printf("FocusIn for 0x%lx\n", e
.window
);
986 OtkEventHandler::focusHandler(e
);
991 Openbox::instance
->setFocusedClient(this);
995 void OBClient::unfocusHandler(const XFocusChangeEvent
&e
)
998 printf("FocusOut for 0x%lx\n", e
.window
);
1001 OtkEventHandler::unfocusHandler(e
);
1006 if (Openbox::instance
->focusedClient() == this) {
1007 printf("UNFOCUSED!\n");
1008 Openbox::instance
->setFocusedClient(this);
1013 void OBClient::configureRequestHandler(const XConfigureRequestEvent
&e
)
1016 printf("ConfigureRequest for 0x%lx\n", e
.window
);
1019 OtkEventHandler::configureRequestHandler(e
);
1021 // XXX: if we are iconic (or shaded? (fvwm does that)) ignore the event
1023 if (e
.value_mask
& CWBorderWidth
)
1024 _border_width
= e
.border_width
;
1026 // resize, then move, as specified in the EWMH section 7.7
1027 if (e
.value_mask
& (CWWidth
| CWHeight
)) {
1028 int w
= (e
.value_mask
& CWWidth
) ? e
.width
: _area
.width();
1029 int h
= (e
.value_mask
& CWHeight
) ? e
.height
: _area
.height();
1033 case NorthEastGravity
:
1037 case SouthWestGravity
:
1039 corner
= BottomLeft
;
1041 case SouthEastGravity
:
1042 corner
= BottomRight
;
1044 default: // NorthWest, Static, etc
1048 resize(corner
, w
, h
);
1051 if (e
.value_mask
& (CWX
| CWY
)) {
1052 int x
= (e
.value_mask
& CWX
) ? e
.x
: _area
.x();
1053 int y
= (e
.value_mask
& CWY
) ? e
.y
: _area
.y();
1057 if (e
.value_mask
& CWStackMode
) {
1061 // XXX: lower the window
1067 // XXX: raise the window
1074 void OBClient::unmapHandler(const XUnmapEvent
&e
)
1077 printf("UnmapNotify for 0x%lx\n", e
.window
);
1080 if (ignore_unmaps
) {
1085 OtkEventHandler::unmapHandler(e
);
1087 // this deletes us etc
1088 Openbox::instance
->screen(_screen
)->unmanageWindow(this);
1092 void OBClient::destroyHandler(const XDestroyWindowEvent
&e
)
1095 printf("DestroyNotify for 0x%lx\n", e
.window
);
1098 OtkEventHandler::destroyHandler(e
);
1100 // this deletes us etc
1101 Openbox::instance
->screen(_screen
)->unmanageWindow(this);
1105 void OBClient::reparentHandler(const XReparentEvent
&e
)
1107 // this is when the client is first taken captive in the frame
1108 if (e
.parent
== frame
->plate()) return;
1111 printf("ReparentNotify for 0x%lx\n", e
.window
);
1114 OtkEventHandler::reparentHandler(e
);
1117 This event is quite rare and is usually handled in unmapHandler.
1118 However, if the window is unmapped when the reparent event occurs,
1119 the window manager never sees it because an unmap event is not sent
1120 to an already unmapped window.
1123 // this deletes us etc
1124 Openbox::instance
->screen(_screen
)->unmanageWindow(this);