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
51 _decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
52 Decor_Iconify
| Decor_Maximize
;
53 _functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
56 // normal windows retain all of the possible decorations and
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
101 const otk::OBProperty
*property
= Openbox::instance
->property();
103 if (Openbox::instance
->state() != Openbox::State_Exiting
) {
104 // these values should not be persisted across a window unmapping/mapping
105 property
->erase(_window
, otk::OBProperty::net_wm_desktop
);
106 property
->erase(_window
, otk::OBProperty::net_wm_state
);
111 void OBClient::getDesktop()
113 const otk::OBProperty
*property
= Openbox::instance
->property();
115 // defaults to the current desktop
116 _desktop
= 0; // XXX: change this to the current desktop!
118 property
->get(_window
, otk::OBProperty::net_wm_desktop
,
119 otk::OBProperty::Atom_Cardinal
,
124 void OBClient::getType()
126 const otk::OBProperty
*property
= Openbox::instance
->property();
128 _type
= (WindowType
) -1;
131 unsigned long num
= (unsigned) -1;
132 if (property
->get(_window
, otk::OBProperty::net_wm_window_type
,
133 otk::OBProperty::Atom_Atom
,
135 // use the first value that we know about in the array
136 for (unsigned long i
= 0; i
< num
; ++i
) {
138 property
->atom(otk::OBProperty::net_wm_window_type_desktop
))
139 _type
= Type_Desktop
;
141 property
->atom(otk::OBProperty::net_wm_window_type_dock
))
144 property
->atom(otk::OBProperty::net_wm_window_type_toolbar
))
145 _type
= Type_Toolbar
;
147 property
->atom(otk::OBProperty::net_wm_window_type_menu
))
150 property
->atom(otk::OBProperty::net_wm_window_type_utility
))
151 _type
= Type_Utility
;
153 property
->atom(otk::OBProperty::net_wm_window_type_splash
))
156 property
->atom(otk::OBProperty::net_wm_window_type_dialog
))
159 property
->atom(otk::OBProperty::net_wm_window_type_normal
))
161 // else if (val[i] ==
162 // property->atom(otk::OBProperty::kde_net_wm_window_type_override))
163 // mwm_decorations = 0; // prevent this window from getting any decor
164 // XXX: make this work again
169 if (_type
== (WindowType
) -1) {
171 * the window type hint was not set, which means we either classify ourself
172 * as a normal window or a dialog, depending on if we are a transient.
174 // XXX: make this code work!
176 // _type = Type_Dialog;
183 void OBClient::getMwmHints()
185 const otk::OBProperty
*property
= Openbox::instance
->property();
190 num
= MwmHints::elements
;
191 if (!property
->get(_window
, otk::OBProperty::motif_wm_hints
,
192 otk::OBProperty::motif_wm_hints
, &num
,
193 (unsigned long **)&hints
))
196 if (num
< MwmHints::elements
) {
201 // retrieved the hints
202 // Mwm Hints are applied subtractively to what has already been chosen for
203 // decor and functionality
205 if (hints
->flags
& MwmFlag_Decorations
) {
206 if (! (hints
->decorations
& MwmDecor_All
)) {
207 if (! (hints
->decorations
& MwmDecor_Border
))
208 _decorations
&= ~Decor_Border
;
209 if (! (hints
->decorations
& MwmDecor_Handle
))
210 _decorations
&= ~Decor_Handle
;
211 if (! (hints
->decorations
& MwmDecor_Title
))
212 _decorations
&= ~Decor_Titlebar
;
213 if (! (hints
->decorations
& MwmDecor_Iconify
))
214 _decorations
&= ~Decor_Iconify
;
215 if (! (hints
->decorations
& MwmDecor_Maximize
))
216 _decorations
&= ~Decor_Maximize
;
220 if (hints
->flags
& MwmFlag_Functions
) {
221 if (! (hints
->functions
& MwmFunc_All
)) {
222 if (! (hints
->functions
& MwmFunc_Resize
))
223 _functions
&= ~Func_Resize
;
224 if (! (hints
->functions
& MwmFunc_Move
))
225 _functions
&= ~Func_Move
;
226 if (! (hints
->functions
& MwmFunc_Iconify
))
227 _functions
&= ~Func_Iconify
;
228 if (! (hints
->functions
& MwmFunc_Maximize
))
229 _functions
&= ~Func_Maximize
;
230 //if (! (hints->functions & MwmFunc_Close))
231 // _functions &= ~Func_Close;
238 void OBClient::getArea()
240 XWindowAttributes wattrib
;
243 ret
= XGetWindowAttributes(otk::OBDisplay::display
, _window
, &wattrib
);
244 assert(ret
!= BadWindow
);
246 _area
.setRect(wattrib
.x
, wattrib
.y
, wattrib
.width
, wattrib
.height
);
247 _border_width
= wattrib
.border_width
;
251 void OBClient::getState()
253 const otk::OBProperty
*property
= Openbox::instance
->property();
255 _modal
= _shaded
= _max_horz
= _max_vert
= _fullscreen
= _above
= _below
=
256 _skip_taskbar
= _skip_pager
= false;
258 unsigned long *state
;
259 unsigned long num
= (unsigned) -1;
261 if (property
->get(_window
, otk::OBProperty::net_wm_state
,
262 otk::OBProperty::Atom_Atom
, &num
, &state
)) {
263 for (unsigned long i
= 0; i
< num
; ++i
) {
264 if (state
[i
] == property
->atom(otk::OBProperty::net_wm_state_modal
))
267 property
->atom(otk::OBProperty::net_wm_state_shaded
))
270 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
))
271 _skip_taskbar
= true;
273 property
->atom(otk::OBProperty::net_wm_state_skip_pager
))
276 property
->atom(otk::OBProperty::net_wm_state_fullscreen
))
279 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
))
282 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
))
285 property
->atom(otk::OBProperty::net_wm_state_above
))
288 property
->atom(otk::OBProperty::net_wm_state_below
))
297 void OBClient::getShaped()
301 if (otk::OBDisplay::shape()) {
306 XShapeSelectInput(otk::OBDisplay::display
, _window
, ShapeNotifyMask
);
308 XShapeQueryExtents(otk::OBDisplay::display
, _window
, &s
, &foo
,
309 &foo
, &ufoo
, &ufoo
, &foo
, &foo
, &foo
, &ufoo
, &ufoo
);
316 void OBClient::calcLayer() {
317 if (_iconic
) _layer
= OBScreen::Layer_Icon
;
318 else if (_type
== Type_Desktop
) _layer
= OBScreen::Layer_Desktop
;
319 else if (_type
== Type_Dock
) _layer
= OBScreen::Layer_Top
;
320 else if (_fullscreen
) _layer
= OBScreen::Layer_Fullscreen
;
321 else if (_above
) _layer
= OBScreen::Layer_Above
;
322 else if (_below
) _layer
= OBScreen::Layer_Below
;
323 else _layer
= OBScreen::Layer_Normal
;
327 void OBClient::updateProtocols()
329 const otk::OBProperty
*property
= Openbox::instance
->property();
334 _focus_notify
= false;
335 _decorations
&= ~Decor_Close
;
336 _functions
&= ~Func_Close
;
338 if (XGetWMProtocols(otk::OBDisplay::display
, _window
, &proto
, &num_return
)) {
339 for (int i
= 0; i
< num_return
; ++i
) {
340 if (proto
[i
] == property
->atom(otk::OBProperty::wm_delete_window
)) {
341 _decorations
|= Decor_Close
;
342 _functions
|= Func_Close
;
344 frame
->adjustSize(); // update the decorations
345 } else if (proto
[i
] == property
->atom(otk::OBProperty::wm_take_focus
))
346 // if this protocol is requested, then the window will be notified
347 // by the window manager whenever it receives focus
348 _focus_notify
= true;
355 void OBClient::updateNormalHints()
359 int oldgravity
= _gravity
;
362 _gravity
= NorthWestGravity
;
363 _size_inc
.setPoint(1, 1);
364 _base_size
.setPoint(0, 0);
365 _min_size
.setPoint(0, 0);
366 _max_size
.setPoint(INT_MAX
, INT_MAX
);
368 // XXX: might want to cancel any interactive resizing of the window at this
371 // get the hints from the window
372 if (XGetWMNormalHints(otk::OBDisplay::display
, _window
, &size
, &ret
)) {
373 _positioned
= (size
.flags
& (PPosition
|USPosition
));
375 if (size
.flags
& PWinGravity
)
376 _gravity
= size
.win_gravity
;
378 if (size
.flags
& PMinSize
)
379 _min_size
.setPoint(size
.min_width
, size
.min_height
);
381 if (size
.flags
& PMaxSize
)
382 _max_size
.setPoint(size
.max_width
, size
.max_height
);
384 if (size
.flags
& PBaseSize
)
385 _base_size
.setPoint(size
.base_width
, size
.base_height
);
387 if (size
.flags
& PResizeInc
)
388 _size_inc
.setPoint(size
.width_inc
, size
.height_inc
);
391 // if the client has a frame, i.e. has already been mapped and is
392 // changing its gravity
393 if (frame
&& _gravity
!= oldgravity
) {
394 // move our idea of the client's position based on its new gravity
396 frame
->frameGravity(x
, y
);
402 void OBClient::updateWMHints()
406 // assume a window takes input if it doesnt specify
410 if ((hints
= XGetWMHints(otk::OBDisplay::display
, _window
)) != NULL
) {
411 if (hints
->flags
& InputHint
)
412 _can_focus
= hints
->input
;
414 if (hints
->flags
& XUrgencyHint
)
417 if (hints
->flags
& WindowGroupHint
) {
418 if (hints
->window_group
!= _group
) {
419 // XXX: remove from the old group if there was one
420 _group
= hints
->window_group
;
421 // XXX: do stuff with the group
431 void OBClient::updateTitle()
433 const otk::OBProperty
*property
= Openbox::instance
->property();
438 if (! property
->get(_window
, otk::OBProperty::net_wm_name
,
439 otk::OBProperty::utf8
, &_title
)) {
441 property
->get(_window
, otk::OBProperty::wm_name
,
442 otk::OBProperty::ascii
, &_title
);
446 _title
= _("Unnamed Window");
449 frame
->setTitle(_title
);
453 void OBClient::updateIconTitle()
455 const otk::OBProperty
*property
= Openbox::instance
->property();
460 if (! property
->get(_window
, otk::OBProperty::net_wm_icon_name
,
461 otk::OBProperty::utf8
, &_icon_title
)) {
463 property
->get(_window
, otk::OBProperty::wm_icon_name
,
464 otk::OBProperty::ascii
, &_icon_title
);
468 _icon_title
= _("Unnamed Window");
472 void OBClient::updateClass()
474 const otk::OBProperty
*property
= Openbox::instance
->property();
477 _app_name
= _app_class
= "";
479 otk::OBProperty::StringVect v
;
480 unsigned long num
= 2;
482 if (! property
->get(_window
, otk::OBProperty::wm_class
,
483 otk::OBProperty::ascii
, &num
, &v
))
486 if (num
> 0) _app_name
= v
[0];
487 if (num
> 1) _app_class
= v
[1];
491 void OBClient::updateStrut()
493 unsigned long num
= 4;
495 if (!Openbox::instance
->property()->get(_window
,
496 otk::OBProperty::net_wm_strut
,
497 otk::OBProperty::Atom_Cardinal
,
502 _strut
.left
= data
[0];
503 _strut
.right
= data
[1];
504 _strut
.top
= data
[2];
505 _strut
.bottom
= data
[3];
507 Openbox::instance
->screen(_screen
)->updateStrut();
514 void OBClient::propertyHandler(const XPropertyEvent
&e
)
516 otk::OtkEventHandler::propertyHandler(e
);
518 const otk::OBProperty
*property
= Openbox::instance
->property();
520 // compress changes to a single property into a single change
522 while (XCheckTypedEvent(otk::OBDisplay::display
, e
.type
, &ce
)) {
523 // XXX: it would be nice to compress ALL changes to a property, not just
524 // changes in a row without other props between.
525 if (ce
.xproperty
.atom
!= e
.atom
) {
526 XPutBackEvent(otk::OBDisplay::display
, &ce
);
531 if (e
.atom
== XA_WM_NORMAL_HINTS
)
533 else if (e
.atom
== XA_WM_HINTS
)
535 else if (e
.atom
== property
->atom(otk::OBProperty::net_wm_name
) ||
536 e
.atom
== property
->atom(otk::OBProperty::wm_name
))
538 else if (e
.atom
== property
->atom(otk::OBProperty::net_wm_icon_name
) ||
539 e
.atom
== property
->atom(otk::OBProperty::wm_icon_name
))
541 else if (e
.atom
== property
->atom(otk::OBProperty::wm_class
))
543 else if (e
.atom
== property
->atom(otk::OBProperty::wm_protocols
))
545 // XXX: transient for hint
546 else if (e
.atom
== property
->atom(otk::OBProperty::net_wm_strut
))
552 void OBClient::setWMState(long state
)
554 if (state
== _wmstate
) return; // no change
558 // XXX: cause it to iconify
561 // XXX: cause it to uniconify
568 void OBClient::setDesktop(long target
)
570 printf("Setting desktop %ld\n", target
);
571 assert(target
>= 0 || target
== (signed)0xffffffff);
572 //assert(target == 0xffffffff || target < MAX);
574 // XXX: move the window to the new desktop (and set root property)
579 void OBClient::setState(StateAction action
, long data1
, long data2
)
581 const otk::OBProperty
*property
= Openbox::instance
->property();
582 bool restack
= false, shadestate
= _shaded
;
584 if (!(action
== State_Add
|| action
== State_Remove
||
585 action
== State_Toggle
))
586 return; // an invalid action was passed to the client message, ignore it
588 for (int i
= 0; i
< 2; ++i
) {
589 Atom state
= i
== 0 ? data1
: data2
;
591 if (! state
) continue;
593 // if toggling, then pick whether we're adding or removing
594 if (action
== State_Toggle
) {
595 if (state
== property
->atom(otk::OBProperty::net_wm_state_modal
))
596 action
= _modal
? State_Remove
: State_Add
;
598 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
))
599 action
= _max_vert
? State_Remove
: State_Add
;
601 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
))
602 action
= _max_horz
? State_Remove
: State_Add
;
603 else if (state
== property
->atom(otk::OBProperty::net_wm_state_shaded
))
604 action
= _shaded
? State_Remove
: State_Add
;
606 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
))
607 action
= _skip_taskbar
? State_Remove
: State_Add
;
609 property
->atom(otk::OBProperty::net_wm_state_skip_pager
))
610 action
= _skip_pager
? State_Remove
: State_Add
;
612 property
->atom(otk::OBProperty::net_wm_state_fullscreen
))
613 action
= _fullscreen
? State_Remove
: State_Add
;
614 else if (state
== property
->atom(otk::OBProperty::net_wm_state_above
))
615 action
= _above
? State_Remove
: State_Add
;
616 else if (state
== property
->atom(otk::OBProperty::net_wm_state_below
))
617 action
= _below
? State_Remove
: State_Add
;
620 if (action
== State_Add
) {
621 if (state
== property
->atom(otk::OBProperty::net_wm_state_modal
)) {
622 if (_modal
) continue;
624 // XXX: give it focus if another window has focus that shouldnt now
626 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
)){
627 if (_max_vert
) continue;
629 // XXX: resize the window etc
631 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
)){
632 if (_max_horz
) continue;
634 // XXX: resize the window etc
636 property
->atom(otk::OBProperty::net_wm_state_shaded
)) {
637 if (_shaded
) continue;
638 // shade when we're all thru here
641 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
)) {
642 _skip_taskbar
= true;
644 property
->atom(otk::OBProperty::net_wm_state_skip_pager
)) {
647 property
->atom(otk::OBProperty::net_wm_state_fullscreen
)) {
648 if (_fullscreen
) continue;
652 property
->atom(otk::OBProperty::net_wm_state_above
)) {
653 if (_above
) continue;
657 property
->atom(otk::OBProperty::net_wm_state_below
)) {
658 if (_below
) continue;
663 } else { // action == State_Remove
664 if (state
== property
->atom(otk::OBProperty::net_wm_state_modal
)) {
665 if (!_modal
) continue;
668 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
)){
669 if (!_max_vert
) continue;
671 // XXX: resize the window etc
673 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
)){
674 if (!_max_horz
) continue;
676 // XXX: resize the window etc
678 property
->atom(otk::OBProperty::net_wm_state_shaded
)) {
679 if (!_shaded
) continue;
680 // unshade when we're all thru here
683 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
)) {
684 _skip_taskbar
= false;
686 property
->atom(otk::OBProperty::net_wm_state_skip_pager
)) {
689 property
->atom(otk::OBProperty::net_wm_state_fullscreen
)) {
690 if (!_fullscreen
) continue;
694 property
->atom(otk::OBProperty::net_wm_state_above
)) {
695 if (!_above
) continue;
699 property
->atom(otk::OBProperty::net_wm_state_below
)) {
700 if (!_below
) continue;
706 if (shadestate
!= _shaded
)
710 Openbox::instance
->screen(_screen
)->restack(true, this); // raise
715 void OBClient::toggleClientBorder(bool addborder
)
717 // adjust our idea of where the client is, based on its border. When the
718 // border is removed, the client should now be considered to be in a
719 // different position.
720 // when re-adding the border to the client, the same operation needs to be
722 int x
= _area
.x(), y
= _area
.y();
724 case NorthWestGravity
:
726 case SouthWestGravity
:
728 case NorthEastGravity
:
730 case SouthEastGravity
:
731 if (addborder
) x
-= _border_width
* 2;
732 else x
+= _border_width
* 2;
736 case NorthWestGravity
:
738 case NorthEastGravity
:
740 case SouthWestGravity
:
742 case SouthEastGravity
:
743 if (addborder
) y
-= _border_width
* 2;
744 else y
+= _border_width
* 2;
747 // no change for StaticGravity etc.
753 XSetWindowBorderWidth(otk::OBDisplay::display
, _window
, _border_width
);
755 // move the client so it is back it the right spot _with_ its border!
756 XMoveWindow(otk::OBDisplay::display
, _window
, x
, y
);
758 XSetWindowBorderWidth(otk::OBDisplay::display
, _window
, 0);
762 void OBClient::clientMessageHandler(const XClientMessageEvent
&e
)
764 otk::OtkEventHandler::clientMessageHandler(e
);
766 if (e
.format
!= 32) return;
768 const otk::OBProperty
*property
= Openbox::instance
->property();
770 if (e
.message_type
== property
->atom(otk::OBProperty::wm_change_state
)) {
771 // compress changes into a single change
772 bool compress
= false;
774 while (XCheckTypedEvent(otk::OBDisplay::display
, e
.type
, &ce
)) {
775 // XXX: it would be nice to compress ALL messages of a type, not just
776 // messages in a row without other message types between.
777 if (ce
.xclient
.message_type
!= e
.message_type
) {
778 XPutBackEvent(otk::OBDisplay::display
, &ce
);
784 setWMState(ce
.xclient
.data
.l
[0]); // use the found event
786 setWMState(e
.data
.l
[0]); // use the original event
787 } else if (e
.message_type
==
788 property
->atom(otk::OBProperty::net_wm_desktop
)) {
789 // compress changes into a single change
790 bool compress
= false;
792 while (XCheckTypedEvent(otk::OBDisplay::display
, e
.type
, &ce
)) {
793 // XXX: it would be nice to compress ALL messages of a type, not just
794 // messages in a row without other message types between.
795 if (ce
.xclient
.message_type
!= e
.message_type
) {
796 XPutBackEvent(otk::OBDisplay::display
, &ce
);
802 setDesktop(e
.data
.l
[0]); // use the found event
804 setDesktop(e
.data
.l
[0]); // use the original event
805 } else if (e
.message_type
== property
->atom(otk::OBProperty::net_wm_state
)) {
806 // can't compress these
807 setState((StateAction
)e
.data
.l
[0], e
.data
.l
[1], e
.data
.l
[2]);
808 } else if (e
.message_type
==
809 property
->atom(otk::OBProperty::net_close_window
)) {
811 } else if (e
.message_type
==
812 property
->atom(otk::OBProperty::net_active_window
)) {
814 Openbox::instance
->screen(_screen
)->restack(true, this); // raise
821 void OBClient::shapeHandler(const XShapeEvent
&e
)
823 otk::OtkEventHandler::shapeHandler(e
);
826 frame
->adjustShape();
831 void OBClient::resize(Corner anchor
, int w
, int h
, int x
, int y
)
836 // for interactive resizing. have to move half an increment in each
838 w
+= _size_inc
.x() / 2;
839 h
+= _size_inc
.y() / 2;
841 // is the window resizable? if it is not, then don't check its sizes, the
842 // client can do what it wants and the user can't change it anyhow
843 if (_min_size
.x() <= _max_size
.x() && _min_size
.y() <= _max_size
.y()) {
844 // smaller than min size or bigger than max size?
845 if (w
< _min_size
.x()) w
= _min_size
.x();
846 else if (w
> _max_size
.x()) w
= _max_size
.x();
847 if (h
< _min_size
.y()) h
= _min_size
.y();
848 else if (h
> _max_size
.y()) h
= _max_size
.y();
851 // keep to the increments
855 // store the logical size
856 _logical_size
.setPoint(w
, h
);
864 if (x
== INT_MIN
|| y
== INT_MIN
) {
871 x
-= w
- _area
.width();
874 y
-= h
- _area
.height();
877 x
-= w
- _area
.width();
878 y
-= h
- _area
.height();
885 XResizeWindow(otk::OBDisplay::display
, _window
, w
, h
);
887 // resize the frame to match the request
893 void OBClient::move(int x
, int y
)
897 // move the frame to be in the requested position
898 frame
->adjustPosition();
902 void OBClient::close()
905 const otk::OBProperty
*property
= Openbox::instance
->property();
907 if (!(_functions
& Func_Close
)) return;
909 // XXX: itd be cool to do timeouts and shit here for killing the client's
911 // like... if the window is around after 5 seconds, then the close button
912 // turns a nice red, and if this function is called again, the client is
913 // explicitly killed.
915 ce
.xclient
.type
= ClientMessage
;
916 ce
.xclient
.message_type
= property
->atom(otk::OBProperty::wm_protocols
);
917 ce
.xclient
.display
= otk::OBDisplay::display
;
918 ce
.xclient
.window
= _window
;
919 ce
.xclient
.format
= 32;
920 ce
.xclient
.data
.l
[0] = property
->atom(otk::OBProperty::wm_delete_window
);
921 ce
.xclient
.data
.l
[1] = CurrentTime
;
922 ce
.xclient
.data
.l
[2] = 0l;
923 ce
.xclient
.data
.l
[3] = 0l;
924 ce
.xclient
.data
.l
[4] = 0l;
925 XSendEvent(otk::OBDisplay::display
, _window
, False
, NoEventMask
, &ce
);
929 void OBClient::changeState()
931 const otk::OBProperty
*property
= Openbox::instance
->property();
933 unsigned long state
[2];
936 property
->set(_window
, otk::OBProperty::wm_state
, otk::OBProperty::wm_state
,
942 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_modal
);
944 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_shaded
);
946 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_hidden
);
949 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
);
951 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_skip_pager
);
953 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_fullscreen
);
956 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
);
959 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
);
961 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_above
);
963 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_below
);
964 property
->set(_window
, otk::OBProperty::net_wm_state
,
965 otk::OBProperty::Atom_Atom
, netstate
, num
);
969 void OBClient::shade(bool shade
)
971 if (shade
== _shaded
) return; // already done
973 _wmstate
= shade
? IconicState
: NormalState
;
980 bool OBClient::focus()
982 if (!(_can_focus
|| _focus_notify
) || _focused
) return false;
985 XSetInputFocus(otk::OBDisplay::display
, _window
, RevertToNone
, CurrentTime
);
989 const otk::OBProperty
*property
= Openbox::instance
->property();
991 ce
.xclient
.type
= ClientMessage
;
992 ce
.xclient
.message_type
= property
->atom(otk::OBProperty::wm_protocols
);
993 ce
.xclient
.display
= otk::OBDisplay::display
;
994 ce
.xclient
.window
= _window
;
995 ce
.xclient
.format
= 32;
996 ce
.xclient
.data
.l
[0] = property
->atom(otk::OBProperty::wm_take_focus
);
997 ce
.xclient
.data
.l
[1] = Openbox::instance
->lastTime();
998 ce
.xclient
.data
.l
[2] = 0l;
999 ce
.xclient
.data
.l
[3] = 0l;
1000 ce
.xclient
.data
.l
[4] = 0l;
1001 XSendEvent(otk::OBDisplay::display
, _window
, False
, NoEventMask
, &ce
);
1008 void OBClient::unfocus()
1010 if (!_focused
) return;
1012 assert(Openbox::instance
->focusedClient() == this);
1013 Openbox::instance
->setFocusedClient(0);
1017 void OBClient::focusHandler(const XFocusChangeEvent
&e
)
1020 printf("FocusIn for 0x%lx\n", e
.window
);
1023 OtkEventHandler::focusHandler(e
);
1028 Openbox::instance
->setFocusedClient(this);
1032 void OBClient::unfocusHandler(const XFocusChangeEvent
&e
)
1035 printf("FocusOut for 0x%lx\n", e
.window
);
1038 OtkEventHandler::unfocusHandler(e
);
1043 if (Openbox::instance
->focusedClient() == this) {
1044 printf("UNFOCUSED!\n");
1045 Openbox::instance
->setFocusedClient(this);
1050 void OBClient::configureRequestHandler(const XConfigureRequestEvent
&e
)
1053 printf("ConfigureRequest for 0x%lx\n", e
.window
);
1056 OtkEventHandler::configureRequestHandler(e
);
1058 // XXX: if we are iconic (or shaded? (fvwm does that)) ignore the event
1060 if (e
.value_mask
& CWBorderWidth
)
1061 _border_width
= e
.border_width
;
1063 // resize, then move, as specified in the EWMH section 7.7
1064 if (e
.value_mask
& (CWWidth
| CWHeight
)) {
1065 int w
= (e
.value_mask
& CWWidth
) ? e
.width
: _area
.width();
1066 int h
= (e
.value_mask
& CWHeight
) ? e
.height
: _area
.height();
1070 case NorthEastGravity
:
1074 case SouthWestGravity
:
1076 corner
= BottomLeft
;
1078 case SouthEastGravity
:
1079 corner
= BottomRight
;
1081 default: // NorthWest, Static, etc
1085 // if moving AND resizing ...
1086 if (e
.value_mask
& (CWX
| CWY
)) {
1087 int x
= (e
.value_mask
& CWX
) ? e
.x
: _area
.x();
1088 int y
= (e
.value_mask
& CWY
) ? e
.y
: _area
.y();
1089 resize(corner
, w
, h
, x
, y
);
1090 } else // if JUST resizing...
1091 resize(corner
, w
, h
);
1092 } else if (e
.value_mask
& (CWX
| CWY
)) { // if JUST moving...
1093 int x
= (e
.value_mask
& CWX
) ? e
.x
: _area
.x();
1094 int y
= (e
.value_mask
& CWY
) ? e
.y
: _area
.y();
1098 if (e
.value_mask
& CWStackMode
) {
1102 // XXX: lower the window
1108 // XXX: raise the window
1115 void OBClient::unmapHandler(const XUnmapEvent
&e
)
1118 printf("UnmapNotify for 0x%lx\n", e
.window
);
1121 if (ignore_unmaps
) {
1126 OtkEventHandler::unmapHandler(e
);
1128 // this deletes us etc
1129 Openbox::instance
->screen(_screen
)->unmanageWindow(this);
1133 void OBClient::destroyHandler(const XDestroyWindowEvent
&e
)
1136 printf("DestroyNotify for 0x%lx\n", e
.window
);
1139 OtkEventHandler::destroyHandler(e
);
1141 // this deletes us etc
1142 Openbox::instance
->screen(_screen
)->unmanageWindow(this);
1146 void OBClient::reparentHandler(const XReparentEvent
&e
)
1148 // this is when the client is first taken captive in the frame
1149 if (e
.parent
== frame
->plate()) return;
1152 printf("ReparentNotify for 0x%lx\n", e
.window
);
1155 OtkEventHandler::reparentHandler(e
);
1158 This event is quite rare and is usually handled in unmapHandler.
1159 However, if the window is unmapped when the reparent event occurs,
1160 the window manager never sees it because an unmap event is not sent
1161 to an already unmapped window.
1164 // this deletes us etc
1165 Openbox::instance
->screen(_screen
)->unmanageWindow(this);