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
= _role
= "";
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
)) {
488 if (num
> 0) _app_name
= v
[0];
489 if (num
> 1) _app_class
= v
[1];
494 if (property
->get(_window
, otk::OBProperty::wm_window_role
,
495 otk::OBProperty::ascii
, &num
, &v
)) {
496 if (num
> 0) _role
= v
[0];
501 void OBClient::updateStrut()
503 unsigned long num
= 4;
505 if (!Openbox::instance
->property()->get(_window
,
506 otk::OBProperty::net_wm_strut
,
507 otk::OBProperty::Atom_Cardinal
,
512 _strut
.left
= data
[0];
513 _strut
.right
= data
[1];
514 _strut
.top
= data
[2];
515 _strut
.bottom
= data
[3];
517 Openbox::instance
->screen(_screen
)->updateStrut();
524 void OBClient::propertyHandler(const XPropertyEvent
&e
)
526 otk::OtkEventHandler::propertyHandler(e
);
528 const otk::OBProperty
*property
= Openbox::instance
->property();
530 // compress changes to a single property into a single change
532 while (XCheckTypedEvent(otk::OBDisplay::display
, e
.type
, &ce
)) {
533 // XXX: it would be nice to compress ALL changes to a property, not just
534 // changes in a row without other props between.
535 if (ce
.xproperty
.atom
!= e
.atom
) {
536 XPutBackEvent(otk::OBDisplay::display
, &ce
);
541 if (e
.atom
== XA_WM_NORMAL_HINTS
)
543 else if (e
.atom
== XA_WM_HINTS
)
545 else if (e
.atom
== property
->atom(otk::OBProperty::net_wm_name
) ||
546 e
.atom
== property
->atom(otk::OBProperty::wm_name
))
548 else if (e
.atom
== property
->atom(otk::OBProperty::net_wm_icon_name
) ||
549 e
.atom
== property
->atom(otk::OBProperty::wm_icon_name
))
551 else if (e
.atom
== property
->atom(otk::OBProperty::wm_class
))
553 else if (e
.atom
== property
->atom(otk::OBProperty::wm_protocols
))
555 // XXX: transient for hint
556 else if (e
.atom
== property
->atom(otk::OBProperty::net_wm_strut
))
562 void OBClient::setWMState(long state
)
564 if (state
== _wmstate
) return; // no change
568 // XXX: cause it to iconify
571 // XXX: cause it to uniconify
578 void OBClient::setDesktop(long target
)
580 printf("Setting desktop %ld\n", target
);
581 assert(target
>= 0 || target
== (signed)0xffffffff);
582 //assert(target == 0xffffffff || target < MAX);
584 // XXX: move the window to the new desktop (and set root property)
589 void OBClient::setState(StateAction action
, long data1
, long data2
)
591 const otk::OBProperty
*property
= Openbox::instance
->property();
592 bool restack
= false, shadestate
= _shaded
;
594 if (!(action
== State_Add
|| action
== State_Remove
||
595 action
== State_Toggle
))
596 return; // an invalid action was passed to the client message, ignore it
598 for (int i
= 0; i
< 2; ++i
) {
599 Atom state
= i
== 0 ? data1
: data2
;
601 if (! state
) continue;
603 // if toggling, then pick whether we're adding or removing
604 if (action
== State_Toggle
) {
605 if (state
== property
->atom(otk::OBProperty::net_wm_state_modal
))
606 action
= _modal
? State_Remove
: State_Add
;
608 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
))
609 action
= _max_vert
? State_Remove
: State_Add
;
611 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
))
612 action
= _max_horz
? State_Remove
: State_Add
;
613 else if (state
== property
->atom(otk::OBProperty::net_wm_state_shaded
))
614 action
= _shaded
? State_Remove
: State_Add
;
616 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
))
617 action
= _skip_taskbar
? State_Remove
: State_Add
;
619 property
->atom(otk::OBProperty::net_wm_state_skip_pager
))
620 action
= _skip_pager
? State_Remove
: State_Add
;
622 property
->atom(otk::OBProperty::net_wm_state_fullscreen
))
623 action
= _fullscreen
? State_Remove
: State_Add
;
624 else if (state
== property
->atom(otk::OBProperty::net_wm_state_above
))
625 action
= _above
? State_Remove
: State_Add
;
626 else if (state
== property
->atom(otk::OBProperty::net_wm_state_below
))
627 action
= _below
? State_Remove
: State_Add
;
630 if (action
== State_Add
) {
631 if (state
== property
->atom(otk::OBProperty::net_wm_state_modal
)) {
632 if (_modal
) continue;
634 // XXX: give it focus if another window has focus that shouldnt now
636 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
)){
637 if (_max_vert
) continue;
639 // XXX: resize the window etc
641 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
)){
642 if (_max_horz
) continue;
644 // XXX: resize the window etc
646 property
->atom(otk::OBProperty::net_wm_state_shaded
)) {
647 if (_shaded
) continue;
648 // shade when we're all thru here
651 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
)) {
652 _skip_taskbar
= true;
654 property
->atom(otk::OBProperty::net_wm_state_skip_pager
)) {
657 property
->atom(otk::OBProperty::net_wm_state_fullscreen
)) {
658 if (_fullscreen
) continue;
662 property
->atom(otk::OBProperty::net_wm_state_above
)) {
663 if (_above
) continue;
667 property
->atom(otk::OBProperty::net_wm_state_below
)) {
668 if (_below
) continue;
673 } else { // action == State_Remove
674 if (state
== property
->atom(otk::OBProperty::net_wm_state_modal
)) {
675 if (!_modal
) continue;
678 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
)){
679 if (!_max_vert
) continue;
681 // XXX: resize the window etc
683 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
)){
684 if (!_max_horz
) continue;
686 // XXX: resize the window etc
688 property
->atom(otk::OBProperty::net_wm_state_shaded
)) {
689 if (!_shaded
) continue;
690 // unshade when we're all thru here
693 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
)) {
694 _skip_taskbar
= false;
696 property
->atom(otk::OBProperty::net_wm_state_skip_pager
)) {
699 property
->atom(otk::OBProperty::net_wm_state_fullscreen
)) {
700 if (!_fullscreen
) continue;
704 property
->atom(otk::OBProperty::net_wm_state_above
)) {
705 if (!_above
) continue;
709 property
->atom(otk::OBProperty::net_wm_state_below
)) {
710 if (!_below
) continue;
716 if (shadestate
!= _shaded
)
720 Openbox::instance
->screen(_screen
)->restack(true, this); // raise
725 void OBClient::toggleClientBorder(bool addborder
)
727 // adjust our idea of where the client is, based on its border. When the
728 // border is removed, the client should now be considered to be in a
729 // different position.
730 // when re-adding the border to the client, the same operation needs to be
732 int x
= _area
.x(), y
= _area
.y();
734 case NorthWestGravity
:
736 case SouthWestGravity
:
738 case NorthEastGravity
:
740 case SouthEastGravity
:
741 if (addborder
) x
-= _border_width
* 2;
742 else x
+= _border_width
* 2;
746 case NorthWestGravity
:
748 case NorthEastGravity
:
750 case SouthWestGravity
:
752 case SouthEastGravity
:
753 if (addborder
) y
-= _border_width
* 2;
754 else y
+= _border_width
* 2;
757 // no change for StaticGravity etc.
763 XSetWindowBorderWidth(otk::OBDisplay::display
, _window
, _border_width
);
765 // move the client so it is back it the right spot _with_ its border!
766 XMoveWindow(otk::OBDisplay::display
, _window
, x
, y
);
768 XSetWindowBorderWidth(otk::OBDisplay::display
, _window
, 0);
772 void OBClient::clientMessageHandler(const XClientMessageEvent
&e
)
774 otk::OtkEventHandler::clientMessageHandler(e
);
776 if (e
.format
!= 32) return;
778 const otk::OBProperty
*property
= Openbox::instance
->property();
780 if (e
.message_type
== property
->atom(otk::OBProperty::wm_change_state
)) {
781 // compress changes into a single change
782 bool compress
= false;
784 while (XCheckTypedEvent(otk::OBDisplay::display
, e
.type
, &ce
)) {
785 // XXX: it would be nice to compress ALL messages of a type, not just
786 // messages in a row without other message types between.
787 if (ce
.xclient
.message_type
!= e
.message_type
) {
788 XPutBackEvent(otk::OBDisplay::display
, &ce
);
794 setWMState(ce
.xclient
.data
.l
[0]); // use the found event
796 setWMState(e
.data
.l
[0]); // use the original event
797 } else if (e
.message_type
==
798 property
->atom(otk::OBProperty::net_wm_desktop
)) {
799 // compress changes into a single change
800 bool compress
= false;
802 while (XCheckTypedEvent(otk::OBDisplay::display
, e
.type
, &ce
)) {
803 // XXX: it would be nice to compress ALL messages of a type, not just
804 // messages in a row without other message types between.
805 if (ce
.xclient
.message_type
!= e
.message_type
) {
806 XPutBackEvent(otk::OBDisplay::display
, &ce
);
812 setDesktop(e
.data
.l
[0]); // use the found event
814 setDesktop(e
.data
.l
[0]); // use the original event
815 } else if (e
.message_type
== property
->atom(otk::OBProperty::net_wm_state
)) {
816 // can't compress these
817 setState((StateAction
)e
.data
.l
[0], e
.data
.l
[1], e
.data
.l
[2]);
818 } else if (e
.message_type
==
819 property
->atom(otk::OBProperty::net_close_window
)) {
821 } else if (e
.message_type
==
822 property
->atom(otk::OBProperty::net_active_window
)) {
824 Openbox::instance
->screen(_screen
)->restack(true, this); // raise
831 void OBClient::shapeHandler(const XShapeEvent
&e
)
833 otk::OtkEventHandler::shapeHandler(e
);
836 frame
->adjustShape();
841 void OBClient::resize(Corner anchor
, int w
, int h
, int x
, int y
)
846 // for interactive resizing. have to move half an increment in each
848 w
+= _size_inc
.x() / 2;
849 h
+= _size_inc
.y() / 2;
851 // is the window resizable? if it is not, then don't check its sizes, the
852 // client can do what it wants and the user can't change it anyhow
853 if (_min_size
.x() <= _max_size
.x() && _min_size
.y() <= _max_size
.y()) {
854 // smaller than min size or bigger than max size?
855 if (w
< _min_size
.x()) w
= _min_size
.x();
856 else if (w
> _max_size
.x()) w
= _max_size
.x();
857 if (h
< _min_size
.y()) h
= _min_size
.y();
858 else if (h
> _max_size
.y()) h
= _max_size
.y();
861 // keep to the increments
865 // store the logical size
866 _logical_size
.setPoint(w
, h
);
874 if (x
== INT_MIN
|| y
== INT_MIN
) {
881 x
-= w
- _area
.width();
884 y
-= h
- _area
.height();
887 x
-= w
- _area
.width();
888 y
-= h
- _area
.height();
895 XResizeWindow(otk::OBDisplay::display
, _window
, w
, h
);
897 // resize the frame to match the request
903 void OBClient::move(int x
, int y
)
907 // move the frame to be in the requested position
908 frame
->adjustPosition();
912 void OBClient::close()
915 const otk::OBProperty
*property
= Openbox::instance
->property();
917 if (!(_functions
& Func_Close
)) return;
919 // XXX: itd be cool to do timeouts and shit here for killing the client's
921 // like... if the window is around after 5 seconds, then the close button
922 // turns a nice red, and if this function is called again, the client is
923 // explicitly killed.
925 ce
.xclient
.type
= ClientMessage
;
926 ce
.xclient
.message_type
= property
->atom(otk::OBProperty::wm_protocols
);
927 ce
.xclient
.display
= otk::OBDisplay::display
;
928 ce
.xclient
.window
= _window
;
929 ce
.xclient
.format
= 32;
930 ce
.xclient
.data
.l
[0] = property
->atom(otk::OBProperty::wm_delete_window
);
931 ce
.xclient
.data
.l
[1] = CurrentTime
;
932 ce
.xclient
.data
.l
[2] = 0l;
933 ce
.xclient
.data
.l
[3] = 0l;
934 ce
.xclient
.data
.l
[4] = 0l;
935 XSendEvent(otk::OBDisplay::display
, _window
, False
, NoEventMask
, &ce
);
939 void OBClient::changeState()
941 const otk::OBProperty
*property
= Openbox::instance
->property();
943 unsigned long state
[2];
946 property
->set(_window
, otk::OBProperty::wm_state
, otk::OBProperty::wm_state
,
952 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_modal
);
954 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_shaded
);
956 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_hidden
);
959 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
);
961 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_skip_pager
);
963 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_fullscreen
);
966 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
);
969 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
);
971 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_above
);
973 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_below
);
974 property
->set(_window
, otk::OBProperty::net_wm_state
,
975 otk::OBProperty::Atom_Atom
, netstate
, num
);
980 void OBClient::setStackLayer(int l
)
983 _above
= _below
= false; // normal
986 _below
= false; // above
989 _below
= true; // below
993 Openbox::instance
->screen(_screen
)->restack(true, this); // raise
997 void OBClient::shade(bool shade
)
999 if (shade
== _shaded
) return; // already done
1001 _wmstate
= shade
? IconicState
: NormalState
;
1004 frame
->adjustSize();
1008 bool OBClient::focus()
1010 if (!(_can_focus
|| _focus_notify
) || _focused
) return false;
1013 XSetInputFocus(otk::OBDisplay::display
, _window
, RevertToNone
, CurrentTime
);
1015 if (_focus_notify
) {
1017 const otk::OBProperty
*property
= Openbox::instance
->property();
1019 ce
.xclient
.type
= ClientMessage
;
1020 ce
.xclient
.message_type
= property
->atom(otk::OBProperty::wm_protocols
);
1021 ce
.xclient
.display
= otk::OBDisplay::display
;
1022 ce
.xclient
.window
= _window
;
1023 ce
.xclient
.format
= 32;
1024 ce
.xclient
.data
.l
[0] = property
->atom(otk::OBProperty::wm_take_focus
);
1025 ce
.xclient
.data
.l
[1] = Openbox::instance
->lastTime();
1026 ce
.xclient
.data
.l
[2] = 0l;
1027 ce
.xclient
.data
.l
[3] = 0l;
1028 ce
.xclient
.data
.l
[4] = 0l;
1029 XSendEvent(otk::OBDisplay::display
, _window
, False
, NoEventMask
, &ce
);
1036 void OBClient::unfocus()
1038 if (!_focused
) return;
1040 assert(Openbox::instance
->focusedClient() == this);
1041 Openbox::instance
->setFocusedClient(0);
1045 void OBClient::focusHandler(const XFocusChangeEvent
&e
)
1048 printf("FocusIn for 0x%lx\n", e
.window
);
1051 OtkEventHandler::focusHandler(e
);
1056 Openbox::instance
->setFocusedClient(this);
1060 void OBClient::unfocusHandler(const XFocusChangeEvent
&e
)
1063 printf("FocusOut for 0x%lx\n", e
.window
);
1066 OtkEventHandler::unfocusHandler(e
);
1071 if (Openbox::instance
->focusedClient() == this) {
1072 printf("UNFOCUSED!\n");
1073 Openbox::instance
->setFocusedClient(this);
1078 void OBClient::configureRequestHandler(const XConfigureRequestEvent
&e
)
1081 printf("ConfigureRequest for 0x%lx\n", e
.window
);
1084 OtkEventHandler::configureRequestHandler(e
);
1086 // XXX: if we are iconic (or shaded? (fvwm does that)) ignore the event
1088 if (e
.value_mask
& CWBorderWidth
)
1089 _border_width
= e
.border_width
;
1091 // resize, then move, as specified in the EWMH section 7.7
1092 if (e
.value_mask
& (CWWidth
| CWHeight
)) {
1093 int w
= (e
.value_mask
& CWWidth
) ? e
.width
: _area
.width();
1094 int h
= (e
.value_mask
& CWHeight
) ? e
.height
: _area
.height();
1098 case NorthEastGravity
:
1102 case SouthWestGravity
:
1104 corner
= BottomLeft
;
1106 case SouthEastGravity
:
1107 corner
= BottomRight
;
1109 default: // NorthWest, Static, etc
1113 // if moving AND resizing ...
1114 if (e
.value_mask
& (CWX
| CWY
)) {
1115 int x
= (e
.value_mask
& CWX
) ? e
.x
: _area
.x();
1116 int y
= (e
.value_mask
& CWY
) ? e
.y
: _area
.y();
1117 resize(corner
, w
, h
, x
, y
);
1118 } else // if JUST resizing...
1119 resize(corner
, w
, h
);
1120 } else if (e
.value_mask
& (CWX
| CWY
)) { // if JUST moving...
1121 int x
= (e
.value_mask
& CWX
) ? e
.x
: _area
.x();
1122 int y
= (e
.value_mask
& CWY
) ? e
.y
: _area
.y();
1126 if (e
.value_mask
& CWStackMode
) {
1130 Openbox::instance
->screen(_screen
)->restack(false, this); // lower
1136 Openbox::instance
->screen(_screen
)->restack(true, this); // raise
1143 void OBClient::unmapHandler(const XUnmapEvent
&e
)
1146 printf("UnmapNotify for 0x%lx\n", e
.window
);
1149 if (ignore_unmaps
) {
1154 OtkEventHandler::unmapHandler(e
);
1156 // this deletes us etc
1157 Openbox::instance
->screen(_screen
)->unmanageWindow(this);
1161 void OBClient::destroyHandler(const XDestroyWindowEvent
&e
)
1164 printf("DestroyNotify for 0x%lx\n", e
.window
);
1167 OtkEventHandler::destroyHandler(e
);
1169 // this deletes us etc
1170 Openbox::instance
->screen(_screen
)->unmanageWindow(this);
1174 void OBClient::reparentHandler(const XReparentEvent
&e
)
1176 // this is when the client is first taken captive in the frame
1177 if (e
.parent
== frame
->plate()) return;
1180 printf("ReparentNotify for 0x%lx\n", e
.window
);
1183 OtkEventHandler::reparentHandler(e
);
1186 This event is quite rare and is usually handled in unmapHandler.
1187 However, if the window is unmapped when the reparent event occurs,
1188 the window manager never sees it because an unmap event is not sent
1189 to an already unmapped window.
1192 // this deletes us etc
1193 Openbox::instance
->screen(_screen
)->unmanageWindow(this);
1197 void OBClient::mapRequestHandler(const XMapRequestEvent
&e
)
1199 printf("\nMAP REQUEST\n\n");
1201 otk::OtkEventHandler::mapRequestHandler(e
);
1205 // XXX: uniconify the window