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
))
270 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
))
271 _skip_taskbar
= true;
273 property
->atom(otk::OBProperty::net_wm_state_skip_pager
))
276 property
->atom(otk::OBProperty::net_wm_state_fullscreen
))
279 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
))
282 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
))
285 property
->atom(otk::OBProperty::net_wm_state_above
))
288 property
->atom(otk::OBProperty::net_wm_state_below
))
297 void OBClient::getShaped()
301 if (otk::OBDisplay::shape()) {
306 XShapeSelectInput(otk::OBDisplay::display
, _window
, ShapeNotifyMask
);
308 XShapeQueryExtents(otk::OBDisplay::display
, _window
, &s
, &foo
,
309 &foo
, &ufoo
, &ufoo
, &foo
, &foo
, &foo
, &ufoo
, &ufoo
);
316 void OBClient::calcLayer() {
317 if (_iconic
) _layer
= OBScreen::Layer_Icon
;
318 else if (_fullscreen
) _layer
= OBScreen::Layer_Fullscreen
;
319 else if (_type
== Type_Desktop
) _layer
= OBScreen::Layer_Desktop
;
320 else if (_type
== Type_Dock
) {
321 if (!_below
) _layer
= OBScreen::Layer_Top
;
322 else _layer
= OBScreen::Layer_Normal
;
324 else if (_above
) _layer
= OBScreen::Layer_Above
;
325 else if (_below
) _layer
= OBScreen::Layer_Below
;
326 else _layer
= OBScreen::Layer_Normal
;
330 void OBClient::updateProtocols()
332 const otk::OBProperty
*property
= Openbox::instance
->property();
337 _focus_notify
= false;
338 _decorations
&= ~Decor_Close
;
339 _functions
&= ~Func_Close
;
341 if (XGetWMProtocols(otk::OBDisplay::display
, _window
, &proto
, &num_return
)) {
342 for (int i
= 0; i
< num_return
; ++i
) {
343 if (proto
[i
] == property
->atom(otk::OBProperty::wm_delete_window
)) {
344 _decorations
|= Decor_Close
;
345 _functions
|= Func_Close
;
347 frame
->adjustSize(); // update the decorations
348 } else if (proto
[i
] == property
->atom(otk::OBProperty::wm_take_focus
))
349 // if this protocol is requested, then the window will be notified
350 // by the window manager whenever it receives focus
351 _focus_notify
= true;
358 void OBClient::updateNormalHints()
362 int oldgravity
= _gravity
;
365 _gravity
= NorthWestGravity
;
366 _size_inc
.setPoint(1, 1);
367 _base_size
.setPoint(0, 0);
368 _min_size
.setPoint(0, 0);
369 _max_size
.setPoint(INT_MAX
, INT_MAX
);
371 // XXX: might want to cancel any interactive resizing of the window at this
374 // get the hints from the window
375 if (XGetWMNormalHints(otk::OBDisplay::display
, _window
, &size
, &ret
)) {
376 _positioned
= (size
.flags
& (PPosition
|USPosition
));
378 if (size
.flags
& PWinGravity
)
379 _gravity
= size
.win_gravity
;
381 if (size
.flags
& PMinSize
)
382 _min_size
.setPoint(size
.min_width
, size
.min_height
);
384 if (size
.flags
& PMaxSize
)
385 _max_size
.setPoint(size
.max_width
, size
.max_height
);
387 if (size
.flags
& PBaseSize
)
388 _base_size
.setPoint(size
.base_width
, size
.base_height
);
390 if (size
.flags
& PResizeInc
)
391 _size_inc
.setPoint(size
.width_inc
, size
.height_inc
);
394 // if the client has a frame, i.e. has already been mapped and is
395 // changing its gravity
396 if (frame
&& _gravity
!= oldgravity
) {
397 // move our idea of the client's position based on its new gravity
399 frame
->frameGravity(x
, y
);
405 void OBClient::updateWMHints()
409 // assume a window takes input if it doesnt specify
413 if ((hints
= XGetWMHints(otk::OBDisplay::display
, _window
)) != NULL
) {
414 if (hints
->flags
& InputHint
)
415 _can_focus
= hints
->input
;
417 if (hints
->flags
& XUrgencyHint
)
420 if (hints
->flags
& WindowGroupHint
) {
421 if (hints
->window_group
!= _group
) {
422 // XXX: remove from the old group if there was one
423 _group
= hints
->window_group
;
424 // XXX: do stuff with the group
434 void OBClient::updateTitle()
436 const otk::OBProperty
*property
= Openbox::instance
->property();
441 if (! property
->get(_window
, otk::OBProperty::net_wm_name
,
442 otk::OBProperty::utf8
, &_title
)) {
444 property
->get(_window
, otk::OBProperty::wm_name
,
445 otk::OBProperty::ascii
, &_title
);
449 _title
= _("Unnamed Window");
452 frame
->setTitle(_title
);
456 void OBClient::updateIconTitle()
458 const otk::OBProperty
*property
= Openbox::instance
->property();
463 if (! property
->get(_window
, otk::OBProperty::net_wm_icon_name
,
464 otk::OBProperty::utf8
, &_icon_title
)) {
466 property
->get(_window
, otk::OBProperty::wm_icon_name
,
467 otk::OBProperty::ascii
, &_icon_title
);
471 _icon_title
= _("Unnamed Window");
475 void OBClient::updateClass()
477 const otk::OBProperty
*property
= Openbox::instance
->property();
480 _app_name
= _app_class
= "";
482 otk::OBProperty::StringVect v
;
483 unsigned long num
= 2;
485 if (! property
->get(_window
, otk::OBProperty::wm_class
,
486 otk::OBProperty::ascii
, &num
, &v
))
489 if (num
> 0) _app_name
= v
[0];
490 if (num
> 1) _app_class
= v
[1];
494 void OBClient::updateStrut()
496 unsigned long num
= 4;
498 if (!Openbox::instance
->property()->get(_window
,
499 otk::OBProperty::net_wm_strut
,
500 otk::OBProperty::Atom_Cardinal
,
505 _strut
.left
= data
[0];
506 _strut
.right
= data
[1];
507 _strut
.top
= data
[2];
508 _strut
.bottom
= data
[3];
510 Openbox::instance
->screen(_screen
)->updateStrut();
517 void OBClient::propertyHandler(const XPropertyEvent
&e
)
519 otk::OtkEventHandler::propertyHandler(e
);
521 const otk::OBProperty
*property
= Openbox::instance
->property();
523 // compress changes to a single property into a single change
525 while (XCheckTypedEvent(otk::OBDisplay::display
, e
.type
, &ce
)) {
526 // XXX: it would be nice to compress ALL changes to a property, not just
527 // changes in a row without other props between.
528 if (ce
.xproperty
.atom
!= e
.atom
) {
529 XPutBackEvent(otk::OBDisplay::display
, &ce
);
534 if (e
.atom
== XA_WM_NORMAL_HINTS
)
536 else if (e
.atom
== XA_WM_HINTS
)
538 else if (e
.atom
== property
->atom(otk::OBProperty::net_wm_name
) ||
539 e
.atom
== property
->atom(otk::OBProperty::wm_name
))
541 else if (e
.atom
== property
->atom(otk::OBProperty::net_wm_icon_name
) ||
542 e
.atom
== property
->atom(otk::OBProperty::wm_icon_name
))
544 else if (e
.atom
== property
->atom(otk::OBProperty::wm_class
))
546 else if (e
.atom
== property
->atom(otk::OBProperty::wm_protocols
))
548 // XXX: transient for hint
549 else if (e
.atom
== property
->atom(otk::OBProperty::net_wm_strut
))
555 void OBClient::setWMState(long state
)
557 if (state
== _wmstate
) return; // no change
561 // XXX: cause it to iconify
564 // XXX: cause it to uniconify
571 void OBClient::setDesktop(long target
)
573 printf("Setting desktop %ld\n", target
);
574 assert(target
>= 0 || target
== (signed)0xffffffff);
575 //assert(target == 0xffffffff || target < MAX);
577 // XXX: move the window to the new desktop (and set root property)
582 void OBClient::setState(StateAction action
, long data1
, long data2
)
584 const otk::OBProperty
*property
= Openbox::instance
->property();
585 bool restack
= false, shadestate
= _shaded
;
587 if (!(action
== State_Add
|| action
== State_Remove
||
588 action
== State_Toggle
))
589 return; // an invalid action was passed to the client message, ignore it
591 for (int i
= 0; i
< 2; ++i
) {
592 Atom state
= i
== 0 ? data1
: data2
;
594 if (! state
) continue;
596 // if toggling, then pick whether we're adding or removing
597 if (action
== State_Toggle
) {
598 if (state
== property
->atom(otk::OBProperty::net_wm_state_modal
))
599 action
= _modal
? State_Remove
: State_Add
;
601 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
))
602 action
= _max_vert
? State_Remove
: State_Add
;
604 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
))
605 action
= _max_horz
? State_Remove
: State_Add
;
606 else if (state
== property
->atom(otk::OBProperty::net_wm_state_shaded
))
607 action
= _shaded
? State_Remove
: State_Add
;
609 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
))
610 action
= _skip_taskbar
? State_Remove
: State_Add
;
612 property
->atom(otk::OBProperty::net_wm_state_skip_pager
))
613 action
= _skip_pager
? State_Remove
: State_Add
;
615 property
->atom(otk::OBProperty::net_wm_state_fullscreen
))
616 action
= _fullscreen
? State_Remove
: State_Add
;
617 else if (state
== property
->atom(otk::OBProperty::net_wm_state_above
))
618 action
= _above
? State_Remove
: State_Add
;
619 else if (state
== property
->atom(otk::OBProperty::net_wm_state_below
))
620 action
= _below
? State_Remove
: State_Add
;
623 if (action
== State_Add
) {
624 if (state
== property
->atom(otk::OBProperty::net_wm_state_modal
)) {
625 if (_modal
) continue;
627 // XXX: give it focus if another window has focus that shouldnt now
629 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
)){
630 if (_max_vert
) continue;
632 // XXX: resize the window etc
634 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
)){
635 if (_max_horz
) continue;
637 // XXX: resize the window etc
639 property
->atom(otk::OBProperty::net_wm_state_shaded
)) {
640 if (_shaded
) continue;
641 // shade when we're all thru here
644 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
)) {
645 _skip_taskbar
= true;
647 property
->atom(otk::OBProperty::net_wm_state_skip_pager
)) {
650 property
->atom(otk::OBProperty::net_wm_state_fullscreen
)) {
651 if (_fullscreen
) continue;
655 property
->atom(otk::OBProperty::net_wm_state_above
)) {
656 if (_above
) continue;
660 property
->atom(otk::OBProperty::net_wm_state_below
)) {
661 if (_below
) continue;
666 } else { // action == State_Remove
667 if (state
== property
->atom(otk::OBProperty::net_wm_state_modal
)) {
668 if (!_modal
) continue;
671 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
)){
672 if (!_max_vert
) continue;
674 // XXX: resize the window etc
676 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
)){
677 if (!_max_horz
) continue;
679 // XXX: resize the window etc
681 property
->atom(otk::OBProperty::net_wm_state_shaded
)) {
682 if (!_shaded
) continue;
683 // unshade when we're all thru here
686 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
)) {
687 _skip_taskbar
= false;
689 property
->atom(otk::OBProperty::net_wm_state_skip_pager
)) {
692 property
->atom(otk::OBProperty::net_wm_state_fullscreen
)) {
693 if (!_fullscreen
) continue;
697 property
->atom(otk::OBProperty::net_wm_state_above
)) {
698 if (!_above
) continue;
702 property
->atom(otk::OBProperty::net_wm_state_below
)) {
703 if (!_below
) continue;
709 if (shadestate
!= _shaded
)
713 Openbox::instance
->screen(_screen
)->restack(true, this); // raise
718 void OBClient::toggleClientBorder(bool addborder
)
720 // adjust our idea of where the client is, based on its border. When the
721 // border is removed, the client should now be considered to be in a
722 // different position.
723 // when re-adding the border to the client, the same operation needs to be
725 int x
= _area
.x(), y
= _area
.y();
727 case NorthWestGravity
:
729 case SouthWestGravity
:
731 case NorthEastGravity
:
733 case SouthEastGravity
:
734 if (addborder
) x
-= _border_width
* 2;
735 else x
+= _border_width
* 2;
739 case NorthWestGravity
:
741 case NorthEastGravity
:
743 case SouthWestGravity
:
745 case SouthEastGravity
:
746 if (addborder
) y
-= _border_width
* 2;
747 else y
+= _border_width
* 2;
750 // no change for StaticGravity etc.
756 XSetWindowBorderWidth(otk::OBDisplay::display
, _window
, _border_width
);
758 // move the client so it is back it the right spot _with_ its border!
759 XMoveWindow(otk::OBDisplay::display
, _window
, x
, y
);
761 XSetWindowBorderWidth(otk::OBDisplay::display
, _window
, 0);
765 void OBClient::clientMessageHandler(const XClientMessageEvent
&e
)
767 otk::OtkEventHandler::clientMessageHandler(e
);
769 if (e
.format
!= 32) return;
771 const otk::OBProperty
*property
= Openbox::instance
->property();
773 if (e
.message_type
== property
->atom(otk::OBProperty::wm_change_state
)) {
774 // compress changes into a single change
775 bool compress
= false;
777 while (XCheckTypedEvent(otk::OBDisplay::display
, e
.type
, &ce
)) {
778 // XXX: it would be nice to compress ALL messages of a type, not just
779 // messages in a row without other message types between.
780 if (ce
.xclient
.message_type
!= e
.message_type
) {
781 XPutBackEvent(otk::OBDisplay::display
, &ce
);
787 setWMState(ce
.xclient
.data
.l
[0]); // use the found event
789 setWMState(e
.data
.l
[0]); // use the original event
790 } else if (e
.message_type
==
791 property
->atom(otk::OBProperty::net_wm_desktop
)) {
792 // compress changes into a single change
793 bool compress
= false;
795 while (XCheckTypedEvent(otk::OBDisplay::display
, e
.type
, &ce
)) {
796 // XXX: it would be nice to compress ALL messages of a type, not just
797 // messages in a row without other message types between.
798 if (ce
.xclient
.message_type
!= e
.message_type
) {
799 XPutBackEvent(otk::OBDisplay::display
, &ce
);
805 setDesktop(e
.data
.l
[0]); // use the found event
807 setDesktop(e
.data
.l
[0]); // use the original event
808 } else if (e
.message_type
== property
->atom(otk::OBProperty::net_wm_state
)) {
809 // can't compress these
810 setState((StateAction
)e
.data
.l
[0], e
.data
.l
[1], e
.data
.l
[2]);
811 } else if (e
.message_type
==
812 property
->atom(otk::OBProperty::net_close_window
)) {
814 } else if (e
.message_type
==
815 property
->atom(otk::OBProperty::net_active_window
)) {
817 Openbox::instance
->screen(_screen
)->restack(true, this); // raise
824 void OBClient::shapeHandler(const XShapeEvent
&e
)
826 otk::OtkEventHandler::shapeHandler(e
);
829 frame
->adjustShape();
834 void OBClient::resize(Corner anchor
, int w
, int h
, int x
, int y
)
839 // for interactive resizing. have to move half an increment in each
841 w
+= _size_inc
.x() / 2;
842 h
+= _size_inc
.y() / 2;
844 // is the window resizable? if it is not, then don't check its sizes, the
845 // client can do what it wants and the user can't change it anyhow
846 if (_min_size
.x() <= _max_size
.x() && _min_size
.y() <= _max_size
.y()) {
847 // smaller than min size or bigger than max size?
848 if (w
< _min_size
.x()) w
= _min_size
.x();
849 else if (w
> _max_size
.x()) w
= _max_size
.x();
850 if (h
< _min_size
.y()) h
= _min_size
.y();
851 else if (h
> _max_size
.y()) h
= _max_size
.y();
854 // keep to the increments
858 // store the logical size
859 _logical_size
.setPoint(w
, h
);
867 if (x
== INT_MIN
|| y
== INT_MIN
) {
874 x
-= w
- _area
.width();
877 y
-= h
- _area
.height();
880 x
-= w
- _area
.width();
881 y
-= h
- _area
.height();
888 XResizeWindow(otk::OBDisplay::display
, _window
, w
, h
);
890 // resize the frame to match the request
896 void OBClient::move(int x
, int y
)
900 // move the frame to be in the requested position
901 frame
->adjustPosition();
905 void OBClient::close()
908 const otk::OBProperty
*property
= Openbox::instance
->property();
910 if (!(_functions
& Func_Close
)) return;
912 // XXX: itd be cool to do timeouts and shit here for killing the client's
914 // like... if the window is around after 5 seconds, then the close button
915 // turns a nice red, and if this function is called again, the client is
916 // explicitly killed.
918 ce
.xclient
.type
= ClientMessage
;
919 ce
.xclient
.message_type
= property
->atom(otk::OBProperty::wm_protocols
);
920 ce
.xclient
.display
= otk::OBDisplay::display
;
921 ce
.xclient
.window
= _window
;
922 ce
.xclient
.format
= 32;
923 ce
.xclient
.data
.l
[0] = property
->atom(otk::OBProperty::wm_delete_window
);
924 ce
.xclient
.data
.l
[1] = CurrentTime
;
925 ce
.xclient
.data
.l
[2] = 0l;
926 ce
.xclient
.data
.l
[3] = 0l;
927 ce
.xclient
.data
.l
[4] = 0l;
928 XSendEvent(otk::OBDisplay::display
, _window
, False
, NoEventMask
, &ce
);
932 void OBClient::changeState()
934 const otk::OBProperty
*property
= Openbox::instance
->property();
936 unsigned long state
[2];
939 property
->set(_window
, otk::OBProperty::wm_state
, otk::OBProperty::wm_state
,
945 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_modal
);
947 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_shaded
);
949 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_hidden
);
952 property
->atom(otk::OBProperty::net_wm_state_skip_taskbar
);
954 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_skip_pager
);
956 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_fullscreen
);
959 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
);
962 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
);
964 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_above
);
966 netstate
[num
++] = property
->atom(otk::OBProperty::net_wm_state_below
);
967 property
->set(_window
, otk::OBProperty::net_wm_state
,
968 otk::OBProperty::Atom_Atom
, netstate
, num
);
973 void OBClient::setStackLayer(int l
)
976 _above
= _below
= false; // normal
979 _below
= false; // above
982 _below
= true; // below
986 Openbox::instance
->screen(_screen
)->restack(true, this); // raise
990 void OBClient::shade(bool shade
)
992 if (shade
== _shaded
) return; // already done
994 _wmstate
= shade
? IconicState
: NormalState
;
1001 bool OBClient::focus()
1003 if (!(_can_focus
|| _focus_notify
) || _focused
) return false;
1006 XSetInputFocus(otk::OBDisplay::display
, _window
, RevertToNone
, CurrentTime
);
1008 if (_focus_notify
) {
1010 const otk::OBProperty
*property
= Openbox::instance
->property();
1012 ce
.xclient
.type
= ClientMessage
;
1013 ce
.xclient
.message_type
= property
->atom(otk::OBProperty::wm_protocols
);
1014 ce
.xclient
.display
= otk::OBDisplay::display
;
1015 ce
.xclient
.window
= _window
;
1016 ce
.xclient
.format
= 32;
1017 ce
.xclient
.data
.l
[0] = property
->atom(otk::OBProperty::wm_take_focus
);
1018 ce
.xclient
.data
.l
[1] = Openbox::instance
->lastTime();
1019 ce
.xclient
.data
.l
[2] = 0l;
1020 ce
.xclient
.data
.l
[3] = 0l;
1021 ce
.xclient
.data
.l
[4] = 0l;
1022 XSendEvent(otk::OBDisplay::display
, _window
, False
, NoEventMask
, &ce
);
1029 void OBClient::unfocus()
1031 if (!_focused
) return;
1033 assert(Openbox::instance
->focusedClient() == this);
1034 Openbox::instance
->setFocusedClient(0);
1038 void OBClient::focusHandler(const XFocusChangeEvent
&e
)
1041 printf("FocusIn for 0x%lx\n", e
.window
);
1044 OtkEventHandler::focusHandler(e
);
1049 Openbox::instance
->setFocusedClient(this);
1053 void OBClient::unfocusHandler(const XFocusChangeEvent
&e
)
1056 printf("FocusOut for 0x%lx\n", e
.window
);
1059 OtkEventHandler::unfocusHandler(e
);
1064 if (Openbox::instance
->focusedClient() == this) {
1065 printf("UNFOCUSED!\n");
1066 Openbox::instance
->setFocusedClient(this);
1071 void OBClient::configureRequestHandler(const XConfigureRequestEvent
&e
)
1074 printf("ConfigureRequest for 0x%lx\n", e
.window
);
1077 OtkEventHandler::configureRequestHandler(e
);
1079 // XXX: if we are iconic (or shaded? (fvwm does that)) ignore the event
1081 if (e
.value_mask
& CWBorderWidth
)
1082 _border_width
= e
.border_width
;
1084 // resize, then move, as specified in the EWMH section 7.7
1085 if (e
.value_mask
& (CWWidth
| CWHeight
)) {
1086 int w
= (e
.value_mask
& CWWidth
) ? e
.width
: _area
.width();
1087 int h
= (e
.value_mask
& CWHeight
) ? e
.height
: _area
.height();
1091 case NorthEastGravity
:
1095 case SouthWestGravity
:
1097 corner
= BottomLeft
;
1099 case SouthEastGravity
:
1100 corner
= BottomRight
;
1102 default: // NorthWest, Static, etc
1106 // if moving AND resizing ...
1107 if (e
.value_mask
& (CWX
| CWY
)) {
1108 int x
= (e
.value_mask
& CWX
) ? e
.x
: _area
.x();
1109 int y
= (e
.value_mask
& CWY
) ? e
.y
: _area
.y();
1110 resize(corner
, w
, h
, x
, y
);
1111 } else // if JUST resizing...
1112 resize(corner
, w
, h
);
1113 } else if (e
.value_mask
& (CWX
| CWY
)) { // if JUST moving...
1114 int x
= (e
.value_mask
& CWX
) ? e
.x
: _area
.x();
1115 int y
= (e
.value_mask
& CWY
) ? e
.y
: _area
.y();
1119 if (e
.value_mask
& CWStackMode
) {
1123 // XXX: lower the window
1129 // XXX: raise the window
1136 void OBClient::unmapHandler(const XUnmapEvent
&e
)
1139 printf("UnmapNotify for 0x%lx\n", e
.window
);
1142 if (ignore_unmaps
) {
1147 OtkEventHandler::unmapHandler(e
);
1149 // this deletes us etc
1150 Openbox::instance
->screen(_screen
)->unmanageWindow(this);
1154 void OBClient::destroyHandler(const XDestroyWindowEvent
&e
)
1157 printf("DestroyNotify for 0x%lx\n", e
.window
);
1160 OtkEventHandler::destroyHandler(e
);
1162 // this deletes us etc
1163 Openbox::instance
->screen(_screen
)->unmanageWindow(this);
1167 void OBClient::reparentHandler(const XReparentEvent
&e
)
1169 // this is when the client is first taken captive in the frame
1170 if (e
.parent
== frame
->plate()) return;
1173 printf("ReparentNotify for 0x%lx\n", e
.window
);
1176 OtkEventHandler::reparentHandler(e
);
1179 This event is quite rare and is usually handled in unmapHandler.
1180 However, if the window is unmapped when the reparent event occurs,
1181 the window manager never sees it because an unmap event is not sent
1182 to an already unmapped window.
1185 // this deletes us etc
1186 Openbox::instance
->screen(_screen
)->unmanageWindow(this);