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
;
343 frame
->adjustSize(); // update the decorations
344 } else if (proto
[i
] == property
->atom(otk::OBProperty::wm_take_focus
))
345 // if this protocol is requested, then the window will be notified
346 // by the window manager whenever it receives focus
347 _focus_notify
= true;
354 void OBClient::updateNormalHints()
358 int oldgravity
= _gravity
;
361 _gravity
= NorthWestGravity
;
362 _size_inc
.setPoint(1, 1);
363 _base_size
.setPoint(0, 0);
364 _min_size
.setPoint(0, 0);
365 _max_size
.setPoint(INT_MAX
, INT_MAX
);
367 // XXX: might want to cancel any interactive resizing of the window at this
370 // get the hints from the window
371 if (XGetWMNormalHints(otk::OBDisplay::display
, _window
, &size
, &ret
)) {
372 _positioned
= (size
.flags
& (PPosition
|USPosition
));
374 if (size
.flags
& PWinGravity
)
375 _gravity
= size
.win_gravity
;
377 if (size
.flags
& PMinSize
)
378 _min_size
.setPoint(size
.min_width
, size
.min_height
);
380 if (size
.flags
& PMaxSize
)
381 _max_size
.setPoint(size
.max_width
, size
.max_height
);
383 if (size
.flags
& PBaseSize
)
384 _base_size
.setPoint(size
.base_width
, size
.base_height
);
386 if (size
.flags
& PResizeInc
)
387 _size_inc
.setPoint(size
.width_inc
, size
.height_inc
);
390 // if the client has a frame, i.e. has already been mapped and is
391 // changing its gravity
392 if (frame
&& _gravity
!= oldgravity
) {
393 // move our idea of the client's position based on its new gravity
395 frame
->frameGravity(x
, y
);
401 void OBClient::updateWMHints()
405 // assume a window takes input if it doesnt specify
409 if ((hints
= XGetWMHints(otk::OBDisplay::display
, _window
)) != NULL
) {
410 if (hints
->flags
& InputHint
)
411 _can_focus
= hints
->input
;
413 if (hints
->flags
& XUrgencyHint
)
416 if (hints
->flags
& WindowGroupHint
) {
417 if (hints
->window_group
!= _group
) {
418 // XXX: remove from the old group if there was one
419 _group
= hints
->window_group
;
420 // XXX: do stuff with the group
430 void OBClient::updateTitle()
432 const otk::OBProperty
*property
= Openbox::instance
->property();
437 if (! property
->get(_window
, otk::OBProperty::net_wm_name
,
438 otk::OBProperty::utf8
, &_title
)) {
440 property
->get(_window
, otk::OBProperty::wm_name
,
441 otk::OBProperty::ascii
, &_title
);
445 _title
= _("Unnamed Window");
448 frame
->setTitle(_title
);
452 void OBClient::updateIconTitle()
454 const otk::OBProperty
*property
= Openbox::instance
->property();
459 if (! property
->get(_window
, otk::OBProperty::net_wm_icon_name
,
460 otk::OBProperty::utf8
, &_icon_title
)) {
462 property
->get(_window
, otk::OBProperty::wm_icon_name
,
463 otk::OBProperty::ascii
, &_icon_title
);
467 _icon_title
= _("Unnamed Window");
471 void OBClient::updateClass()
473 const otk::OBProperty
*property
= Openbox::instance
->property();
476 _app_name
= _app_class
= "";
478 otk::OBProperty::StringVect v
;
479 unsigned long num
= 2;
481 if (! property
->get(_window
, otk::OBProperty::wm_class
,
482 otk::OBProperty::ascii
, &num
, &v
))
485 if (num
> 0) _app_name
= v
[0];
486 if (num
> 1) _app_class
= v
[1];
490 void OBClient::propertyHandler(const XPropertyEvent
&e
)
492 otk::OtkEventHandler::propertyHandler(e
);
494 const otk::OBProperty
*property
= Openbox::instance
->property();
496 // compress changes to a single property into a single change
498 while (XCheckTypedEvent(otk::OBDisplay::display
, e
.type
, &ce
)) {
499 // XXX: it would be nice to compress ALL changes to a property, not just
500 // changes in a row without other props between.
501 if (ce
.xproperty
.atom
!= e
.atom
) {
502 XPutBackEvent(otk::OBDisplay::display
, &ce
);
507 if (e
.atom
== XA_WM_NORMAL_HINTS
)
509 else if (e
.atom
== XA_WM_HINTS
)
511 else if (e
.atom
== property
->atom(otk::OBProperty::net_wm_name
) ||
512 e
.atom
== property
->atom(otk::OBProperty::wm_name
))
514 else if (e
.atom
== property
->atom(otk::OBProperty::net_wm_icon_name
) ||
515 e
.atom
== property
->atom(otk::OBProperty::wm_icon_name
))
517 else if (e
.atom
== property
->atom(otk::OBProperty::wm_class
))
519 else if (e
.atom
== property
->atom(otk::OBProperty::wm_protocols
))
521 // XXX: transient for hint
526 void OBClient::setWMState(long state
)
528 if (state
== _wmstate
) return; // no change
532 // XXX: cause it to iconify
535 // XXX: cause it to uniconify
542 void OBClient::setDesktop(long target
)
544 printf("Setting desktop %ld\n", target
);
545 assert(target
>= 0 || target
== (signed)0xffffffff);
546 //assert(target == 0xffffffff || target < MAX);
548 // XXX: move the window to the new desktop (and set root property)
553 void OBClient::setState(StateAction action
, long data1
, long data2
)
555 const otk::OBProperty
*property
= Openbox::instance
->property();
556 bool restack
= false, shadestate
= _shaded
;
558 if (!(action
== State_Add
|| action
== State_Remove
||
559 action
== State_Toggle
))
560 return; // an invalid action was passed to the client message, ignore it
562 for (int i
= 0; i
< 2; ++i
) {
563 Atom state
= i
== 0 ? data1
: data2
;
565 if (! state
) continue;
567 // if toggling, then pick whether we're adding or removing
568 if (action
== State_Toggle
) {
569 if (state
== property
->atom(otk::OBProperty::net_wm_state_modal
))
570 action
= _modal
? State_Remove
: State_Add
;
572 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
))
573 action
= _max_vert
? State_Remove
: State_Add
;
575 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
))
576 action
= _max_horz
? State_Remove
: State_Add
;
577 else if (state
== property
->atom(otk::OBProperty::net_wm_state_shaded
))
578 action
= _shaded
? State_Remove
: State_Add
;
580 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
))
581 action
= _skip_taskbar
? State_Remove
: State_Add
;
583 property
->atom(otk::OBProperty::net_wm_state_skip_pager
))
584 action
= _skip_pager
? State_Remove
: State_Add
;
586 property
->atom(otk::OBProperty::net_wm_state_fullscreen
))
587 action
= _fullscreen
? State_Remove
: State_Add
;
588 else if (state
== property
->atom(otk::OBProperty::net_wm_state_above
))
589 action
= _above
? State_Remove
: State_Add
;
590 else if (state
== property
->atom(otk::OBProperty::net_wm_state_below
))
591 action
= _below
? State_Remove
: State_Add
;
594 if (action
== State_Add
) {
595 if (state
== property
->atom(otk::OBProperty::net_wm_state_modal
)) {
596 if (_modal
) continue;
598 // XXX: give it focus if another window has focus that shouldnt now
600 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
)){
601 if (_max_vert
) continue;
603 // XXX: resize the window etc
605 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
)){
606 if (_max_horz
) continue;
608 // XXX: resize the window etc
610 property
->atom(otk::OBProperty::net_wm_state_shaded
)) {
611 if (_shaded
) continue;
612 // shade when we're all thru here
615 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
)) {
616 _skip_taskbar
= true;
618 property
->atom(otk::OBProperty::net_wm_state_skip_pager
)) {
621 property
->atom(otk::OBProperty::net_wm_state_fullscreen
)) {
622 if (_fullscreen
) continue;
626 property
->atom(otk::OBProperty::net_wm_state_above
)) {
627 if (_above
) continue;
631 property
->atom(otk::OBProperty::net_wm_state_below
)) {
632 if (_below
) continue;
637 } else { // action == State_Remove
638 if (state
== property
->atom(otk::OBProperty::net_wm_state_modal
)) {
639 if (!_modal
) continue;
642 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
)){
643 if (!_max_vert
) continue;
645 // XXX: resize the window etc
647 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
)){
648 if (!_max_horz
) continue;
650 // XXX: resize the window etc
652 property
->atom(otk::OBProperty::net_wm_state_shaded
)) {
653 if (!_shaded
) continue;
654 // unshade when we're all thru here
657 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
)) {
658 _skip_taskbar
= false;
660 property
->atom(otk::OBProperty::net_wm_state_skip_pager
)) {
663 property
->atom(otk::OBProperty::net_wm_state_fullscreen
)) {
664 if (!_fullscreen
) continue;
668 property
->atom(otk::OBProperty::net_wm_state_above
)) {
669 if (!_above
) continue;
673 property
->atom(otk::OBProperty::net_wm_state_below
)) {
674 if (!_below
) continue;
680 if (shadestate
!= _shaded
)
684 Openbox::instance
->screen(_screen
)->restack(true, this); // raise
689 void OBClient::toggleClientBorder(bool addborder
)
691 // adjust our idea of where the client is, based on its border. When the
692 // border is removed, the client should now be considered to be in a
693 // different position.
694 // when re-adding the border to the client, the same operation needs to be
696 int x
= _area
.x(), y
= _area
.y();
698 case NorthWestGravity
:
700 case SouthWestGravity
:
702 case NorthEastGravity
:
704 case SouthEastGravity
:
705 if (addborder
) x
-= _border_width
* 2;
706 else x
+= _border_width
* 2;
710 case NorthWestGravity
:
712 case NorthEastGravity
:
714 case SouthWestGravity
:
716 case SouthEastGravity
:
717 if (addborder
) y
-= _border_width
* 2;
718 else y
+= _border_width
* 2;
721 // no change for StaticGravity etc.
727 XSetWindowBorderWidth(otk::OBDisplay::display
, _window
, _border_width
);
729 // move the client so it is back it the right spot _with_ its border!
730 XMoveWindow(otk::OBDisplay::display
, _window
, x
, y
);
732 XSetWindowBorderWidth(otk::OBDisplay::display
, _window
, 0);
736 void OBClient::clientMessageHandler(const XClientMessageEvent
&e
)
738 otk::OtkEventHandler::clientMessageHandler(e
);
740 if (e
.format
!= 32) return;
742 const otk::OBProperty
*property
= Openbox::instance
->property();
744 if (e
.message_type
== property
->atom(otk::OBProperty::wm_change_state
)) {
745 // compress changes into a single change
746 bool compress
= false;
748 while (XCheckTypedEvent(otk::OBDisplay::display
, e
.type
, &ce
)) {
749 // XXX: it would be nice to compress ALL messages of a type, not just
750 // messages in a row without other message types between.
751 if (ce
.xclient
.message_type
!= e
.message_type
) {
752 XPutBackEvent(otk::OBDisplay::display
, &ce
);
758 setWMState(ce
.xclient
.data
.l
[0]); // use the found event
760 setWMState(e
.data
.l
[0]); // use the original event
761 } else if (e
.message_type
==
762 property
->atom(otk::OBProperty::net_wm_desktop
)) {
763 // compress changes into a single change
764 bool compress
= false;
766 while (XCheckTypedEvent(otk::OBDisplay::display
, e
.type
, &ce
)) {
767 // XXX: it would be nice to compress ALL messages of a type, not just
768 // messages in a row without other message types between.
769 if (ce
.xclient
.message_type
!= e
.message_type
) {
770 XPutBackEvent(otk::OBDisplay::display
, &ce
);
776 setDesktop(e
.data
.l
[0]); // use the found event
778 setDesktop(e
.data
.l
[0]); // use the original event
779 } else if (e
.message_type
== property
->atom(otk::OBProperty::net_wm_state
)) {
780 // can't compress these
781 setState((StateAction
)e
.data
.l
[0], e
.data
.l
[1], e
.data
.l
[2]);
782 } else if (e
.message_type
==
783 property
->atom(otk::OBProperty::net_close_window
)) {
785 } else if (e
.message_type
==
786 property
->atom(otk::OBProperty::net_active_window
)) {
788 Openbox::instance
->screen(_screen
)->restack(true, this); // raise
795 void OBClient::shapeHandler(const XShapeEvent
&e
)
797 otk::OtkEventHandler::shapeHandler(e
);
800 frame
->adjustShape();
805 void OBClient::resize(Corner anchor
, int w
, int h
, int x
, int y
)
810 // for interactive resizing. have to move half an increment in each
812 w
+= _size_inc
.x() / 2;
813 h
+= _size_inc
.y() / 2;
815 // is the window resizable? if it is not, then don't check its sizes, the
816 // client can do what it wants and the user can't change it anyhow
817 if (_min_size
.x() <= _max_size
.x() && _min_size
.y() <= _max_size
.y()) {
818 // smaller than min size or bigger than max size?
819 if (w
< _min_size
.x()) w
= _min_size
.x();
820 else if (w
> _max_size
.x()) w
= _max_size
.x();
821 if (h
< _min_size
.y()) h
= _min_size
.y();
822 else if (h
> _max_size
.y()) h
= _max_size
.y();
825 // keep to the increments
829 // store the logical size
830 _logical_size
.setPoint(w
, h
);
838 if (x
== INT_MIN
|| y
== INT_MIN
) {
845 x
-= w
- _area
.width();
848 y
-= h
- _area
.height();
851 x
-= w
- _area
.width();
852 y
-= h
- _area
.height();
859 XResizeWindow(otk::OBDisplay::display
, _window
, w
, h
);
861 // resize the frame to match the request
867 void OBClient::move(int x
, int y
)
871 // move the frame to be in the requested position
872 frame
->adjustPosition();
876 void OBClient::close()
879 const otk::OBProperty
*property
= Openbox::instance
->property();
881 if (!(_functions
& Func_Close
)) return;
883 // XXX: itd be cool to do timeouts and shit here for killing the client's
886 ce
.xclient
.type
= ClientMessage
;
887 ce
.xclient
.message_type
= property
->atom(otk::OBProperty::wm_protocols
);
888 ce
.xclient
.display
= otk::OBDisplay::display
;
889 ce
.xclient
.window
= _window
;
890 ce
.xclient
.format
= 32;
891 ce
.xclient
.data
.l
[0] = property
->atom(otk::OBProperty::wm_delete_window
);
892 ce
.xclient
.data
.l
[1] = CurrentTime
;
893 ce
.xclient
.data
.l
[2] = 0l;
894 ce
.xclient
.data
.l
[3] = 0l;
895 ce
.xclient
.data
.l
[4] = 0l;
896 XSendEvent(otk::OBDisplay::display
, _window
, False
, NoEventMask
, &ce
);
900 void OBClient::changeState()
902 const otk::OBProperty
*property
= Openbox::instance
->property();
904 unsigned long state
[2];
907 property
->set(_window
, otk::OBProperty::wm_state
, otk::OBProperty::wm_state
,
913 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_modal
);
915 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_shaded
);
917 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_hidden
);
920 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
);
922 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_skip_pager
);
924 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_fullscreen
);
927 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
);
930 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
);
932 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_above
);
934 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_below
);
935 property
->set(_window
, otk::OBProperty::net_wm_state
,
936 otk::OBProperty::Atom_Atom
, netstate
, num
);
940 void OBClient::shade(bool shade
)
942 if (shade
== _shaded
) return; // already done
944 _wmstate
= shade
? IconicState
: NormalState
;
951 bool OBClient::focus()
953 if (!(_can_focus
|| _focus_notify
) || _focused
) return false;
956 XSetInputFocus(otk::OBDisplay::display
, _window
, RevertToNone
, CurrentTime
);
960 const otk::OBProperty
*property
= Openbox::instance
->property();
962 ce
.xclient
.type
= ClientMessage
;
963 ce
.xclient
.message_type
= property
->atom(otk::OBProperty::wm_protocols
);
964 ce
.xclient
.display
= otk::OBDisplay::display
;
965 ce
.xclient
.window
= _window
;
966 ce
.xclient
.format
= 32;
967 ce
.xclient
.data
.l
[0] = property
->atom(otk::OBProperty::wm_take_focus
);
968 ce
.xclient
.data
.l
[1] = Openbox::instance
->lastTime();
969 ce
.xclient
.data
.l
[2] = 0l;
970 ce
.xclient
.data
.l
[3] = 0l;
971 ce
.xclient
.data
.l
[4] = 0l;
972 XSendEvent(otk::OBDisplay::display
, _window
, False
, NoEventMask
, &ce
);
979 void OBClient::unfocus()
981 if (!_focused
) return;
983 assert(Openbox::instance
->focusedClient() == this);
984 Openbox::instance
->setFocusedClient(0);
988 void OBClient::focusHandler(const XFocusChangeEvent
&e
)
991 printf("FocusIn for 0x%lx\n", e
.window
);
994 OtkEventHandler::focusHandler(e
);
999 Openbox::instance
->setFocusedClient(this);
1003 void OBClient::unfocusHandler(const XFocusChangeEvent
&e
)
1006 printf("FocusOut for 0x%lx\n", e
.window
);
1009 OtkEventHandler::unfocusHandler(e
);
1014 if (Openbox::instance
->focusedClient() == this) {
1015 printf("UNFOCUSED!\n");
1016 Openbox::instance
->setFocusedClient(this);
1021 void OBClient::configureRequestHandler(const XConfigureRequestEvent
&e
)
1024 printf("ConfigureRequest for 0x%lx\n", e
.window
);
1027 OtkEventHandler::configureRequestHandler(e
);
1029 // XXX: if we are iconic (or shaded? (fvwm does that)) ignore the event
1031 if (e
.value_mask
& CWBorderWidth
)
1032 _border_width
= e
.border_width
;
1034 // resize, then move, as specified in the EWMH section 7.7
1035 if (e
.value_mask
& (CWWidth
| CWHeight
)) {
1036 int w
= (e
.value_mask
& CWWidth
) ? e
.width
: _area
.width();
1037 int h
= (e
.value_mask
& CWHeight
) ? e
.height
: _area
.height();
1041 case NorthEastGravity
:
1045 case SouthWestGravity
:
1047 corner
= BottomLeft
;
1049 case SouthEastGravity
:
1050 corner
= BottomRight
;
1052 default: // NorthWest, Static, etc
1056 // if moving AND resizing ...
1057 if (e
.value_mask
& (CWX
| CWY
)) {
1058 int x
= (e
.value_mask
& CWX
) ? e
.x
: _area
.x();
1059 int y
= (e
.value_mask
& CWY
) ? e
.y
: _area
.y();
1060 resize(corner
, w
, h
, x
, y
);
1061 } else // if JUST resizing...
1062 resize(corner
, w
, h
);
1063 } else if (e
.value_mask
& (CWX
| CWY
)) { // if JUST moving...
1064 int x
= (e
.value_mask
& CWX
) ? e
.x
: _area
.x();
1065 int y
= (e
.value_mask
& CWY
) ? e
.y
: _area
.y();
1069 if (e
.value_mask
& CWStackMode
) {
1073 // XXX: lower the window
1079 // XXX: raise the window
1086 void OBClient::unmapHandler(const XUnmapEvent
&e
)
1089 printf("UnmapNotify for 0x%lx\n", e
.window
);
1092 if (ignore_unmaps
) {
1097 OtkEventHandler::unmapHandler(e
);
1099 // this deletes us etc
1100 Openbox::instance
->screen(_screen
)->unmanageWindow(this);
1104 void OBClient::destroyHandler(const XDestroyWindowEvent
&e
)
1107 printf("DestroyNotify for 0x%lx\n", e
.window
);
1110 OtkEventHandler::destroyHandler(e
);
1112 // this deletes us etc
1113 Openbox::instance
->screen(_screen
)->unmanageWindow(this);
1117 void OBClient::reparentHandler(const XReparentEvent
&e
)
1119 // this is when the client is first taken captive in the frame
1120 if (e
.parent
== frame
->plate()) return;
1123 printf("ReparentNotify for 0x%lx\n", e
.window
);
1126 OtkEventHandler::reparentHandler(e
);
1129 This event is quite rare and is usually handled in unmapHandler.
1130 However, if the window is unmapped when the reparent event occurs,
1131 the window manager never sees it because an unmap event is not sent
1132 to an already unmapped window.
1135 // this deletes us etc
1136 Openbox::instance
->screen(_screen
)->unmanageWindow(this);