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;
44 // not a transient by default of course
52 // XXX: changeAllowedActions();
54 // set the decorations and functions
55 _decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
56 Decor_Iconify
| Decor_Maximize
;
57 _functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
60 // normal windows retain all of the possible decorations and
64 // dialogs cannot be maximized
65 _decorations
&= ~Decor_Maximize
;
66 _functions
&= ~Func_Maximize
;
72 // these windows get less functionality
73 _decorations
&= ~(Decor_Iconify
| Decor_Handle
);
74 _functions
&= ~(Func_Iconify
| Func_Resize
);
80 // none of these windows are manipulated by the window manager
86 getMwmHints(); // this fucks (in good ways) with the decors and functions
103 OBClient::~OBClient()
105 const otk::OBProperty
*property
= Openbox::instance
->property();
107 if (Openbox::instance
->state() != Openbox::State_Exiting
) {
108 // these values should not be persisted across a window unmapping/mapping
109 property
->erase(_window
, otk::OBProperty::net_wm_desktop
);
110 property
->erase(_window
, otk::OBProperty::net_wm_state
);
115 void OBClient::getDesktop()
117 const otk::OBProperty
*property
= Openbox::instance
->property();
119 // defaults to the current desktop
120 _desktop
= 0; // XXX: change this to the current desktop!
122 property
->get(_window
, otk::OBProperty::net_wm_desktop
,
123 otk::OBProperty::Atom_Cardinal
,
128 void OBClient::getType()
130 const otk::OBProperty
*property
= Openbox::instance
->property();
132 _type
= (WindowType
) -1;
135 unsigned long num
= (unsigned) -1;
136 if (property
->get(_window
, otk::OBProperty::net_wm_window_type
,
137 otk::OBProperty::Atom_Atom
,
139 // use the first value that we know about in the array
140 for (unsigned long i
= 0; i
< num
; ++i
) {
142 property
->atom(otk::OBProperty::net_wm_window_type_desktop
))
143 _type
= Type_Desktop
;
145 property
->atom(otk::OBProperty::net_wm_window_type_dock
))
148 property
->atom(otk::OBProperty::net_wm_window_type_toolbar
))
149 _type
= Type_Toolbar
;
151 property
->atom(otk::OBProperty::net_wm_window_type_menu
))
154 property
->atom(otk::OBProperty::net_wm_window_type_utility
))
155 _type
= Type_Utility
;
157 property
->atom(otk::OBProperty::net_wm_window_type_splash
))
160 property
->atom(otk::OBProperty::net_wm_window_type_dialog
))
163 property
->atom(otk::OBProperty::net_wm_window_type_normal
))
165 // else if (val[i] ==
166 // property->atom(otk::OBProperty::kde_net_wm_window_type_override))
167 // mwm_decorations = 0; // prevent this window from getting any decor
168 // XXX: make this work again
173 if (_type
== (WindowType
) -1) {
175 * the window type hint was not set, which means we either classify ourself
176 * as a normal window or a dialog, depending on if we are a transient.
186 void OBClient::getMwmHints()
188 const otk::OBProperty
*property
= Openbox::instance
->property();
193 num
= MwmHints::elements
;
194 if (!property
->get(_window
, otk::OBProperty::motif_wm_hints
,
195 otk::OBProperty::motif_wm_hints
, &num
,
196 (unsigned long **)&hints
))
199 if (num
< MwmHints::elements
) {
204 // retrieved the hints
205 // Mwm Hints are applied subtractively to what has already been chosen for
206 // decor and functionality
208 if (hints
->flags
& MwmFlag_Decorations
) {
209 if (! (hints
->decorations
& MwmDecor_All
)) {
210 if (! (hints
->decorations
& MwmDecor_Border
))
211 _decorations
&= ~Decor_Border
;
212 if (! (hints
->decorations
& MwmDecor_Handle
))
213 _decorations
&= ~Decor_Handle
;
214 if (! (hints
->decorations
& MwmDecor_Title
))
215 _decorations
&= ~Decor_Titlebar
;
216 if (! (hints
->decorations
& MwmDecor_Iconify
))
217 _decorations
&= ~Decor_Iconify
;
218 if (! (hints
->decorations
& MwmDecor_Maximize
))
219 _decorations
&= ~Decor_Maximize
;
223 if (hints
->flags
& MwmFlag_Functions
) {
224 if (! (hints
->functions
& MwmFunc_All
)) {
225 if (! (hints
->functions
& MwmFunc_Resize
))
226 _functions
&= ~Func_Resize
;
227 if (! (hints
->functions
& MwmFunc_Move
))
228 _functions
&= ~Func_Move
;
229 if (! (hints
->functions
& MwmFunc_Iconify
))
230 _functions
&= ~Func_Iconify
;
231 if (! (hints
->functions
& MwmFunc_Maximize
))
232 _functions
&= ~Func_Maximize
;
233 //if (! (hints->functions & MwmFunc_Close))
234 // _functions &= ~Func_Close;
241 void OBClient::getArea()
243 XWindowAttributes wattrib
;
246 ret
= XGetWindowAttributes(otk::OBDisplay::display
, _window
, &wattrib
);
247 assert(ret
!= BadWindow
);
249 _area
.setRect(wattrib
.x
, wattrib
.y
, wattrib
.width
, wattrib
.height
);
250 _border_width
= wattrib
.border_width
;
254 void OBClient::getState()
256 const otk::OBProperty
*property
= Openbox::instance
->property();
258 _modal
= _shaded
= _max_horz
= _max_vert
= _fullscreen
= _above
= _below
=
259 _skip_taskbar
= _skip_pager
= false;
261 unsigned long *state
;
262 unsigned long num
= (unsigned) -1;
264 if (property
->get(_window
, otk::OBProperty::net_wm_state
,
265 otk::OBProperty::Atom_Atom
, &num
, &state
)) {
266 for (unsigned long i
= 0; i
< num
; ++i
) {
267 if (state
[i
] == property
->atom(otk::OBProperty::net_wm_state_modal
))
270 property
->atom(otk::OBProperty::net_wm_state_shaded
)) {
272 _wmstate
= IconicState
;
273 } else if (state
[i
] ==
274 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
))
275 _skip_taskbar
= true;
277 property
->atom(otk::OBProperty::net_wm_state_skip_pager
))
280 property
->atom(otk::OBProperty::net_wm_state_fullscreen
))
283 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
))
286 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
))
289 property
->atom(otk::OBProperty::net_wm_state_above
))
292 property
->atom(otk::OBProperty::net_wm_state_below
))
301 void OBClient::getShaped()
305 if (otk::OBDisplay::shape()) {
310 XShapeSelectInput(otk::OBDisplay::display
, _window
, ShapeNotifyMask
);
312 XShapeQueryExtents(otk::OBDisplay::display
, _window
, &s
, &foo
,
313 &foo
, &ufoo
, &ufoo
, &foo
, &foo
, &foo
, &ufoo
, &ufoo
);
320 void OBClient::calcLayer() {
321 if (_iconic
) _layer
= Layer_Icon
;
322 else if (_fullscreen
) _layer
= Layer_Fullscreen
;
323 else if (_type
== Type_Desktop
) _layer
= Layer_Desktop
;
324 else if (_type
== Type_Dock
) {
325 if (!_below
) _layer
= Layer_Top
;
326 else _layer
= Layer_Normal
;
328 else if (_above
) _layer
= Layer_Above
;
329 else if (_below
) _layer
= Layer_Below
;
330 else _layer
= Layer_Normal
;
334 void OBClient::updateProtocols()
336 const otk::OBProperty
*property
= Openbox::instance
->property();
341 _focus_notify
= false;
342 _decorations
&= ~Decor_Close
;
343 _functions
&= ~Func_Close
;
345 if (XGetWMProtocols(otk::OBDisplay::display
, _window
, &proto
, &num_return
)) {
346 for (int i
= 0; i
< num_return
; ++i
) {
347 if (proto
[i
] == property
->atom(otk::OBProperty::wm_delete_window
)) {
348 _decorations
|= Decor_Close
;
349 _functions
|= Func_Close
;
351 frame
->adjustSize(); // update the decorations
352 } else if (proto
[i
] == property
->atom(otk::OBProperty::wm_take_focus
))
353 // if this protocol is requested, then the window will be notified
354 // by the window manager whenever it receives focus
355 _focus_notify
= true;
362 void OBClient::updateNormalHints()
366 int oldgravity
= _gravity
;
369 _gravity
= NorthWestGravity
;
370 _size_inc
.setPoint(1, 1);
371 _base_size
.setPoint(0, 0);
372 _min_size
.setPoint(0, 0);
373 _max_size
.setPoint(INT_MAX
, INT_MAX
);
375 // XXX: might want to cancel any interactive resizing of the window at this
378 // get the hints from the window
379 if (XGetWMNormalHints(otk::OBDisplay::display
, _window
, &size
, &ret
)) {
380 _positioned
= (size
.flags
& (PPosition
|USPosition
));
382 if (size
.flags
& PWinGravity
)
383 _gravity
= size
.win_gravity
;
385 if (size
.flags
& PMinSize
)
386 _min_size
.setPoint(size
.min_width
, size
.min_height
);
388 if (size
.flags
& PMaxSize
)
389 _max_size
.setPoint(size
.max_width
, size
.max_height
);
391 if (size
.flags
& PBaseSize
)
392 _base_size
.setPoint(size
.base_width
, size
.base_height
);
394 if (size
.flags
& PResizeInc
)
395 _size_inc
.setPoint(size
.width_inc
, size
.height_inc
);
398 // if the client has a frame, i.e. has already been mapped and is
399 // changing its gravity
400 if (frame
&& _gravity
!= oldgravity
) {
401 // move our idea of the client's position based on its new gravity
403 frame
->frameGravity(x
, y
);
409 void OBClient::updateWMHints()
413 // assume a window takes input if it doesnt specify
417 if ((hints
= XGetWMHints(otk::OBDisplay::display
, _window
)) != NULL
) {
418 if (hints
->flags
& InputHint
)
419 _can_focus
= hints
->input
;
421 if (hints
->flags
& XUrgencyHint
)
424 if (hints
->flags
& WindowGroupHint
) {
425 if (hints
->window_group
!= _group
) {
426 // XXX: remove from the old group if there was one
427 _group
= hints
->window_group
;
428 // XXX: do stuff with the group
438 void OBClient::updateTitle()
440 const otk::OBProperty
*property
= Openbox::instance
->property();
445 if (! property
->get(_window
, otk::OBProperty::net_wm_name
,
446 otk::OBProperty::utf8
, &_title
)) {
448 property
->get(_window
, otk::OBProperty::wm_name
,
449 otk::OBProperty::ascii
, &_title
);
453 _title
= _("Unnamed Window");
456 frame
->setTitle(_title
);
460 void OBClient::updateIconTitle()
462 const otk::OBProperty
*property
= Openbox::instance
->property();
467 if (! property
->get(_window
, otk::OBProperty::net_wm_icon_name
,
468 otk::OBProperty::utf8
, &_icon_title
)) {
470 property
->get(_window
, otk::OBProperty::wm_icon_name
,
471 otk::OBProperty::ascii
, &_icon_title
);
475 _icon_title
= _("Unnamed Window");
479 void OBClient::updateClass()
481 const otk::OBProperty
*property
= Openbox::instance
->property();
484 _app_name
= _app_class
= _role
= "";
486 otk::OBProperty::StringVect v
;
487 unsigned long num
= 2;
489 if (property
->get(_window
, otk::OBProperty::wm_class
,
490 otk::OBProperty::ascii
, &num
, &v
)) {
491 if (num
> 0) _app_name
= v
[0];
492 if (num
> 1) _app_class
= v
[1];
497 if (property
->get(_window
, otk::OBProperty::wm_window_role
,
498 otk::OBProperty::ascii
, &num
, &v
)) {
499 if (num
> 0) _role
= v
[0];
504 void OBClient::updateStrut()
506 unsigned long num
= 4;
508 if (!Openbox::instance
->property()->get(_window
,
509 otk::OBProperty::net_wm_strut
,
510 otk::OBProperty::Atom_Cardinal
,
515 _strut
.left
= data
[0];
516 _strut
.right
= data
[1];
517 _strut
.top
= data
[2];
518 _strut
.bottom
= data
[3];
520 Openbox::instance
->screen(_screen
)->updateStrut();
527 void OBClient::updateTransientFor()
532 if (XGetTransientForHint(otk::OBDisplay::display
, _window
, &t
) &&
533 t
!= _window
) { // cant be transient to itself!
534 c
= Openbox::instance
->findClient(t
);
535 assert(c
!= this); // if this happens then we need to check for it
537 if (!c
/*XXX: && _group*/) {
538 // not transient to a client, see if it is transient for a group
539 if (//t == _group->leader() ||
541 t
== otk::OBDisplay::screenInfo(_screen
)->rootWindow()) {
542 // window is a transient for its group!
543 // XXX: for now this is treated as non-transient.
544 // this needs to be fixed!
549 // if anything has changed...
550 if (c
!= _transient_for
) {
552 _transient_for
->_transients
.remove(this); // remove from old parent
555 _transient_for
->_transients
.push_back(this); // add to new parent
557 // XXX: change decor status?
562 void OBClient::propertyHandler(const XPropertyEvent
&e
)
564 otk::OtkEventHandler::propertyHandler(e
);
566 const otk::OBProperty
*property
= Openbox::instance
->property();
568 // compress changes to a single property into a single change
570 while (XCheckTypedEvent(otk::OBDisplay::display
, e
.type
, &ce
)) {
571 // XXX: it would be nice to compress ALL changes to a property, not just
572 // changes in a row without other props between.
573 if (ce
.xproperty
.atom
!= e
.atom
) {
574 XPutBackEvent(otk::OBDisplay::display
, &ce
);
579 if (e
.atom
== XA_WM_NORMAL_HINTS
)
581 else if (e
.atom
== XA_WM_HINTS
)
583 else if (e
.atom
== XA_WM_TRANSIENT_FOR
)
584 updateTransientFor();
585 else if (e
.atom
== property
->atom(otk::OBProperty::net_wm_name
) ||
586 e
.atom
== property
->atom(otk::OBProperty::wm_name
))
588 else if (e
.atom
== property
->atom(otk::OBProperty::net_wm_icon_name
) ||
589 e
.atom
== property
->atom(otk::OBProperty::wm_icon_name
))
591 else if (e
.atom
== property
->atom(otk::OBProperty::wm_class
))
593 else if (e
.atom
== property
->atom(otk::OBProperty::wm_protocols
))
595 else if (e
.atom
== property
->atom(otk::OBProperty::net_wm_strut
))
600 void OBClient::setWMState(long state
)
602 if (state
== _wmstate
) return; // no change
607 // XXX: cause it to iconify
610 // XXX: cause it to uniconify
616 void OBClient::setDesktop(long target
)
618 printf("Setting desktop %ld\n", target
);
619 assert(target
>= 0 || target
== (signed)0xffffffff);
620 //assert(target == 0xffffffff || target < MAX);
622 // XXX: move the window to the new desktop (and set root property)
627 void OBClient::setState(StateAction action
, long data1
, long data2
)
629 const otk::OBProperty
*property
= Openbox::instance
->property();
630 bool restack
= false, shadestate
= _shaded
;
632 if (!(action
== State_Add
|| action
== State_Remove
||
633 action
== State_Toggle
))
634 return; // an invalid action was passed to the client message, ignore it
636 for (int i
= 0; i
< 2; ++i
) {
637 Atom state
= i
== 0 ? data1
: data2
;
639 if (! state
) continue;
641 // if toggling, then pick whether we're adding or removing
642 if (action
== State_Toggle
) {
643 if (state
== property
->atom(otk::OBProperty::net_wm_state_modal
))
644 action
= _modal
? State_Remove
: State_Add
;
646 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
))
647 action
= _max_vert
? State_Remove
: State_Add
;
649 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
))
650 action
= _max_horz
? State_Remove
: State_Add
;
651 else if (state
== property
->atom(otk::OBProperty::net_wm_state_shaded
))
652 action
= _shaded
? State_Remove
: State_Add
;
654 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
))
655 action
= _skip_taskbar
? State_Remove
: State_Add
;
657 property
->atom(otk::OBProperty::net_wm_state_skip_pager
))
658 action
= _skip_pager
? State_Remove
: State_Add
;
660 property
->atom(otk::OBProperty::net_wm_state_fullscreen
))
661 action
= _fullscreen
? State_Remove
: State_Add
;
662 else if (state
== property
->atom(otk::OBProperty::net_wm_state_above
))
663 action
= _above
? State_Remove
: State_Add
;
664 else if (state
== property
->atom(otk::OBProperty::net_wm_state_below
))
665 action
= _below
? State_Remove
: State_Add
;
668 if (action
== State_Add
) {
669 if (state
== property
->atom(otk::OBProperty::net_wm_state_modal
)) {
670 if (_modal
) continue;
672 // XXX: give it focus if another window has focus that shouldnt now
674 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
)){
675 if (_max_vert
) continue;
677 // XXX: resize the window etc
679 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
)){
680 if (_max_horz
) continue;
682 // XXX: resize the window etc
684 property
->atom(otk::OBProperty::net_wm_state_shaded
)) {
685 if (_shaded
) continue;
686 // shade when we're all thru here
689 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
)) {
690 _skip_taskbar
= true;
692 property
->atom(otk::OBProperty::net_wm_state_skip_pager
)) {
695 property
->atom(otk::OBProperty::net_wm_state_fullscreen
)) {
696 if (_fullscreen
) continue;
700 property
->atom(otk::OBProperty::net_wm_state_above
)) {
701 if (_above
) continue;
705 property
->atom(otk::OBProperty::net_wm_state_below
)) {
706 if (_below
) continue;
711 } else { // action == State_Remove
712 if (state
== property
->atom(otk::OBProperty::net_wm_state_modal
)) {
713 if (!_modal
) continue;
716 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
)){
717 if (!_max_vert
) continue;
719 // XXX: resize the window etc
721 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
)){
722 if (!_max_horz
) continue;
724 // XXX: resize the window etc
726 property
->atom(otk::OBProperty::net_wm_state_shaded
)) {
727 if (!_shaded
) continue;
728 // unshade when we're all thru here
731 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
)) {
732 _skip_taskbar
= false;
734 property
->atom(otk::OBProperty::net_wm_state_skip_pager
)) {
737 property
->atom(otk::OBProperty::net_wm_state_fullscreen
)) {
738 if (!_fullscreen
) continue;
742 property
->atom(otk::OBProperty::net_wm_state_above
)) {
743 if (!_above
) continue;
747 property
->atom(otk::OBProperty::net_wm_state_below
)) {
748 if (!_below
) continue;
754 if (shadestate
!= _shaded
)
758 Openbox::instance
->screen(_screen
)->restack(true, this); // raise
763 void OBClient::toggleClientBorder(bool addborder
)
765 // adjust our idea of where the client is, based on its border. When the
766 // border is removed, the client should now be considered to be in a
767 // different position.
768 // when re-adding the border to the client, the same operation needs to be
770 int x
= _area
.x(), y
= _area
.y();
772 case NorthWestGravity
:
774 case SouthWestGravity
:
776 case NorthEastGravity
:
778 case SouthEastGravity
:
779 if (addborder
) x
-= _border_width
* 2;
780 else x
+= _border_width
* 2;
784 case NorthWestGravity
:
786 case NorthEastGravity
:
788 case SouthWestGravity
:
790 case SouthEastGravity
:
791 if (addborder
) y
-= _border_width
* 2;
792 else y
+= _border_width
* 2;
795 // no change for StaticGravity etc.
801 XSetWindowBorderWidth(otk::OBDisplay::display
, _window
, _border_width
);
803 // move the client so it is back it the right spot _with_ its border!
804 XMoveWindow(otk::OBDisplay::display
, _window
, x
, y
);
806 XSetWindowBorderWidth(otk::OBDisplay::display
, _window
, 0);
810 void OBClient::clientMessageHandler(const XClientMessageEvent
&e
)
812 otk::OtkEventHandler::clientMessageHandler(e
);
814 if (e
.format
!= 32) return;
816 const otk::OBProperty
*property
= Openbox::instance
->property();
818 if (e
.message_type
== property
->atom(otk::OBProperty::wm_change_state
)) {
819 // compress changes into a single change
820 bool compress
= false;
822 while (XCheckTypedEvent(otk::OBDisplay::display
, e
.type
, &ce
)) {
823 // XXX: it would be nice to compress ALL messages of a type, not just
824 // messages in a row without other message types between.
825 if (ce
.xclient
.message_type
!= e
.message_type
) {
826 XPutBackEvent(otk::OBDisplay::display
, &ce
);
832 setWMState(ce
.xclient
.data
.l
[0]); // use the found event
834 setWMState(e
.data
.l
[0]); // use the original event
835 } else if (e
.message_type
==
836 property
->atom(otk::OBProperty::net_wm_desktop
)) {
837 // compress changes into a single change
838 bool compress
= false;
840 while (XCheckTypedEvent(otk::OBDisplay::display
, e
.type
, &ce
)) {
841 // XXX: it would be nice to compress ALL messages of a type, not just
842 // messages in a row without other message types between.
843 if (ce
.xclient
.message_type
!= e
.message_type
) {
844 XPutBackEvent(otk::OBDisplay::display
, &ce
);
850 setDesktop(e
.data
.l
[0]); // use the found event
852 setDesktop(e
.data
.l
[0]); // use the original event
853 } else if (e
.message_type
== property
->atom(otk::OBProperty::net_wm_state
)) {
854 // can't compress these
855 setState((StateAction
)e
.data
.l
[0], e
.data
.l
[1], e
.data
.l
[2]);
856 } else if (e
.message_type
==
857 property
->atom(otk::OBProperty::net_close_window
)) {
859 } else if (e
.message_type
==
860 property
->atom(otk::OBProperty::net_active_window
)) {
862 Openbox::instance
->screen(_screen
)->restack(true, this); // raise
869 void OBClient::shapeHandler(const XShapeEvent
&e
)
871 otk::OtkEventHandler::shapeHandler(e
);
874 frame
->adjustShape();
879 void OBClient::resize(Corner anchor
, int w
, int h
, int x
, int y
)
884 // for interactive resizing. have to move half an increment in each
886 w
+= _size_inc
.x() / 2;
887 h
+= _size_inc
.y() / 2;
889 // is the window resizable? if it is not, then don't check its sizes, the
890 // client can do what it wants and the user can't change it anyhow
891 if (_min_size
.x() <= _max_size
.x() && _min_size
.y() <= _max_size
.y()) {
892 // smaller than min size or bigger than max size?
893 if (w
< _min_size
.x()) w
= _min_size
.x();
894 else if (w
> _max_size
.x()) w
= _max_size
.x();
895 if (h
< _min_size
.y()) h
= _min_size
.y();
896 else if (h
> _max_size
.y()) h
= _max_size
.y();
899 // keep to the increments
903 // store the logical size
904 _logical_size
.setPoint(w
, h
);
912 if (x
== INT_MIN
|| y
== INT_MIN
) {
919 x
-= w
- _area
.width();
922 y
-= h
- _area
.height();
925 x
-= w
- _area
.width();
926 y
-= h
- _area
.height();
933 XResizeWindow(otk::OBDisplay::display
, _window
, w
, h
);
935 // resize the frame to match the request
941 void OBClient::move(int x
, int y
)
945 // move the frame to be in the requested position
946 frame
->adjustPosition();
950 void OBClient::close()
953 const otk::OBProperty
*property
= Openbox::instance
->property();
955 if (!(_functions
& Func_Close
)) return;
957 // XXX: itd be cool to do timeouts and shit here for killing the client's
959 // like... if the window is around after 5 seconds, then the close button
960 // turns a nice red, and if this function is called again, the client is
961 // explicitly killed.
963 ce
.xclient
.type
= ClientMessage
;
964 ce
.xclient
.message_type
= property
->atom(otk::OBProperty::wm_protocols
);
965 ce
.xclient
.display
= otk::OBDisplay::display
;
966 ce
.xclient
.window
= _window
;
967 ce
.xclient
.format
= 32;
968 ce
.xclient
.data
.l
[0] = property
->atom(otk::OBProperty::wm_delete_window
);
969 ce
.xclient
.data
.l
[1] = CurrentTime
;
970 ce
.xclient
.data
.l
[2] = 0l;
971 ce
.xclient
.data
.l
[3] = 0l;
972 ce
.xclient
.data
.l
[4] = 0l;
973 XSendEvent(otk::OBDisplay::display
, _window
, False
, NoEventMask
, &ce
);
977 void OBClient::changeState()
979 const otk::OBProperty
*property
= Openbox::instance
->property();
981 unsigned long state
[2];
984 property
->set(_window
, otk::OBProperty::wm_state
, otk::OBProperty::wm_state
,
990 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_modal
);
992 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_shaded
);
994 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_hidden
);
997 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
);
999 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_skip_pager
);
1001 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_fullscreen
);
1004 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
);
1007 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
);
1009 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_above
);
1011 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_below
);
1012 property
->set(_window
, otk::OBProperty::net_wm_state
,
1013 otk::OBProperty::Atom_Atom
, netstate
, num
);
1018 void OBClient::setStackLayer(int l
)
1021 _above
= _below
= false; // normal
1024 _below
= false; // above
1027 _below
= true; // below
1031 Openbox::instance
->screen(_screen
)->restack(true, this); // raise
1035 void OBClient::shade(bool shade
)
1037 if (shade
== _shaded
) return; // already done
1039 _wmstate
= shade
? IconicState
: NormalState
;
1042 frame
->adjustSize();
1046 bool OBClient::focus()
1048 if (!(_can_focus
|| _focus_notify
) || _focused
) return false;
1051 XSetInputFocus(otk::OBDisplay::display
, _window
, RevertToNone
, CurrentTime
);
1053 if (_focus_notify
) {
1055 const otk::OBProperty
*property
= Openbox::instance
->property();
1057 ce
.xclient
.type
= ClientMessage
;
1058 ce
.xclient
.message_type
= property
->atom(otk::OBProperty::wm_protocols
);
1059 ce
.xclient
.display
= otk::OBDisplay::display
;
1060 ce
.xclient
.window
= _window
;
1061 ce
.xclient
.format
= 32;
1062 ce
.xclient
.data
.l
[0] = property
->atom(otk::OBProperty::wm_take_focus
);
1063 ce
.xclient
.data
.l
[1] = Openbox::instance
->lastTime();
1064 ce
.xclient
.data
.l
[2] = 0l;
1065 ce
.xclient
.data
.l
[3] = 0l;
1066 ce
.xclient
.data
.l
[4] = 0l;
1067 XSendEvent(otk::OBDisplay::display
, _window
, False
, NoEventMask
, &ce
);
1074 void OBClient::unfocus()
1076 if (!_focused
) return;
1078 assert(Openbox::instance
->focusedClient() == this);
1079 Openbox::instance
->setFocusedClient(0);
1083 void OBClient::focusHandler(const XFocusChangeEvent
&e
)
1086 printf("FocusIn for 0x%lx\n", e
.window
);
1089 OtkEventHandler::focusHandler(e
);
1094 Openbox::instance
->setFocusedClient(this);
1098 void OBClient::unfocusHandler(const XFocusChangeEvent
&e
)
1101 printf("FocusOut for 0x%lx\n", e
.window
);
1104 OtkEventHandler::unfocusHandler(e
);
1109 if (Openbox::instance
->focusedClient() == this) {
1110 printf("UNFOCUSED!\n");
1111 Openbox::instance
->setFocusedClient(this);
1116 void OBClient::configureRequestHandler(const XConfigureRequestEvent
&e
)
1119 printf("ConfigureRequest for 0x%lx\n", e
.window
);
1122 OtkEventHandler::configureRequestHandler(e
);
1124 // XXX: if we are iconic (or shaded? (fvwm does that)) ignore the event
1126 if (e
.value_mask
& CWBorderWidth
)
1127 _border_width
= e
.border_width
;
1129 // resize, then move, as specified in the EWMH section 7.7
1130 if (e
.value_mask
& (CWWidth
| CWHeight
)) {
1131 int w
= (e
.value_mask
& CWWidth
) ? e
.width
: _area
.width();
1132 int h
= (e
.value_mask
& CWHeight
) ? e
.height
: _area
.height();
1136 case NorthEastGravity
:
1140 case SouthWestGravity
:
1142 corner
= BottomLeft
;
1144 case SouthEastGravity
:
1145 corner
= BottomRight
;
1147 default: // NorthWest, Static, etc
1151 // if moving AND resizing ...
1152 if (e
.value_mask
& (CWX
| CWY
)) {
1153 int x
= (e
.value_mask
& CWX
) ? e
.x
: _area
.x();
1154 int y
= (e
.value_mask
& CWY
) ? e
.y
: _area
.y();
1155 resize(corner
, w
, h
, x
, y
);
1156 } else // if JUST resizing...
1157 resize(corner
, w
, h
);
1158 } else if (e
.value_mask
& (CWX
| CWY
)) { // if JUST moving...
1159 int x
= (e
.value_mask
& CWX
) ? e
.x
: _area
.x();
1160 int y
= (e
.value_mask
& CWY
) ? e
.y
: _area
.y();
1164 if (e
.value_mask
& CWStackMode
) {
1168 Openbox::instance
->screen(_screen
)->restack(false, this); // lower
1174 Openbox::instance
->screen(_screen
)->restack(true, this); // raise
1181 void OBClient::unmapHandler(const XUnmapEvent
&e
)
1184 printf("UnmapNotify for 0x%lx\n", e
.window
);
1187 if (ignore_unmaps
) {
1192 OtkEventHandler::unmapHandler(e
);
1194 // this deletes us etc
1195 Openbox::instance
->screen(_screen
)->unmanageWindow(this);
1199 void OBClient::destroyHandler(const XDestroyWindowEvent
&e
)
1202 printf("DestroyNotify for 0x%lx\n", e
.window
);
1205 OtkEventHandler::destroyHandler(e
);
1207 // this deletes us etc
1208 Openbox::instance
->screen(_screen
)->unmanageWindow(this);
1212 void OBClient::reparentHandler(const XReparentEvent
&e
)
1214 // this is when the client is first taken captive in the frame
1215 if (e
.parent
== frame
->plate()) return;
1218 printf("ReparentNotify for 0x%lx\n", e
.window
);
1221 OtkEventHandler::reparentHandler(e
);
1224 This event is quite rare and is usually handled in unmapHandler.
1225 However, if the window is unmapped when the reparent event occurs,
1226 the window manager never sees it because an unmap event is not sent
1227 to an already unmapped window.
1230 // this deletes us etc
1231 Openbox::instance
->screen(_screen
)->unmanageWindow(this);
1235 void OBClient::mapRequestHandler(const XMapRequestEvent
&e
)
1237 printf("\nMAP REQUEST\n\n");
1239 otk::OtkEventHandler::mapRequestHandler(e
);
1243 // XXX: uniconify the window