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
)) {
269 _wmstate
= IconicState
;
270 } else if (state
[i
] ==
271 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
))
272 _skip_taskbar
= true;
274 property
->atom(otk::OBProperty::net_wm_state_skip_pager
))
277 property
->atom(otk::OBProperty::net_wm_state_fullscreen
))
280 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
))
283 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
))
286 property
->atom(otk::OBProperty::net_wm_state_above
))
289 property
->atom(otk::OBProperty::net_wm_state_below
))
298 void OBClient::getShaped()
302 if (otk::OBDisplay::shape()) {
307 XShapeSelectInput(otk::OBDisplay::display
, _window
, ShapeNotifyMask
);
309 XShapeQueryExtents(otk::OBDisplay::display
, _window
, &s
, &foo
,
310 &foo
, &ufoo
, &ufoo
, &foo
, &foo
, &foo
, &ufoo
, &ufoo
);
317 void OBClient::calcLayer() {
318 if (_iconic
) _layer
= OBScreen::Layer_Icon
;
319 else if (_fullscreen
) _layer
= OBScreen::Layer_Fullscreen
;
320 else if (_type
== Type_Desktop
) _layer
= OBScreen::Layer_Desktop
;
321 else if (_type
== Type_Dock
) {
322 if (!_below
) _layer
= OBScreen::Layer_Top
;
323 else _layer
= OBScreen::Layer_Normal
;
325 else if (_above
) _layer
= OBScreen::Layer_Above
;
326 else if (_below
) _layer
= OBScreen::Layer_Below
;
327 else _layer
= OBScreen::Layer_Normal
;
331 void OBClient::updateProtocols()
333 const otk::OBProperty
*property
= Openbox::instance
->property();
338 _focus_notify
= false;
339 _decorations
&= ~Decor_Close
;
340 _functions
&= ~Func_Close
;
342 if (XGetWMProtocols(otk::OBDisplay::display
, _window
, &proto
, &num_return
)) {
343 for (int i
= 0; i
< num_return
; ++i
) {
344 if (proto
[i
] == property
->atom(otk::OBProperty::wm_delete_window
)) {
345 _decorations
|= Decor_Close
;
346 _functions
|= Func_Close
;
348 frame
->adjustSize(); // update the decorations
349 } else if (proto
[i
] == property
->atom(otk::OBProperty::wm_take_focus
))
350 // if this protocol is requested, then the window will be notified
351 // by the window manager whenever it receives focus
352 _focus_notify
= true;
359 void OBClient::updateNormalHints()
363 int oldgravity
= _gravity
;
366 _gravity
= NorthWestGravity
;
367 _size_inc
.setPoint(1, 1);
368 _base_size
.setPoint(0, 0);
369 _min_size
.setPoint(0, 0);
370 _max_size
.setPoint(INT_MAX
, INT_MAX
);
372 // XXX: might want to cancel any interactive resizing of the window at this
375 // get the hints from the window
376 if (XGetWMNormalHints(otk::OBDisplay::display
, _window
, &size
, &ret
)) {
377 _positioned
= (size
.flags
& (PPosition
|USPosition
));
379 if (size
.flags
& PWinGravity
)
380 _gravity
= size
.win_gravity
;
382 if (size
.flags
& PMinSize
)
383 _min_size
.setPoint(size
.min_width
, size
.min_height
);
385 if (size
.flags
& PMaxSize
)
386 _max_size
.setPoint(size
.max_width
, size
.max_height
);
388 if (size
.flags
& PBaseSize
)
389 _base_size
.setPoint(size
.base_width
, size
.base_height
);
391 if (size
.flags
& PResizeInc
)
392 _size_inc
.setPoint(size
.width_inc
, size
.height_inc
);
395 // if the client has a frame, i.e. has already been mapped and is
396 // changing its gravity
397 if (frame
&& _gravity
!= oldgravity
) {
398 // move our idea of the client's position based on its new gravity
400 frame
->frameGravity(x
, y
);
406 void OBClient::updateWMHints()
410 // assume a window takes input if it doesnt specify
414 if ((hints
= XGetWMHints(otk::OBDisplay::display
, _window
)) != NULL
) {
415 if (hints
->flags
& InputHint
)
416 _can_focus
= hints
->input
;
418 if (hints
->flags
& XUrgencyHint
)
421 if (hints
->flags
& WindowGroupHint
) {
422 if (hints
->window_group
!= _group
) {
423 // XXX: remove from the old group if there was one
424 _group
= hints
->window_group
;
425 // XXX: do stuff with the group
435 void OBClient::updateTitle()
437 const otk::OBProperty
*property
= Openbox::instance
->property();
442 if (! property
->get(_window
, otk::OBProperty::net_wm_name
,
443 otk::OBProperty::utf8
, &_title
)) {
445 property
->get(_window
, otk::OBProperty::wm_name
,
446 otk::OBProperty::ascii
, &_title
);
450 _title
= _("Unnamed Window");
453 frame
->setTitle(_title
);
457 void OBClient::updateIconTitle()
459 const otk::OBProperty
*property
= Openbox::instance
->property();
464 if (! property
->get(_window
, otk::OBProperty::net_wm_icon_name
,
465 otk::OBProperty::utf8
, &_icon_title
)) {
467 property
->get(_window
, otk::OBProperty::wm_icon_name
,
468 otk::OBProperty::ascii
, &_icon_title
);
472 _icon_title
= _("Unnamed Window");
476 void OBClient::updateClass()
478 const otk::OBProperty
*property
= Openbox::instance
->property();
481 _app_name
= _app_class
= "";
483 otk::OBProperty::StringVect v
;
484 unsigned long num
= 2;
486 if (! property
->get(_window
, otk::OBProperty::wm_class
,
487 otk::OBProperty::ascii
, &num
, &v
))
490 if (num
> 0) _app_name
= v
[0];
491 if (num
> 1) _app_class
= v
[1];
495 void OBClient::updateStrut()
497 unsigned long num
= 4;
499 if (!Openbox::instance
->property()->get(_window
,
500 otk::OBProperty::net_wm_strut
,
501 otk::OBProperty::Atom_Cardinal
,
506 _strut
.left
= data
[0];
507 _strut
.right
= data
[1];
508 _strut
.top
= data
[2];
509 _strut
.bottom
= data
[3];
511 Openbox::instance
->screen(_screen
)->updateStrut();
518 void OBClient::propertyHandler(const XPropertyEvent
&e
)
520 otk::OtkEventHandler::propertyHandler(e
);
522 const otk::OBProperty
*property
= Openbox::instance
->property();
524 // compress changes to a single property into a single change
526 while (XCheckTypedEvent(otk::OBDisplay::display
, e
.type
, &ce
)) {
527 // XXX: it would be nice to compress ALL changes to a property, not just
528 // changes in a row without other props between.
529 if (ce
.xproperty
.atom
!= e
.atom
) {
530 XPutBackEvent(otk::OBDisplay::display
, &ce
);
535 if (e
.atom
== XA_WM_NORMAL_HINTS
)
537 else if (e
.atom
== XA_WM_HINTS
)
539 else if (e
.atom
== property
->atom(otk::OBProperty::net_wm_name
) ||
540 e
.atom
== property
->atom(otk::OBProperty::wm_name
))
542 else if (e
.atom
== property
->atom(otk::OBProperty::net_wm_icon_name
) ||
543 e
.atom
== property
->atom(otk::OBProperty::wm_icon_name
))
545 else if (e
.atom
== property
->atom(otk::OBProperty::wm_class
))
547 else if (e
.atom
== property
->atom(otk::OBProperty::wm_protocols
))
549 // XXX: transient for hint
550 else if (e
.atom
== property
->atom(otk::OBProperty::net_wm_strut
))
556 void OBClient::setWMState(long state
)
558 if (state
== _wmstate
) return; // no change
562 // XXX: cause it to iconify
565 // XXX: cause it to uniconify
572 void OBClient::setDesktop(long target
)
574 printf("Setting desktop %ld\n", target
);
575 assert(target
>= 0 || target
== (signed)0xffffffff);
576 //assert(target == 0xffffffff || target < MAX);
578 // XXX: move the window to the new desktop (and set root property)
583 void OBClient::setState(StateAction action
, long data1
, long data2
)
585 const otk::OBProperty
*property
= Openbox::instance
->property();
586 bool restack
= false, shadestate
= _shaded
;
588 if (!(action
== State_Add
|| action
== State_Remove
||
589 action
== State_Toggle
))
590 return; // an invalid action was passed to the client message, ignore it
592 for (int i
= 0; i
< 2; ++i
) {
593 Atom state
= i
== 0 ? data1
: data2
;
595 if (! state
) continue;
597 // if toggling, then pick whether we're adding or removing
598 if (action
== State_Toggle
) {
599 if (state
== property
->atom(otk::OBProperty::net_wm_state_modal
))
600 action
= _modal
? State_Remove
: State_Add
;
602 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
))
603 action
= _max_vert
? State_Remove
: State_Add
;
605 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
))
606 action
= _max_horz
? State_Remove
: State_Add
;
607 else if (state
== property
->atom(otk::OBProperty::net_wm_state_shaded
))
608 action
= _shaded
? State_Remove
: State_Add
;
610 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
))
611 action
= _skip_taskbar
? State_Remove
: State_Add
;
613 property
->atom(otk::OBProperty::net_wm_state_skip_pager
))
614 action
= _skip_pager
? State_Remove
: State_Add
;
616 property
->atom(otk::OBProperty::net_wm_state_fullscreen
))
617 action
= _fullscreen
? State_Remove
: State_Add
;
618 else if (state
== property
->atom(otk::OBProperty::net_wm_state_above
))
619 action
= _above
? State_Remove
: State_Add
;
620 else if (state
== property
->atom(otk::OBProperty::net_wm_state_below
))
621 action
= _below
? State_Remove
: State_Add
;
624 if (action
== State_Add
) {
625 if (state
== property
->atom(otk::OBProperty::net_wm_state_modal
)) {
626 if (_modal
) continue;
628 // XXX: give it focus if another window has focus that shouldnt now
630 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
)){
631 if (_max_vert
) continue;
633 // XXX: resize the window etc
635 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
)){
636 if (_max_horz
) continue;
638 // XXX: resize the window etc
640 property
->atom(otk::OBProperty::net_wm_state_shaded
)) {
641 if (_shaded
) continue;
642 // shade when we're all thru here
645 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
)) {
646 _skip_taskbar
= true;
648 property
->atom(otk::OBProperty::net_wm_state_skip_pager
)) {
651 property
->atom(otk::OBProperty::net_wm_state_fullscreen
)) {
652 if (_fullscreen
) continue;
656 property
->atom(otk::OBProperty::net_wm_state_above
)) {
657 if (_above
) continue;
661 property
->atom(otk::OBProperty::net_wm_state_below
)) {
662 if (_below
) continue;
667 } else { // action == State_Remove
668 if (state
== property
->atom(otk::OBProperty::net_wm_state_modal
)) {
669 if (!_modal
) continue;
672 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
)){
673 if (!_max_vert
) continue;
675 // XXX: resize the window etc
677 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
)){
678 if (!_max_horz
) continue;
680 // XXX: resize the window etc
682 property
->atom(otk::OBProperty::net_wm_state_shaded
)) {
683 if (!_shaded
) continue;
684 // unshade when we're all thru here
687 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
)) {
688 _skip_taskbar
= false;
690 property
->atom(otk::OBProperty::net_wm_state_skip_pager
)) {
693 property
->atom(otk::OBProperty::net_wm_state_fullscreen
)) {
694 if (!_fullscreen
) continue;
698 property
->atom(otk::OBProperty::net_wm_state_above
)) {
699 if (!_above
) continue;
703 property
->atom(otk::OBProperty::net_wm_state_below
)) {
704 if (!_below
) continue;
710 if (shadestate
!= _shaded
)
714 Openbox::instance
->screen(_screen
)->restack(true, this); // raise
719 void OBClient::toggleClientBorder(bool addborder
)
721 // adjust our idea of where the client is, based on its border. When the
722 // border is removed, the client should now be considered to be in a
723 // different position.
724 // when re-adding the border to the client, the same operation needs to be
726 int x
= _area
.x(), y
= _area
.y();
728 case NorthWestGravity
:
730 case SouthWestGravity
:
732 case NorthEastGravity
:
734 case SouthEastGravity
:
735 if (addborder
) x
-= _border_width
* 2;
736 else x
+= _border_width
* 2;
740 case NorthWestGravity
:
742 case NorthEastGravity
:
744 case SouthWestGravity
:
746 case SouthEastGravity
:
747 if (addborder
) y
-= _border_width
* 2;
748 else y
+= _border_width
* 2;
751 // no change for StaticGravity etc.
757 XSetWindowBorderWidth(otk::OBDisplay::display
, _window
, _border_width
);
759 // move the client so it is back it the right spot _with_ its border!
760 XMoveWindow(otk::OBDisplay::display
, _window
, x
, y
);
762 XSetWindowBorderWidth(otk::OBDisplay::display
, _window
, 0);
766 void OBClient::clientMessageHandler(const XClientMessageEvent
&e
)
768 otk::OtkEventHandler::clientMessageHandler(e
);
770 if (e
.format
!= 32) return;
772 const otk::OBProperty
*property
= Openbox::instance
->property();
774 if (e
.message_type
== property
->atom(otk::OBProperty::wm_change_state
)) {
775 // compress changes into a single change
776 bool compress
= false;
778 while (XCheckTypedEvent(otk::OBDisplay::display
, e
.type
, &ce
)) {
779 // XXX: it would be nice to compress ALL messages of a type, not just
780 // messages in a row without other message types between.
781 if (ce
.xclient
.message_type
!= e
.message_type
) {
782 XPutBackEvent(otk::OBDisplay::display
, &ce
);
788 setWMState(ce
.xclient
.data
.l
[0]); // use the found event
790 setWMState(e
.data
.l
[0]); // use the original event
791 } else if (e
.message_type
==
792 property
->atom(otk::OBProperty::net_wm_desktop
)) {
793 // compress changes into a single change
794 bool compress
= false;
796 while (XCheckTypedEvent(otk::OBDisplay::display
, e
.type
, &ce
)) {
797 // XXX: it would be nice to compress ALL messages of a type, not just
798 // messages in a row without other message types between.
799 if (ce
.xclient
.message_type
!= e
.message_type
) {
800 XPutBackEvent(otk::OBDisplay::display
, &ce
);
806 setDesktop(e
.data
.l
[0]); // use the found event
808 setDesktop(e
.data
.l
[0]); // use the original event
809 } else if (e
.message_type
== property
->atom(otk::OBProperty::net_wm_state
)) {
810 // can't compress these
811 setState((StateAction
)e
.data
.l
[0], e
.data
.l
[1], e
.data
.l
[2]);
812 } else if (e
.message_type
==
813 property
->atom(otk::OBProperty::net_close_window
)) {
815 } else if (e
.message_type
==
816 property
->atom(otk::OBProperty::net_active_window
)) {
818 Openbox::instance
->screen(_screen
)->restack(true, this); // raise
825 void OBClient::shapeHandler(const XShapeEvent
&e
)
827 otk::OtkEventHandler::shapeHandler(e
);
830 frame
->adjustShape();
835 void OBClient::resize(Corner anchor
, int w
, int h
, int x
, int y
)
840 // for interactive resizing. have to move half an increment in each
842 w
+= _size_inc
.x() / 2;
843 h
+= _size_inc
.y() / 2;
845 // is the window resizable? if it is not, then don't check its sizes, the
846 // client can do what it wants and the user can't change it anyhow
847 if (_min_size
.x() <= _max_size
.x() && _min_size
.y() <= _max_size
.y()) {
848 // smaller than min size or bigger than max size?
849 if (w
< _min_size
.x()) w
= _min_size
.x();
850 else if (w
> _max_size
.x()) w
= _max_size
.x();
851 if (h
< _min_size
.y()) h
= _min_size
.y();
852 else if (h
> _max_size
.y()) h
= _max_size
.y();
855 // keep to the increments
859 // store the logical size
860 _logical_size
.setPoint(w
, h
);
868 if (x
== INT_MIN
|| y
== INT_MIN
) {
875 x
-= w
- _area
.width();
878 y
-= h
- _area
.height();
881 x
-= w
- _area
.width();
882 y
-= h
- _area
.height();
889 XResizeWindow(otk::OBDisplay::display
, _window
, w
, h
);
891 // resize the frame to match the request
897 void OBClient::move(int x
, int y
)
901 // move the frame to be in the requested position
902 frame
->adjustPosition();
906 void OBClient::close()
909 const otk::OBProperty
*property
= Openbox::instance
->property();
911 if (!(_functions
& Func_Close
)) return;
913 // XXX: itd be cool to do timeouts and shit here for killing the client's
915 // like... if the window is around after 5 seconds, then the close button
916 // turns a nice red, and if this function is called again, the client is
917 // explicitly killed.
919 ce
.xclient
.type
= ClientMessage
;
920 ce
.xclient
.message_type
= property
->atom(otk::OBProperty::wm_protocols
);
921 ce
.xclient
.display
= otk::OBDisplay::display
;
922 ce
.xclient
.window
= _window
;
923 ce
.xclient
.format
= 32;
924 ce
.xclient
.data
.l
[0] = property
->atom(otk::OBProperty::wm_delete_window
);
925 ce
.xclient
.data
.l
[1] = CurrentTime
;
926 ce
.xclient
.data
.l
[2] = 0l;
927 ce
.xclient
.data
.l
[3] = 0l;
928 ce
.xclient
.data
.l
[4] = 0l;
929 XSendEvent(otk::OBDisplay::display
, _window
, False
, NoEventMask
, &ce
);
933 void OBClient::changeState()
935 const otk::OBProperty
*property
= Openbox::instance
->property();
937 unsigned long state
[2];
940 property
->set(_window
, otk::OBProperty::wm_state
, otk::OBProperty::wm_state
,
946 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_modal
);
948 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_shaded
);
950 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_hidden
);
953 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
);
955 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_skip_pager
);
957 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_fullscreen
);
960 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
);
963 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
);
965 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_above
);
967 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_below
);
968 property
->set(_window
, otk::OBProperty::net_wm_state
,
969 otk::OBProperty::Atom_Atom
, netstate
, num
);
974 void OBClient::setStackLayer(int l
)
977 _above
= _below
= false; // normal
980 _below
= false; // above
983 _below
= true; // below
987 Openbox::instance
->screen(_screen
)->restack(true, this); // raise
991 void OBClient::shade(bool shade
)
993 if (shade
== _shaded
) return; // already done
995 _wmstate
= shade
? IconicState
: NormalState
;
1002 bool OBClient::focus()
1004 if (!(_can_focus
|| _focus_notify
) || _focused
) return false;
1007 XSetInputFocus(otk::OBDisplay::display
, _window
, RevertToNone
, CurrentTime
);
1009 if (_focus_notify
) {
1011 const otk::OBProperty
*property
= Openbox::instance
->property();
1013 ce
.xclient
.type
= ClientMessage
;
1014 ce
.xclient
.message_type
= property
->atom(otk::OBProperty::wm_protocols
);
1015 ce
.xclient
.display
= otk::OBDisplay::display
;
1016 ce
.xclient
.window
= _window
;
1017 ce
.xclient
.format
= 32;
1018 ce
.xclient
.data
.l
[0] = property
->atom(otk::OBProperty::wm_take_focus
);
1019 ce
.xclient
.data
.l
[1] = Openbox::instance
->lastTime();
1020 ce
.xclient
.data
.l
[2] = 0l;
1021 ce
.xclient
.data
.l
[3] = 0l;
1022 ce
.xclient
.data
.l
[4] = 0l;
1023 XSendEvent(otk::OBDisplay::display
, _window
, False
, NoEventMask
, &ce
);
1030 void OBClient::unfocus()
1032 if (!_focused
) return;
1034 assert(Openbox::instance
->focusedClient() == this);
1035 Openbox::instance
->setFocusedClient(0);
1039 void OBClient::focusHandler(const XFocusChangeEvent
&e
)
1042 printf("FocusIn for 0x%lx\n", e
.window
);
1045 OtkEventHandler::focusHandler(e
);
1050 Openbox::instance
->setFocusedClient(this);
1054 void OBClient::unfocusHandler(const XFocusChangeEvent
&e
)
1057 printf("FocusOut for 0x%lx\n", e
.window
);
1060 OtkEventHandler::unfocusHandler(e
);
1065 if (Openbox::instance
->focusedClient() == this) {
1066 printf("UNFOCUSED!\n");
1067 Openbox::instance
->setFocusedClient(this);
1072 void OBClient::configureRequestHandler(const XConfigureRequestEvent
&e
)
1075 printf("ConfigureRequest for 0x%lx\n", e
.window
);
1078 OtkEventHandler::configureRequestHandler(e
);
1080 // XXX: if we are iconic (or shaded? (fvwm does that)) ignore the event
1082 if (e
.value_mask
& CWBorderWidth
)
1083 _border_width
= e
.border_width
;
1085 // resize, then move, as specified in the EWMH section 7.7
1086 if (e
.value_mask
& (CWWidth
| CWHeight
)) {
1087 int w
= (e
.value_mask
& CWWidth
) ? e
.width
: _area
.width();
1088 int h
= (e
.value_mask
& CWHeight
) ? e
.height
: _area
.height();
1092 case NorthEastGravity
:
1096 case SouthWestGravity
:
1098 corner
= BottomLeft
;
1100 case SouthEastGravity
:
1101 corner
= BottomRight
;
1103 default: // NorthWest, Static, etc
1107 // if moving AND resizing ...
1108 if (e
.value_mask
& (CWX
| CWY
)) {
1109 int x
= (e
.value_mask
& CWX
) ? e
.x
: _area
.x();
1110 int y
= (e
.value_mask
& CWY
) ? e
.y
: _area
.y();
1111 resize(corner
, w
, h
, x
, y
);
1112 } else // if JUST resizing...
1113 resize(corner
, w
, h
);
1114 } else if (e
.value_mask
& (CWX
| CWY
)) { // if JUST moving...
1115 int x
= (e
.value_mask
& CWX
) ? e
.x
: _area
.x();
1116 int y
= (e
.value_mask
& CWY
) ? e
.y
: _area
.y();
1120 if (e
.value_mask
& CWStackMode
) {
1124 Openbox::instance
->screen(_screen
)->restack(false, this); // lower
1130 Openbox::instance
->screen(_screen
)->restack(true, this); // raise
1137 void OBClient::unmapHandler(const XUnmapEvent
&e
)
1140 printf("UnmapNotify for 0x%lx\n", e
.window
);
1143 if (ignore_unmaps
) {
1148 OtkEventHandler::unmapHandler(e
);
1150 // this deletes us etc
1151 Openbox::instance
->screen(_screen
)->unmanageWindow(this);
1155 void OBClient::destroyHandler(const XDestroyWindowEvent
&e
)
1158 printf("DestroyNotify for 0x%lx\n", e
.window
);
1161 OtkEventHandler::destroyHandler(e
);
1163 // this deletes us etc
1164 Openbox::instance
->screen(_screen
)->unmanageWindow(this);
1168 void OBClient::reparentHandler(const XReparentEvent
&e
)
1170 // this is when the client is first taken captive in the frame
1171 if (e
.parent
== frame
->plate()) return;
1174 printf("ReparentNotify for 0x%lx\n", e
.window
);
1177 OtkEventHandler::reparentHandler(e
);
1180 This event is quite rare and is usually handled in unmapHandler.
1181 However, if the window is unmapped when the reparent event occurs,
1182 the window manager never sees it because an unmap event is not sent
1183 to an already unmapped window.
1186 // this deletes us etc
1187 Openbox::instance
->screen(_screen
)->unmanageWindow(this);
1191 void OBClient::mapRequestHandler(const XMapRequestEvent
&e
)
1193 printf("\nMAP REQUEST\n\n");
1195 otk::OtkEventHandler::mapRequestHandler(e
);
1199 // XXX: uniconify the window