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)