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();
555 if (!(action
== State_Add
|| action
== State_Remove
||
556 action
== State_Toggle
))
557 return; // an invalid action was passed to the client message, ignore it
559 for (int i
= 0; i
< 2; ++i
) {
560 Atom state
= i
== 0 ? data1
: data2
;
562 if (! state
) continue;
564 // if toggling, then pick whether we're adding or removing
565 if (action
== State_Toggle
) {
566 if (state
== property
->atom(otk::OBProperty::net_wm_state_modal
))
567 action
= _modal
? State_Remove
: State_Add
;
569 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
))
570 action
= _max_vert
? State_Remove
: State_Add
;
572 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
))
573 action
= _max_horz
? State_Remove
: State_Add
;
574 else if (state
== property
->atom(otk::OBProperty::net_wm_state_shaded
))
575 action
= _shaded
? State_Remove
: State_Add
;
577 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
))
578 action
= _skip_taskbar
? State_Remove
: State_Add
;
580 property
->atom(otk::OBProperty::net_wm_state_skip_pager
))
581 action
= _skip_pager
? State_Remove
: State_Add
;
583 property
->atom(otk::OBProperty::net_wm_state_fullscreen
))
584 action
= _fullscreen
? State_Remove
: State_Add
;
585 else if (state
== property
->atom(otk::OBProperty::net_wm_state_above
))
586 action
= _above
? State_Remove
: State_Add
;
587 else if (state
== property
->atom(otk::OBProperty::net_wm_state_below
))
588 action
= _below
? State_Remove
: State_Add
;
591 if (action
== State_Add
) {
592 if (state
== property
->atom(otk::OBProperty::net_wm_state_modal
)) {
593 if (_modal
) continue;
595 // XXX: give it focus if another window has focus that shouldnt now
597 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
)){
598 if (_max_vert
) continue;
600 // XXX: resize the window etc
602 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
)){
603 if (_max_horz
) continue;
605 // XXX: resize the window etc
607 property
->atom(otk::OBProperty::net_wm_state_shaded
)) {
608 if (_shaded
) continue;
610 // XXX: hide the client window
612 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
)) {
613 _skip_taskbar
= true;
615 property
->atom(otk::OBProperty::net_wm_state_skip_pager
)) {
618 property
->atom(otk::OBProperty::net_wm_state_fullscreen
)) {
619 if (_fullscreen
) continue;
621 // XXX: raise the window n shit
623 property
->atom(otk::OBProperty::net_wm_state_above
)) {
624 if (_above
) continue;
626 // XXX: raise the window n shit
628 property
->atom(otk::OBProperty::net_wm_state_below
)) {
629 if (_below
) continue;
631 // XXX: lower the window n shit
634 } else { // action == State_Remove
635 if (state
== property
->atom(otk::OBProperty::net_wm_state_modal
)) {
636 if (!_modal
) continue;
639 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
)){
640 if (!_max_vert
) continue;
642 // XXX: resize the window etc
644 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
)){
645 if (!_max_horz
) continue;
647 // XXX: resize the window etc
649 property
->atom(otk::OBProperty::net_wm_state_shaded
)) {
650 if (!_shaded
) continue;
652 // XXX: show the client window
654 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
)) {
655 _skip_taskbar
= false;
657 property
->atom(otk::OBProperty::net_wm_state_skip_pager
)) {
660 property
->atom(otk::OBProperty::net_wm_state_fullscreen
)) {
661 if (!_fullscreen
) continue;
663 // XXX: lower the window to its proper layer
665 property
->atom(otk::OBProperty::net_wm_state_above
)) {
666 if (!_above
) continue;
668 // XXX: lower the window to its proper layer
670 property
->atom(otk::OBProperty::net_wm_state_below
)) {
671 if (!_below
) continue;
673 // XXX: raise the window to its proper layer
678 Openbox::instance
->screen(_screen
)->restack(true, this); // raise
682 void OBClient::toggleClientBorder(bool addborder
)
684 // adjust our idea of where the client is, based on its border. When the
685 // border is removed, the client should now be considered to be in a
686 // different position.
687 // when re-adding the border to the client, the same operation needs to be
689 int x
= _area
.x(), y
= _area
.y();
691 case NorthWestGravity
:
693 case SouthWestGravity
:
695 case NorthEastGravity
:
697 case SouthEastGravity
:
698 if (addborder
) x
-= _border_width
* 2;
699 else x
+= _border_width
* 2;
703 case NorthWestGravity
:
705 case NorthEastGravity
:
707 case SouthWestGravity
:
709 case SouthEastGravity
:
710 if (addborder
) y
-= _border_width
* 2;
711 else y
+= _border_width
* 2;
714 // no change for StaticGravity etc.
720 XSetWindowBorderWidth(otk::OBDisplay::display
, _window
, _border_width
);
722 // move the client so it is back it the right spot _with_ its border!
723 XMoveWindow(otk::OBDisplay::display
, _window
, x
, y
);
725 XSetWindowBorderWidth(otk::OBDisplay::display
, _window
, 0);
729 void OBClient::clientMessageHandler(const XClientMessageEvent
&e
)
731 otk::OtkEventHandler::clientMessageHandler(e
);
733 if (e
.format
!= 32) return;
735 const otk::OBProperty
*property
= Openbox::instance
->property();
737 if (e
.message_type
== property
->atom(otk::OBProperty::wm_change_state
)) {
738 // compress changes into a single change
739 bool compress
= false;
741 while (XCheckTypedEvent(otk::OBDisplay::display
, e
.type
, &ce
)) {
742 // XXX: it would be nice to compress ALL messages of a type, not just
743 // messages in a row without other message types between.
744 if (ce
.xclient
.message_type
!= e
.message_type
) {
745 XPutBackEvent(otk::OBDisplay::display
, &ce
);
751 setWMState(ce
.xclient
.data
.l
[0]); // use the found event
753 setWMState(e
.data
.l
[0]); // use the original event
754 } else if (e
.message_type
==
755 property
->atom(otk::OBProperty::net_wm_desktop
)) {
756 // compress changes into a single change
757 bool compress
= false;
759 while (XCheckTypedEvent(otk::OBDisplay::display
, e
.type
, &ce
)) {
760 // XXX: it would be nice to compress ALL messages of a type, not just
761 // messages in a row without other message types between.
762 if (ce
.xclient
.message_type
!= e
.message_type
) {
763 XPutBackEvent(otk::OBDisplay::display
, &ce
);
769 setDesktop(e
.data
.l
[0]); // use the found event
771 setDesktop(e
.data
.l
[0]); // use the original event
772 } else if (e
.message_type
== property
->atom(otk::OBProperty::net_wm_state
)) {
773 // can't compress these
774 setState((StateAction
)e
.data
.l
[0], e
.data
.l
[1], e
.data
.l
[2]);
775 } else if (e
.message_type
==
776 property
->atom(otk::OBProperty::net_close_window
)) {
778 } else if (e
.message_type
==
779 property
->atom(otk::OBProperty::net_active_window
)) {
785 #if defined(SHAPE) || defined(DOXYGEN_IGNORE)
786 void OBClient::shapeHandler(const XShapeEvent
&e
)
788 otk::OtkEventHandler::shapeHandler(e
);
795 void OBClient::resize(Corner anchor
, int w
, int h
)
800 // for interactive resizing. have to move half an increment in each
802 w
+= _size_inc
.x() / 2;
803 h
+= _size_inc
.y() / 2;
805 // is the window resizable? if it is not, then don't check its sizes, the
806 // client can do what it wants and the user can't change it anyhow
807 if (_min_size
.x() <= _max_size
.x() && _min_size
.y() <= _max_size
.y()) {
808 // smaller than min size or bigger than max size?
809 if (w
< _min_size
.x()) w
= _min_size
.x();
810 else if (w
> _max_size
.x()) w
= _max_size
.x();
811 if (h
< _min_size
.y()) h
= _min_size
.y();
812 else if (h
> _max_size
.y()) h
= _max_size
.y();
815 // keep to the increments
819 // store the logical size
820 _logical_size
.setPoint(w
, h
);
828 int x
= _area
.x(), y
= _area
.y();
833 x
-= w
- _area
.width();
836 y
-= h
- _area
.height();
839 x
-= w
- _area
.width();
840 y
-= h
- _area
.height();
845 XResizeWindow(otk::OBDisplay::display
, _window
, w
, h
);
847 // resize the frame to match the request
853 void OBClient::move(int x
, int y
)
856 // move the frame to be in the requested position
857 frame
->adjustPosition();
861 void OBClient::close()
864 const otk::OBProperty
*property
= Openbox::instance
->property();
866 if (!(_functions
& Func_Close
)) return;
868 // XXX: itd be cool to do timeouts and shit here for killing the client's
871 ce
.xclient
.type
= ClientMessage
;
872 ce
.xclient
.message_type
= property
->atom(otk::OBProperty::wm_protocols
);
873 ce
.xclient
.display
= otk::OBDisplay::display
;
874 ce
.xclient
.window
= _window
;
875 ce
.xclient
.format
= 32;
876 ce
.xclient
.data
.l
[0] = property
->atom(otk::OBProperty::wm_delete_window
);
877 ce
.xclient
.data
.l
[1] = CurrentTime
;
878 ce
.xclient
.data
.l
[2] = 0l;
879 ce
.xclient
.data
.l
[3] = 0l;
880 ce
.xclient
.data
.l
[4] = 0l;
881 XSendEvent(otk::OBDisplay::display
, _window
, False
, NoEventMask
, &ce
);
885 void OBClient::changeState()
887 const otk::OBProperty
*property
= Openbox::instance
->property();
889 unsigned long state
[2];
892 property
->set(_window
, otk::OBProperty::wm_state
, otk::OBProperty::wm_state
,
898 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_modal
);
900 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_shaded
);
902 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_hidden
);
905 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
);
907 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_skip_pager
);
909 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_fullscreen
);
912 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
);
915 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
);
917 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_above
);
919 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_below
);
920 property
->set(_window
, otk::OBProperty::net_wm_state
,
921 otk::OBProperty::Atom_Atom
, netstate
, num
);
925 void OBClient::shade(bool shade
)
927 if (shade
== _shaded
) return; // already done
929 _wmstate
= shade
? IconicState
: NormalState
;
936 bool OBClient::focus()
938 if (!(_can_focus
|| _focus_notify
) || _focused
) return false;
941 XSetInputFocus(otk::OBDisplay::display
, _window
, RevertToNone
, CurrentTime
);
945 const otk::OBProperty
*property
= Openbox::instance
->property();
947 ce
.xclient
.type
= ClientMessage
;
948 ce
.xclient
.message_type
= property
->atom(otk::OBProperty::wm_protocols
);
949 ce
.xclient
.display
= otk::OBDisplay::display
;
950 ce
.xclient
.window
= _window
;
951 ce
.xclient
.format
= 32;
952 ce
.xclient
.data
.l
[0] = property
->atom(otk::OBProperty::wm_take_focus
);
953 ce
.xclient
.data
.l
[1] = Openbox::instance
->lastTime();
954 ce
.xclient
.data
.l
[2] = 0l;
955 ce
.xclient
.data
.l
[3] = 0l;
956 ce
.xclient
.data
.l
[4] = 0l;
957 XSendEvent(otk::OBDisplay::display
, _window
, False
, NoEventMask
, &ce
);
964 void OBClient::unfocus()
966 if (!_focused
) return;
968 assert(Openbox::instance
->focusedClient() == this);
969 Openbox::instance
->setFocusedClient(0);
973 void OBClient::focusHandler(const XFocusChangeEvent
&e
)
976 printf("FocusIn for 0x%lx\n", e
.window
);
979 OtkEventHandler::focusHandler(e
);
984 Openbox::instance
->setFocusedClient(this);
988 void OBClient::unfocusHandler(const XFocusChangeEvent
&e
)
991 printf("FocusOut for 0x%lx\n", e
.window
);
994 OtkEventHandler::unfocusHandler(e
);
999 if (Openbox::instance
->focusedClient() == this) {
1000 printf("UNFOCUSED!\n");
1001 Openbox::instance
->setFocusedClient(this);
1006 void OBClient::configureRequestHandler(const XConfigureRequestEvent
&e
)
1009 printf("ConfigureRequest for 0x%lx\n", e
.window
);
1012 OtkEventHandler::configureRequestHandler(e
);
1014 // XXX: if we are iconic (or shaded? (fvwm does that)) ignore the event
1016 if (e
.value_mask
& CWBorderWidth
)
1017 _border_width
= e
.border_width
;
1019 // resize, then move, as specified in the EWMH section 7.7
1020 if (e
.value_mask
& (CWWidth
| CWHeight
)) {
1021 int w
= (e
.value_mask
& CWWidth
) ? e
.width
: _area
.width();
1022 int h
= (e
.value_mask
& CWHeight
) ? e
.height
: _area
.height();
1026 case NorthEastGravity
:
1030 case SouthWestGravity
:
1032 corner
= BottomLeft
;
1034 case SouthEastGravity
:
1035 corner
= BottomRight
;
1037 default: // NorthWest, Static, etc
1041 resize(corner
, w
, h
);
1044 if (e
.value_mask
& (CWX
| CWY
)) {
1045 int x
= (e
.value_mask
& CWX
) ? e
.x
: _area
.x();
1046 int y
= (e
.value_mask
& CWY
) ? e
.y
: _area
.y();
1050 if (e
.value_mask
& CWStackMode
) {
1054 // XXX: lower the window
1060 // XXX: raise the window
1067 void OBClient::unmapHandler(const XUnmapEvent
&e
)
1070 printf("UnmapNotify for 0x%lx\n", e
.window
);
1073 if (ignore_unmaps
) {
1078 OtkEventHandler::unmapHandler(e
);
1080 // this deletes us etc
1081 Openbox::instance
->screen(_screen
)->unmanageWindow(this);
1085 void OBClient::destroyHandler(const XDestroyWindowEvent
&e
)
1088 printf("DestroyNotify for 0x%lx\n", e
.window
);
1091 OtkEventHandler::destroyHandler(e
);
1093 // this deletes us etc
1094 Openbox::instance
->screen(_screen
)->unmanageWindow(this);
1098 void OBClient::reparentHandler(const XReparentEvent
&e
)
1100 // this is when the client is first taken captive in the frame
1101 if (e
.parent
== frame
->plate()) return;
1104 printf("ReparentNotify for 0x%lx\n", e
.window
);
1107 OtkEventHandler::reparentHandler(e
);
1110 This event is quite rare and is usually handled in unmapHandler.
1111 However, if the window is unmapped when the reparent event occurs,
1112 the window manager never sees it because an unmap event is not sent
1113 to an already unmapped window.
1116 // this deletes us etc
1117 Openbox::instance
->screen(_screen
)->unmanageWindow(this);