1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
6 #include "otk/display.hh"
7 #include "otk/property.hh"
11 #include <X11/Xutil.h>
16 #define _(str) gettext(str)
21 OBClient::OBClient(Window window
)
26 // update EVERYTHING the first time!!
28 // the state is kinda assumed to be normal. is this right? XXX
29 _wmstate
= NormalState
;
39 // XXX: updateTransientFor();
44 printf("Mapped window: 0x%lx\n"
60 " can be focused: %s\n"
67 " vert maximized: %s\n"
68 " horz maximized: %s\n"
77 _area
.width(), _area
.height(),
87 _can_focus
? "yes" : "no",
88 _focus_notify
? "yes" : "no",
89 _urgent
? "yes" : "no",
90 _shaped
? "yes" : "no",
91 _modal
? "yes" : "no",
92 _shaded
? "yes" : "no",
93 _iconic
? "yes" : "no",
94 _max_vert
? "yes" : "no",
95 _max_horz
? "yes" : "no",
96 _fullscreen
? "yes" : "no",
97 _floating
? "yes" : "no");
102 OBClient::~OBClient()
104 const otk::OBProperty
*property
= Openbox::instance
->property();
106 // these values should not be persisted across a window unmapping/mapping
107 property
->erase(_window
, otk::OBProperty::net_wm_desktop
);
108 property
->erase(_window
, otk::OBProperty::net_wm_state
);
112 void OBClient::getDesktop()
114 const otk::OBProperty
*property
= Openbox::instance
->property();
116 // defaults to the current desktop
117 _desktop
= 0; // XXX: change this to the current desktop!
119 property
->get(_window
, otk::OBProperty::net_wm_desktop
,
120 otk::OBProperty::Atom_Cardinal
,
125 void OBClient::getType()
127 const otk::OBProperty
*property
= Openbox::instance
->property();
129 _type
= (WindowType
) -1;
132 unsigned long num
= (unsigned) -1;
133 if (property
->get(_window
, otk::OBProperty::net_wm_window_type
,
134 otk::OBProperty::Atom_Atom
,
136 // use the first value that we know about in the array
137 for (unsigned long i
= 0; i
< num
; ++i
) {
139 property
->atom(otk::OBProperty::net_wm_window_type_desktop
))
140 _type
= Type_Desktop
;
142 property
->atom(otk::OBProperty::net_wm_window_type_dock
))
145 property
->atom(otk::OBProperty::net_wm_window_type_toolbar
))
146 _type
= Type_Toolbar
;
148 property
->atom(otk::OBProperty::net_wm_window_type_menu
))
151 property
->atom(otk::OBProperty::net_wm_window_type_utility
))
152 _type
= Type_Utility
;
154 property
->atom(otk::OBProperty::net_wm_window_type_splash
))
157 property
->atom(otk::OBProperty::net_wm_window_type_dialog
))
160 property
->atom(otk::OBProperty::net_wm_window_type_normal
))
162 // else if (val[i] ==
163 // property->atom(otk::OBProperty::kde_net_wm_window_type_override))
164 // mwm_decorations = 0; // prevent this window from getting any decor
165 // XXX: make this work again
170 if (_type
== (WindowType
) -1) {
172 * the window type hint was not set, which means we either classify ourself
173 * as a normal window or a dialog, depending on if we are a transient.
175 // XXX: make this code work!
177 // _type = Type_Dialog;
184 void OBClient::getArea()
186 XWindowAttributes wattrib
;
187 assert(XGetWindowAttributes(otk::OBDisplay::display
, _window
, &wattrib
));
189 _area
.setRect(wattrib
.x
, wattrib
.y
, wattrib
.width
, wattrib
.height
);
193 void OBClient::getState()
195 const otk::OBProperty
*property
= Openbox::instance
->property();
197 _modal
= _shaded
= _max_horz
= _max_vert
= _fullscreen
= _floating
= false;
199 unsigned long *state
;
200 unsigned long num
= (unsigned) -1;
202 if (property
->get(_window
, otk::OBProperty::net_wm_state
,
203 otk::OBProperty::Atom_Atom
, &num
, &state
)) {
204 for (unsigned long i
= 0; i
< num
; ++i
) {
205 if (state
[i
] == property
->atom(otk::OBProperty::net_wm_state_modal
))
208 property
->atom(otk::OBProperty::net_wm_state_shaded
))
211 property
->atom(otk::OBProperty::net_wm_state_fullscreen
))
214 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
))
217 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
))
226 void OBClient::getShaped()
230 if (otk::OBDisplay::shape()) {
234 XShapeQueryExtents(otk::OBDisplay::display
, client
.window
, &_shaped
, &foo
,
235 &foo
, &ufoo
, &ufoo
, &foo
, &foo
, &foo
, &ufoo
, &ufoo
);
241 void OBClient::updateNormalHints()
247 _gravity
= NorthWestGravity
;
249 _base_x
= _base_y
= 0;
251 // get the hints from the window
252 if (XGetWMNormalHints(otk::OBDisplay::display
, _window
, &size
, &ret
)) {
253 if (size
.flags
& PWinGravity
)
254 _gravity
= size
.win_gravity
;
255 if (size
.flags
& PBaseSize
) {
256 _base_x
= size
.base_width
;
257 _base_y
= size
.base_height
;
259 if (size
.flags
& PResizeInc
) {
260 _inc_x
= size
.width_inc
;
261 _inc_y
= size
.height_inc
;
267 void OBClient::updateWMHints()
271 // assume a window takes input if it doesnt specify
275 if ((hints
= XGetWMHints(otk::OBDisplay::display
, _window
)) != NULL
) {
276 if (hints
->flags
& InputHint
)
277 _can_focus
= hints
->input
;
279 if (hints
->flags
& XUrgencyHint
)
282 if (hints
->flags
& WindowGroupHint
) {
283 if (hints
->window_group
!= _group
) {
284 // XXX: remove from the old group if there was one
285 _group
= hints
->window_group
;
286 // XXX: do stuff with the group
296 void OBClient::updateTitle()
298 const otk::OBProperty
*property
= Openbox::instance
->property();
303 if (! property
->get(_window
, otk::OBProperty::net_wm_name
,
304 otk::OBProperty::utf8
, &_title
)) {
306 property
->get(_window
, otk::OBProperty::wm_name
,
307 otk::OBProperty::ascii
, &_title
);
311 _title
= _("Unnamed Window");
315 void OBClient::updateClass()
317 const otk::OBProperty
*property
= Openbox::instance
->property();
320 _app_name
= _app_class
= "";
322 otk::OBProperty::StringVect v
;
323 unsigned long num
= 2;
325 if (! property
->get(_window
, otk::OBProperty::wm_class
,
326 otk::OBProperty::ascii
, &num
, &v
))
329 if (num
> 0) _app_name
= v
[0];
330 if (num
> 1) _app_class
= v
[1];
334 void OBClient::update(const XPropertyEvent
&e
)
336 const otk::OBProperty
*property
= Openbox::instance
->property();
338 if (e
.atom
== XA_WM_NORMAL_HINTS
)
340 else if (e
.atom
== XA_WM_HINTS
)
342 else if (e
.atom
== property
->atom(otk::OBProperty::net_wm_name
) ||
343 e
.atom
== property
->atom(otk::OBProperty::wm_name
) ||
344 e
.atom
== property
->atom(otk::OBProperty::net_wm_icon_name
) ||
345 e
.atom
== property
->atom(otk::OBProperty::wm_icon_name
))
347 else if (e
.atom
== property
->atom(otk::OBProperty::wm_class
))
349 // XXX: transient for hint
353 void OBClient::setWMState(long state
)
355 if (state
== _wmstate
) return; // no change
359 // XXX: cause it to iconify
362 // XXX: cause it to uniconify
369 void OBClient::setDesktop(long target
)
372 //assert(target == 0xffffffff || target < MAX);
374 // XXX: move the window to the new desktop
379 void OBClient::setState(StateAction action
, long data1
, long data2
)
381 const otk::OBProperty
*property
= Openbox::instance
->property();
383 if (!(action
== State_Add
|| action
== State_Remove
||
384 action
== State_Toggle
))
385 return; // an invalid action was passed to the client message, ignore it
387 for (int i
= 0; i
< 2; ++i
) {
388 Atom state
= i
== 0 ? data1
: data2
;
390 if (! state
) continue;
392 // if toggling, then pick whether we're adding or removing
393 if (action
== State_Toggle
) {
394 if (state
== property
->atom(otk::OBProperty::net_wm_state_modal
))
395 action
= _modal
? State_Remove
: State_Add
;
397 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
))
398 action
= _max_vert
? State_Remove
: State_Add
;
400 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
))
401 action
= _max_horz
? State_Remove
: State_Add
;
402 else if (state
== property
->atom(otk::OBProperty::net_wm_state_shaded
))
403 action
= _shaded
? State_Remove
: State_Add
;
405 property
->atom(otk::OBProperty::net_wm_state_fullscreen
))
406 action
= _fullscreen
? State_Remove
: State_Add
;
407 else if (state
== property
->atom(otk::OBProperty::net_wm_state_floating
))
408 action
= _floating
? State_Remove
: State_Add
;
411 if (action
== State_Add
) {
412 if (state
== property
->atom(otk::OBProperty::net_wm_state_modal
)) {
413 if (_modal
) continue;
415 // XXX: give it focus if another window has focus that shouldnt now
417 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
)){
418 if (_max_vert
) continue;
420 // XXX: resize the window etc
422 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
)){
423 if (_max_horz
) continue;
425 // XXX: resize the window etc
427 property
->atom(otk::OBProperty::net_wm_state_shaded
)) {
428 if (_shaded
) continue;
430 // XXX: hide the client window
432 property
->atom(otk::OBProperty::net_wm_state_fullscreen
)) {
433 if (_fullscreen
) continue;
435 // XXX: raise the window n shit
437 property
->atom(otk::OBProperty::net_wm_state_floating
)) {
438 if (_floating
) continue;
440 // XXX: raise the window n shit
443 } else { // action == State_Remove
444 if (state
== property
->atom(otk::OBProperty::net_wm_state_modal
)) {
445 if (!_modal
) continue;
448 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
)){
449 if (!_max_vert
) continue;
451 // XXX: resize the window etc
453 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
)){
454 if (!_max_horz
) continue;
456 // XXX: resize the window etc
458 property
->atom(otk::OBProperty::net_wm_state_shaded
)) {
459 if (!_shaded
) continue;
461 // XXX: show the client window
463 property
->atom(otk::OBProperty::net_wm_state_fullscreen
)) {
464 if (!_fullscreen
) continue;
466 // XXX: lower the window to its proper layer
468 property
->atom(otk::OBProperty::net_wm_state_floating
)) {
469 if (!_floating
) continue;
471 // XXX: lower the window to its proper layer
478 void OBClient::update(const XClientMessageEvent
&e
)
480 if (e
.format
!= 32) return;
482 const otk::OBProperty
*property
= Openbox::instance
->property();
484 if (e
.message_type
== property
->atom(otk::OBProperty::wm_change_state
))
485 setWMState(e
.data
.l
[0]);
486 else if (e
.message_type
==
487 property
->atom(otk::OBProperty::net_wm_desktop
))
488 setDesktop(e
.data
.l
[0]);
489 else if (e
.message_type
== property
->atom(otk::OBProperty::net_wm_state
))
490 setState((StateAction
)e
.data
.l
[0], e
.data
.l
[1], e
.data
.l
[2]);
494 void OBClient::setArea(const otk::Rect
&area
)