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
)
542 printf("Setting desktop %ld\n", target
);
543 assert(target
>= 0 || target
== (signed)0xffffffff);
544 //assert(target == 0xffffffff || target < MAX);
546 // XXX: move the window to the new desktop (and set root property)
551 void OBClient::setState(StateAction action
, long data1
, long data2
)
553 const otk::OBProperty
*property
= Openbox::instance
->property();
554 bool restack
= false, shadestate
= _shaded
;
556 if (!(action
== State_Add
|| action
== State_Remove
||
557 action
== State_Toggle
))
558 return; // an invalid action was passed to the client message, ignore it
560 for (int i
= 0; i
< 2; ++i
) {
561 Atom state
= i
== 0 ? data1
: data2
;
563 if (! state
) continue;
565 // if toggling, then pick whether we're adding or removing
566 if (action
== State_Toggle
) {
567 if (state
== property
->atom(otk::OBProperty::net_wm_state_modal
))
568 action
= _modal
? State_Remove
: State_Add
;
570 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
))
571 action
= _max_vert
? State_Remove
: State_Add
;
573 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
))
574 action
= _max_horz
? State_Remove
: State_Add
;
575 else if (state
== property
->atom(otk::OBProperty::net_wm_state_shaded
))
576 action
= _shaded
? State_Remove
: State_Add
;
578 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
))
579 action
= _skip_taskbar
? State_Remove
: State_Add
;
581 property
->atom(otk::OBProperty::net_wm_state_skip_pager
))
582 action
= _skip_pager
? State_Remove
: State_Add
;
584 property
->atom(otk::OBProperty::net_wm_state_fullscreen
))
585 action
= _fullscreen
? State_Remove
: State_Add
;
586 else if (state
== property
->atom(otk::OBProperty::net_wm_state_above
))
587 action
= _above
? State_Remove
: State_Add
;
588 else if (state
== property
->atom(otk::OBProperty::net_wm_state_below
))
589 action
= _below
? State_Remove
: State_Add
;
592 if (action
== State_Add
) {
593 if (state
== property
->atom(otk::OBProperty::net_wm_state_modal
)) {
594 if (_modal
) continue;
596 // XXX: give it focus if another window has focus that shouldnt now
598 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
)){
599 if (_max_vert
) continue;
601 // XXX: resize the window etc
603 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
)){
604 if (_max_horz
) continue;
606 // XXX: resize the window etc
608 property
->atom(otk::OBProperty::net_wm_state_shaded
)) {
609 if (_shaded
) continue;
610 // shade when we're all thru here
613 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
)) {
614 _skip_taskbar
= true;
616 property
->atom(otk::OBProperty::net_wm_state_skip_pager
)) {
619 property
->atom(otk::OBProperty::net_wm_state_fullscreen
)) {
620 if (_fullscreen
) continue;
624 property
->atom(otk::OBProperty::net_wm_state_above
)) {
625 if (_above
) continue;
629 property
->atom(otk::OBProperty::net_wm_state_below
)) {
630 if (_below
) continue;
635 } else { // action == State_Remove
636 if (state
== property
->atom(otk::OBProperty::net_wm_state_modal
)) {
637 if (!_modal
) continue;
640 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
)){
641 if (!_max_vert
) continue;
643 // XXX: resize the window etc
645 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
)){
646 if (!_max_horz
) continue;
648 // XXX: resize the window etc
650 property
->atom(otk::OBProperty::net_wm_state_shaded
)) {
651 if (!_shaded
) continue;
652 // unshade when we're all thru here
655 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
)) {
656 _skip_taskbar
= false;
658 property
->atom(otk::OBProperty::net_wm_state_skip_pager
)) {
661 property
->atom(otk::OBProperty::net_wm_state_fullscreen
)) {
662 if (!_fullscreen
) continue;
666 property
->atom(otk::OBProperty::net_wm_state_above
)) {
667 if (!_above
) continue;
671 property
->atom(otk::OBProperty::net_wm_state_below
)) {
672 if (!_below
) continue;
678 if (shadestate
!= _shaded
)
682 Openbox::instance
->screen(_screen
)->restack(true, this); // raise
687 void OBClient::toggleClientBorder(bool addborder
)
689 // adjust our idea of where the client is, based on its border. When the
690 // border is removed, the client should now be considered to be in a
691 // different position.
692 // when re-adding the border to the client, the same operation needs to be
694 int x
= _area
.x(), y
= _area
.y();
696 case NorthWestGravity
:
698 case SouthWestGravity
:
700 case NorthEastGravity
:
702 case SouthEastGravity
:
703 if (addborder
) x
-= _border_width
* 2;
704 else x
+= _border_width
* 2;
708 case NorthWestGravity
:
710 case NorthEastGravity
:
712 case SouthWestGravity
:
714 case SouthEastGravity
:
715 if (addborder
) y
-= _border_width
* 2;
716 else y
+= _border_width
* 2;
719 // no change for StaticGravity etc.
725 XSetWindowBorderWidth(otk::OBDisplay::display
, _window
, _border_width
);
727 // move the client so it is back it the right spot _with_ its border!
728 XMoveWindow(otk::OBDisplay::display
, _window
, x
, y
);
730 XSetWindowBorderWidth(otk::OBDisplay::display
, _window
, 0);
734 void OBClient::clientMessageHandler(const XClientMessageEvent
&e
)
736 otk::OtkEventHandler::clientMessageHandler(e
);
738 if (e
.format
!= 32) return;
740 const otk::OBProperty
*property
= Openbox::instance
->property();
742 if (e
.message_type
== property
->atom(otk::OBProperty::wm_change_state
)) {
743 // compress changes into a single change
744 bool compress
= false;
746 while (XCheckTypedEvent(otk::OBDisplay::display
, e
.type
, &ce
)) {
747 // XXX: it would be nice to compress ALL messages of a type, not just
748 // messages in a row without other message types between.
749 if (ce
.xclient
.message_type
!= e
.message_type
) {
750 XPutBackEvent(otk::OBDisplay::display
, &ce
);
756 setWMState(ce
.xclient
.data
.l
[0]); // use the found event
758 setWMState(e
.data
.l
[0]); // use the original event
759 } else if (e
.message_type
==
760 property
->atom(otk::OBProperty::net_wm_desktop
)) {
761 // compress changes into a single change
762 bool compress
= false;
764 while (XCheckTypedEvent(otk::OBDisplay::display
, e
.type
, &ce
)) {
765 // XXX: it would be nice to compress ALL messages of a type, not just
766 // messages in a row without other message types between.
767 if (ce
.xclient
.message_type
!= e
.message_type
) {
768 XPutBackEvent(otk::OBDisplay::display
, &ce
);
774 setDesktop(e
.data
.l
[0]); // use the found event
776 setDesktop(e
.data
.l
[0]); // use the original event
777 } else if (e
.message_type
== property
->atom(otk::OBProperty::net_wm_state
)) {
778 // can't compress these
779 setState((StateAction
)e
.data
.l
[0], e
.data
.l
[1], e
.data
.l
[2]);
780 } else if (e
.message_type
==
781 property
->atom(otk::OBProperty::net_close_window
)) {
783 } else if (e
.message_type
==
784 property
->atom(otk::OBProperty::net_active_window
)) {
790 #if defined(SHAPE) || defined(DOXYGEN_IGNORE)
791 void OBClient::shapeHandler(const XShapeEvent
&e
)
793 otk::OtkEventHandler::shapeHandler(e
);
800 void OBClient::resize(Corner anchor
, int w
, int h
)
805 // for interactive resizing. have to move half an increment in each
807 w
+= _size_inc
.x() / 2;
808 h
+= _size_inc
.y() / 2;
810 // is the window resizable? if it is not, then don't check its sizes, the
811 // client can do what it wants and the user can't change it anyhow
812 if (_min_size
.x() <= _max_size
.x() && _min_size
.y() <= _max_size
.y()) {
813 // smaller than min size or bigger than max size?
814 if (w
< _min_size
.x()) w
= _min_size
.x();
815 else if (w
> _max_size
.x()) w
= _max_size
.x();
816 if (h
< _min_size
.y()) h
= _min_size
.y();
817 else if (h
> _max_size
.y()) h
= _max_size
.y();
820 // keep to the increments
824 // store the logical size
825 _logical_size
.setPoint(w
, h
);
833 int x
= _area
.x(), y
= _area
.y();
838 x
-= w
- _area
.width();
841 y
-= h
- _area
.height();
844 x
-= w
- _area
.width();
845 y
-= h
- _area
.height();
850 XResizeWindow(otk::OBDisplay::display
, _window
, w
, h
);
852 // resize the frame to match the request
858 void OBClient::move(int x
, int y
)
861 // move the frame to be in the requested position
862 frame
->adjustPosition();
866 void OBClient::close()
869 const otk::OBProperty
*property
= Openbox::instance
->property();
871 if (!(_functions
& Func_Close
)) return;
873 // XXX: itd be cool to do timeouts and shit here for killing the client's
876 ce
.xclient
.type
= ClientMessage
;
877 ce
.xclient
.message_type
= property
->atom(otk::OBProperty::wm_protocols
);
878 ce
.xclient
.display
= otk::OBDisplay::display
;
879 ce
.xclient
.window
= _window
;
880 ce
.xclient
.format
= 32;
881 ce
.xclient
.data
.l
[0] = property
->atom(otk::OBProperty::wm_delete_window
);
882 ce
.xclient
.data
.l
[1] = CurrentTime
;
883 ce
.xclient
.data
.l
[2] = 0l;
884 ce
.xclient
.data
.l
[3] = 0l;
885 ce
.xclient
.data
.l
[4] = 0l;
886 XSendEvent(otk::OBDisplay::display
, _window
, False
, NoEventMask
, &ce
);
890 void OBClient::changeState()
892 const otk::OBProperty
*property
= Openbox::instance
->property();
894 unsigned long state
[2];
897 property
->set(_window
, otk::OBProperty::wm_state
, otk::OBProperty::wm_state
,
903 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_modal
);
905 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_shaded
);
907 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_hidden
);
910 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
);
912 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_skip_pager
);
914 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_fullscreen
);
917 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
);
920 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
);
922 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_above
);
924 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_below
);
925 property
->set(_window
, otk::OBProperty::net_wm_state
,
926 otk::OBProperty::Atom_Atom
, netstate
, num
);
930 void OBClient::shade(bool shade
)
932 if (shade
== _shaded
) return; // already done
934 _wmstate
= shade
? IconicState
: NormalState
;
941 bool OBClient::focus()
943 if (!(_can_focus
|| _focus_notify
) || _focused
) return false;
946 XSetInputFocus(otk::OBDisplay::display
, _window
, RevertToNone
, CurrentTime
);
950 const otk::OBProperty
*property
= Openbox::instance
->property();
952 ce
.xclient
.type
= ClientMessage
;
953 ce
.xclient
.message_type
= property
->atom(otk::OBProperty::wm_protocols
);
954 ce
.xclient
.display
= otk::OBDisplay::display
;
955 ce
.xclient
.window
= _window
;
956 ce
.xclient
.format
= 32;
957 ce
.xclient
.data
.l
[0] = property
->atom(otk::OBProperty::wm_take_focus
);
958 ce
.xclient
.data
.l
[1] = Openbox::instance
->lastTime();
959 ce
.xclient
.data
.l
[2] = 0l;
960 ce
.xclient
.data
.l
[3] = 0l;
961 ce
.xclient
.data
.l
[4] = 0l;
962 XSendEvent(otk::OBDisplay::display
, _window
, False
, NoEventMask
, &ce
);
969 void OBClient::unfocus()
971 if (!_focused
) return;
973 assert(Openbox::instance
->focusedClient() == this);
974 Openbox::instance
->setFocusedClient(0);
978 void OBClient::focusHandler(const XFocusChangeEvent
&e
)
981 printf("FocusIn for 0x%lx\n", e
.window
);
984 OtkEventHandler::focusHandler(e
);
989 Openbox::instance
->setFocusedClient(this);
993 void OBClient::unfocusHandler(const XFocusChangeEvent
&e
)
996 printf("FocusOut for 0x%lx\n", e
.window
);
999 OtkEventHandler::unfocusHandler(e
);
1004 if (Openbox::instance
->focusedClient() == this) {
1005 printf("UNFOCUSED!\n");
1006 Openbox::instance
->setFocusedClient(this);
1011 void OBClient::configureRequestHandler(const XConfigureRequestEvent
&e
)
1014 printf("ConfigureRequest for 0x%lx\n", e
.window
);
1017 OtkEventHandler::configureRequestHandler(e
);
1019 // XXX: if we are iconic (or shaded? (fvwm does that)) ignore the event
1021 if (e
.value_mask
& CWBorderWidth
)
1022 _border_width
= e
.border_width
;
1024 // resize, then move, as specified in the EWMH section 7.7
1025 if (e
.value_mask
& (CWWidth
| CWHeight
)) {
1026 int w
= (e
.value_mask
& CWWidth
) ? e
.width
: _area
.width();
1027 int h
= (e
.value_mask
& CWHeight
) ? e
.height
: _area
.height();
1031 case NorthEastGravity
:
1035 case SouthWestGravity
:
1037 corner
= BottomLeft
;
1039 case SouthEastGravity
:
1040 corner
= BottomRight
;
1042 default: // NorthWest, Static, etc
1046 resize(corner
, w
, h
);
1049 if (e
.value_mask
& (CWX
| CWY
)) {
1050 int x
= (e
.value_mask
& CWX
) ? e
.x
: _area
.x();
1051 int y
= (e
.value_mask
& CWY
) ? e
.y
: _area
.y();
1055 if (e
.value_mask
& CWStackMode
) {
1059 // XXX: lower the window
1065 // XXX: raise the window
1072 void OBClient::unmapHandler(const XUnmapEvent
&e
)
1075 printf("UnmapNotify for 0x%lx\n", e
.window
);
1078 if (ignore_unmaps
) {
1083 OtkEventHandler::unmapHandler(e
);
1085 // this deletes us etc
1086 Openbox::instance
->screen(_screen
)->unmanageWindow(this);
1090 void OBClient::destroyHandler(const XDestroyWindowEvent
&e
)
1093 printf("DestroyNotify for 0x%lx\n", e
.window
);
1096 OtkEventHandler::destroyHandler(e
);
1098 // this deletes us etc
1099 Openbox::instance
->screen(_screen
)->unmanageWindow(this);
1103 void OBClient::reparentHandler(const XReparentEvent
&e
)
1105 // this is when the client is first taken captive in the frame
1106 if (e
.parent
== frame
->plate()) return;
1109 printf("ReparentNotify for 0x%lx\n", e
.window
);
1112 OtkEventHandler::reparentHandler(e
);
1115 This event is quite rare and is usually handled in unmapHandler.
1116 However, if the window is unmapped when the reparent event occurs,
1117 the window manager never sees it because an unmap event is not sent
1118 to an already unmapped window.
1121 // this deletes us etc
1122 Openbox::instance
->screen(_screen
)->unmanageWindow(this);