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
;
40 // XXX: updateTransientFor();
45 printf("Mapped window: 0x%lx\n"
46 " title: \t%s\t icon title: \t%s\n"
47 " app name: \t%s\t\t class: \t%s\n"
48 " position: \t%d, %d\t\t size: \t%d, %d\n"
49 " desktop: \t%lu\t\t group: \t0x%lx\n"
50 " type: \t%d\t\t min size \t%d, %d\n"
51 " base size \t%d, %d\t\t max size \t%d, %d\n"
52 " size incr \t%d, %d\t\t gravity \t%d\n"
53 " wm state \t%ld\t\t can be focused:\t%s\n"
54 " notify focus: \t%s\t\t urgent: \t%s\n"
55 " shaped: \t%s\t\t modal: \t%s\n"
56 " shaded: \t%s\t\t iconic: \t%s\n"
57 " vert maximized:\t%s\t\t horz maximized:\t%s\n"
58 " fullscreen: \t%s\t\t floating: \t%s\n"
59 " requested pos: \t%s\n",
66 _area
.width(), _area
.height(),
76 _can_focus
? "yes" : "no",
77 _focus_notify
? "yes" : "no",
78 _urgent
? "yes" : "no",
79 _shaped
? "yes" : "no",
80 _modal
? "yes" : "no",
81 _shaded
? "yes" : "no",
82 _iconic
? "yes" : "no",
83 _max_vert
? "yes" : "no",
84 _max_horz
? "yes" : "no",
85 _fullscreen
? "yes" : "no",
86 _floating
? "yes" : "no",
87 _positioned
? "yes" : "no");
94 const otk::OBProperty
*property
= Openbox::instance
->property();
96 // these values should not be persisted across a window unmapping/mapping
97 property
->erase(_window
, otk::OBProperty::net_wm_desktop
);
98 property
->erase(_window
, otk::OBProperty::net_wm_state
);
102 void OBClient::getDesktop()
104 const otk::OBProperty
*property
= Openbox::instance
->property();
106 // defaults to the current desktop
107 _desktop
= 0; // XXX: change this to the current desktop!
109 property
->get(_window
, otk::OBProperty::net_wm_desktop
,
110 otk::OBProperty::Atom_Cardinal
,
115 void OBClient::getType()
117 const otk::OBProperty
*property
= Openbox::instance
->property();
119 _type
= (WindowType
) -1;
122 unsigned long num
= (unsigned) -1;
123 if (property
->get(_window
, otk::OBProperty::net_wm_window_type
,
124 otk::OBProperty::Atom_Atom
,
126 // use the first value that we know about in the array
127 for (unsigned long i
= 0; i
< num
; ++i
) {
129 property
->atom(otk::OBProperty::net_wm_window_type_desktop
))
130 _type
= Type_Desktop
;
132 property
->atom(otk::OBProperty::net_wm_window_type_dock
))
135 property
->atom(otk::OBProperty::net_wm_window_type_toolbar
))
136 _type
= Type_Toolbar
;
138 property
->atom(otk::OBProperty::net_wm_window_type_menu
))
141 property
->atom(otk::OBProperty::net_wm_window_type_utility
))
142 _type
= Type_Utility
;
144 property
->atom(otk::OBProperty::net_wm_window_type_splash
))
147 property
->atom(otk::OBProperty::net_wm_window_type_dialog
))
150 property
->atom(otk::OBProperty::net_wm_window_type_normal
))
152 // else if (val[i] ==
153 // property->atom(otk::OBProperty::kde_net_wm_window_type_override))
154 // mwm_decorations = 0; // prevent this window from getting any decor
155 // XXX: make this work again
160 if (_type
== (WindowType
) -1) {
162 * the window type hint was not set, which means we either classify ourself
163 * as a normal window or a dialog, depending on if we are a transient.
165 // XXX: make this code work!
167 // _type = Type_Dialog;
174 void OBClient::getArea()
176 XWindowAttributes wattrib
;
177 assert(XGetWindowAttributes(otk::OBDisplay::display
, _window
, &wattrib
));
179 _area
.setRect(wattrib
.x
, wattrib
.y
, wattrib
.width
, wattrib
.height
);
180 _border_width
= wattrib
.border_width
;
184 void OBClient::getState()
186 const otk::OBProperty
*property
= Openbox::instance
->property();
188 _modal
= _shaded
= _max_horz
= _max_vert
= _fullscreen
= _floating
= false;
190 unsigned long *state
;
191 unsigned long num
= (unsigned) -1;
193 if (property
->get(_window
, otk::OBProperty::net_wm_state
,
194 otk::OBProperty::Atom_Atom
, &num
, &state
)) {
195 for (unsigned long i
= 0; i
< num
; ++i
) {
196 if (state
[i
] == property
->atom(otk::OBProperty::net_wm_state_modal
))
199 property
->atom(otk::OBProperty::net_wm_state_shaded
))
202 property
->atom(otk::OBProperty::net_wm_state_fullscreen
))
205 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
))
208 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
))
217 void OBClient::getShaped()
221 if (otk::OBDisplay::shape()) {
225 XShapeQueryExtents(otk::OBDisplay::display
, client
.window
, &_shaped
, &foo
,
226 &foo
, &ufoo
, &ufoo
, &foo
, &foo
, &foo
, &ufoo
, &ufoo
);
232 void OBClient::updateProtocols() {
233 const otk::OBProperty
*property
= Openbox::instance
->property();
238 _focus_notify
= false;
240 if (XGetWMProtocols(otk::OBDisplay::display
, _window
, &proto
, &num_return
)) {
241 for (int i
= 0; i
< num_return
; ++i
) {
242 if (proto
[i
] == property
->atom(otk::OBProperty::wm_delete_window
)) {
243 // XXX: do shit with this! let the window close, and show a close
245 } else if (proto
[i
] == property
->atom(otk::OBProperty::wm_take_focus
))
246 // if this protocol is requested, then the window will be notified
247 // by the window manager whenever it receives focus
248 _focus_notify
= true;
255 void OBClient::updateNormalHints()
261 _gravity
= NorthWestGravity
;
263 _base_x
= _base_y
= 0;
265 _max_x
= _max_y
= INT_MAX
;
267 // get the hints from the window
268 if (XGetWMNormalHints(otk::OBDisplay::display
, _window
, &size
, &ret
)) {
269 _positioned
= (size
.flags
& (PPosition
|USPosition
));
271 if (size
.flags
& PWinGravity
)
272 _gravity
= size
.win_gravity
;
274 if (size
.flags
& PMinSize
) {
275 _min_x
= size
.min_width
;
276 _min_y
= size
.min_height
;
279 if (size
.flags
& PMaxSize
) {
280 _max_x
= size
.max_width
;
281 _max_y
= size
.max_height
;
284 if (size
.flags
& PBaseSize
) {
285 _base_x
= size
.base_width
;
286 _base_y
= size
.base_height
;
289 if (size
.flags
& PResizeInc
) {
290 _inc_x
= size
.width_inc
;
291 _inc_y
= size
.height_inc
;
297 void OBClient::updateWMHints()
301 // assume a window takes input if it doesnt specify
305 if ((hints
= XGetWMHints(otk::OBDisplay::display
, _window
)) != NULL
) {
306 if (hints
->flags
& InputHint
)
307 _can_focus
= hints
->input
;
309 if (hints
->flags
& XUrgencyHint
)
312 if (hints
->flags
& WindowGroupHint
) {
313 if (hints
->window_group
!= _group
) {
314 // XXX: remove from the old group if there was one
315 _group
= hints
->window_group
;
316 // XXX: do stuff with the group
326 void OBClient::updateTitle()
328 const otk::OBProperty
*property
= Openbox::instance
->property();
333 if (! property
->get(_window
, otk::OBProperty::net_wm_name
,
334 otk::OBProperty::utf8
, &_title
)) {
336 property
->get(_window
, otk::OBProperty::wm_name
,
337 otk::OBProperty::ascii
, &_title
);
341 _title
= _("Unnamed Window");
345 void OBClient::updateClass()
347 const otk::OBProperty
*property
= Openbox::instance
->property();
350 _app_name
= _app_class
= "";
352 otk::OBProperty::StringVect v
;
353 unsigned long num
= 2;
355 if (! property
->get(_window
, otk::OBProperty::wm_class
,
356 otk::OBProperty::ascii
, &num
, &v
))
359 if (num
> 0) _app_name
= v
[0];
360 if (num
> 1) _app_class
= v
[1];
364 void OBClient::update(const XPropertyEvent
&e
)
366 const otk::OBProperty
*property
= Openbox::instance
->property();
368 if (e
.atom
== XA_WM_NORMAL_HINTS
)
370 else if (e
.atom
== XA_WM_HINTS
)
372 else if (e
.atom
== property
->atom(otk::OBProperty::net_wm_name
) ||
373 e
.atom
== property
->atom(otk::OBProperty::wm_name
) ||
374 e
.atom
== property
->atom(otk::OBProperty::net_wm_icon_name
) ||
375 e
.atom
== property
->atom(otk::OBProperty::wm_icon_name
))
377 else if (e
.atom
== property
->atom(otk::OBProperty::wm_class
))
379 else if (e
.atom
== property
->atom(otk::OBProperty::wm_protocols
))
381 // XXX: transient for hint
386 void OBClient::setWMState(long state
)
388 if (state
== _wmstate
) return; // no change
392 // XXX: cause it to iconify
395 // XXX: cause it to uniconify
402 void OBClient::setDesktop(long target
)
405 //assert(target == 0xffffffff || target < MAX);
407 // XXX: move the window to the new desktop
412 void OBClient::setState(StateAction action
, long data1
, long data2
)
414 const otk::OBProperty
*property
= Openbox::instance
->property();
416 if (!(action
== State_Add
|| action
== State_Remove
||
417 action
== State_Toggle
))
418 return; // an invalid action was passed to the client message, ignore it
420 for (int i
= 0; i
< 2; ++i
) {
421 Atom state
= i
== 0 ? data1
: data2
;
423 if (! state
) continue;
425 // if toggling, then pick whether we're adding or removing
426 if (action
== State_Toggle
) {
427 if (state
== property
->atom(otk::OBProperty::net_wm_state_modal
))
428 action
= _modal
? State_Remove
: State_Add
;
430 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
))
431 action
= _max_vert
? State_Remove
: State_Add
;
433 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
))
434 action
= _max_horz
? State_Remove
: State_Add
;
435 else if (state
== property
->atom(otk::OBProperty::net_wm_state_shaded
))
436 action
= _shaded
? State_Remove
: State_Add
;
438 property
->atom(otk::OBProperty::net_wm_state_fullscreen
))
439 action
= _fullscreen
? State_Remove
: State_Add
;
440 else if (state
== property
->atom(otk::OBProperty::net_wm_state_floating
))
441 action
= _floating
? State_Remove
: State_Add
;
444 if (action
== State_Add
) {
445 if (state
== property
->atom(otk::OBProperty::net_wm_state_modal
)) {
446 if (_modal
) continue;
448 // XXX: give it focus if another window has focus that shouldnt now
450 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
)){
451 if (_max_vert
) continue;
453 // XXX: resize the window etc
455 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
)){
456 if (_max_horz
) continue;
458 // XXX: resize the window etc
460 property
->atom(otk::OBProperty::net_wm_state_shaded
)) {
461 if (_shaded
) continue;
463 // XXX: hide the client window
465 property
->atom(otk::OBProperty::net_wm_state_fullscreen
)) {
466 if (_fullscreen
) continue;
468 // XXX: raise the window n shit
470 property
->atom(otk::OBProperty::net_wm_state_floating
)) {
471 if (_floating
) continue;
473 // XXX: raise the window n shit
476 } else { // action == State_Remove
477 if (state
== property
->atom(otk::OBProperty::net_wm_state_modal
)) {
478 if (!_modal
) continue;
481 property
->atom(otk::OBProperty::net_wm_state_maximized_vert
)){
482 if (!_max_vert
) continue;
484 // XXX: resize the window etc
486 property
->atom(otk::OBProperty::net_wm_state_maximized_horz
)){
487 if (!_max_horz
) continue;
489 // XXX: resize the window etc
491 property
->atom(otk::OBProperty::net_wm_state_shaded
)) {
492 if (!_shaded
) continue;
494 // XXX: show the client window
496 property
->atom(otk::OBProperty::net_wm_state_fullscreen
)) {
497 if (!_fullscreen
) continue;
499 // XXX: lower the window to its proper layer
501 property
->atom(otk::OBProperty::net_wm_state_floating
)) {
502 if (!_floating
) continue;
504 // XXX: lower the window to its proper layer
511 void OBClient::update(const XClientMessageEvent
&e
)
513 if (e
.format
!= 32) return;
515 const otk::OBProperty
*property
= Openbox::instance
->property();
517 if (e
.message_type
== property
->atom(otk::OBProperty::wm_change_state
))
518 setWMState(e
.data
.l
[0]);
519 else if (e
.message_type
==
520 property
->atom(otk::OBProperty::net_wm_desktop
))
521 setDesktop(e
.data
.l
[0]);
522 else if (e
.message_type
== property
->atom(otk::OBProperty::net_wm_state
))
523 setState((StateAction
)e
.data
.l
[0], e
.data
.l
[1], e
.data
.l
[2]);
527 void OBClient::setArea(const otk::Rect
&area
)