fix compiling with the new strut (new namespace)
[mikachu/openbox.git] / src / client.cc
1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2
3 #include "client.hh"
4 #include "screen.hh"
5 #include "openbox.hh"
6 #include "otk/display.hh"
7 #include "otk/property.hh"
8
9 extern "C" {
10 #include <X11/Xlib.h>
11 #include <X11/Xutil.h>
12
13 #include <assert.h>
14
15 #include "gettext.h"
16 #define _(str) gettext(str)
17 }
18
19 namespace ob {
20
21 OBClient::OBClient(Window window)
22   : _window(window)
23 {
24   assert(window);
25
26   // initialize vars to false/invalid values
27   _group = 0;
28   _gravity = _base_x = _base_y = _inc_x = _inc_y = _max_x = _max_y = _min_x =
29     _min_y = -1;
30   _state = -1;
31   _type = Type_Normal;
32   _desktop = 0xffffffff - 1;
33   _can_focus = _urgent = _focus_notify = _shaped = _modal = _shaded =
34     _max_horz = _max_vert = _fullscreen = _floating = false;
35   
36   
37   // update EVERYTHING the first time!!
38 }
39
40 OBClient::~OBClient()
41 {
42 }
43
44
45 void OBClient::updateNormalHints()
46 {
47   XSizeHints size;
48   long ret;
49
50   // defaults
51   _gravity = NorthWestGravity;
52   _inc_x = _inc_y = 1;
53   _base_x = _base_y = 0;
54
55   // get the hints from the window
56   if (XGetWMNormalHints(otk::OBDisplay::display, _window, &size, &ret)) {
57     if (size.flags & PWinGravity)
58       _gravity = size.win_gravity;
59     if (size.flags & PBaseSize) {
60       _base_x = size.base_width;
61       _base_y = size.base_height;
62     }
63     if (size.flags & PResizeInc) {
64       _inc_x = size.width_inc;
65       _inc_y = size.height_inc;
66     }
67   }
68 }
69
70
71 void OBClient::updateWMHints()
72 {
73   XWMHints *hints;
74
75   // assume a window takes input if it doesnt specify
76   _can_focus = true;
77   _urgent = false;
78   
79   if ((hints = XGetWMHints(otk::OBDisplay::display, _window)) != NULL) {
80     if (hints->flags & InputHint)
81       _can_focus = hints->input;
82     if (hints->flags & XUrgencyHint)
83       _urgent = true;
84     if (hints->flags & WindowGroupHint)
85       if (hints->window_group != _group) {
86         // XXX: remove from the old group if there was one
87         _group = hints->window_group;
88         // XXX: do stuff with the group
89       }
90     XFree(hints);
91   }
92 }
93
94
95 void OBClient::updateTitle()
96 {
97   const otk::OBProperty *property = Openbox::instance->property();
98
99   _title = "";
100   
101   // try netwm
102   if (! property->get(_window, otk::OBProperty::net_wm_name,
103                       otk::OBProperty::utf8, &_title)) {
104     // try old x stuff
105     property->get(_window, otk::OBProperty::wm_name,
106                   otk::OBProperty::ascii, &_title);
107   }
108
109   if (_title.empty())
110     _title = _("Unnamed Window");
111 }
112
113
114 void OBClient::updateClass()
115 {
116   const otk::OBProperty *property = Openbox::instance->property();
117
118   // set the defaults
119   _app_name = _app_class = "";
120
121   otk::OBProperty::StringVect v;
122   unsigned long num = 2;
123
124   if (! property->get(_window, otk::OBProperty::wm_class,
125                       otk::OBProperty::ascii, &num, &v))
126     return;
127
128   if (num > 0) _app_name = v[0];
129   if (num > 1) _app_class = v[1];
130 }
131
132
133 void OBClient::update(const XPropertyEvent &e)
134 {
135   const otk::OBProperty *property = Openbox::instance->property();
136
137   if (e.atom == XA_WM_NORMAL_HINTS)
138     updateNormalHints();
139   else if (e.atom == XA_WM_HINTS)
140     updateWMHints();
141   else if (e.atom == property->atom(otk::OBProperty::net_wm_name) ||
142            e.atom == property->atom(otk::OBProperty::wm_name) ||
143            e.atom == property->atom(otk::OBProperty::net_wm_icon_name) ||
144            e.atom == property->atom(otk::OBProperty::wm_icon_name))
145     updateTitle();
146   else if (e.atom == property->atom(otk::OBProperty::wm_class))
147     updateClass();
148 }
149
150
151 void OBClient::setWMState(long state)
152 {
153   if (state == _state) return; // no change
154   
155   switch (state) {
156   case IconicState:
157     // XXX: cause it to iconify
158     break;
159   case NormalState:
160     // XXX: cause it to uniconify
161     break;
162   }
163   _state = state;
164 }
165
166
167 void OBClient::setDesktop(long target)
168 {
169   assert(target >= 0);
170   //assert(target == 0xffffffff || target < MAX);
171   
172   // XXX: move the window to the new desktop
173   _desktop = target;
174 }
175
176
177 void OBClient::setState(StateAction action, long data1, long data2)
178 {
179   const otk::OBProperty *property = Openbox::instance->property();
180
181   if (!(action == State_Add || action == State_Remove ||
182         action == State_Toggle))
183     return; // an invalid action was passed to the client message, ignore it
184
185   for (int i = 0; i < 2; ++i) {
186     Atom state = i == 0 ? data1 : data2;
187     
188     if (! state) continue;
189
190     // if toggling, then pick whether we're adding or removing
191     if (action == State_Toggle) {
192       if (state == property->atom(otk::OBProperty::net_wm_state_modal))
193         action = _modal ? State_Remove : State_Add;
194       else if (state ==
195                property->atom(otk::OBProperty::net_wm_state_maximized_vert))
196         action = _max_vert ? State_Remove : State_Add;
197       else if (state ==
198                property->atom(otk::OBProperty::net_wm_state_maximized_horz))
199         action = _max_horz ? State_Remove : State_Add;
200       else if (state == property->atom(otk::OBProperty::net_wm_state_shaded))
201         action = _shaded ? State_Remove : State_Add;
202       else if (state ==
203                property->atom(otk::OBProperty::net_wm_state_fullscreen))
204         action = _fullscreen ? State_Remove : State_Add;
205       else if (state == property->atom(otk::OBProperty::net_wm_state_floating))
206         action = _floating ? State_Remove : State_Add;
207     }
208     
209     if (action == State_Add) {
210       if (state == property->atom(otk::OBProperty::net_wm_state_modal)) {
211         if (_modal) continue;
212         _modal = true;
213         // XXX: give it focus if another window has focus that shouldnt now
214       } else if (state ==
215                  property->atom(otk::OBProperty::net_wm_state_maximized_vert)){
216         if (_max_vert) continue;
217         _max_vert = true;
218         // XXX: resize the window etc
219       } else if (state ==
220                  property->atom(otk::OBProperty::net_wm_state_maximized_horz)){
221         if (_max_horz) continue;
222         _max_horz = true;
223         // XXX: resize the window etc
224       } else if (state ==
225                  property->atom(otk::OBProperty::net_wm_state_shaded)) {
226         if (_shaded) continue;
227         _shaded = true;
228         // XXX: hide the client window
229       } else if (state ==
230                  property->atom(otk::OBProperty::net_wm_state_fullscreen)) {
231         if (_fullscreen) continue;
232         _fullscreen = true;
233         // XXX: raise the window n shit
234       } else if (state ==
235                  property->atom(otk::OBProperty::net_wm_state_floating)) {
236         if (_floating) continue;
237         _floating = true;
238         // XXX: raise the window n shit
239       }
240
241     } else { // action == State_Remove
242       if (state == property->atom(otk::OBProperty::net_wm_state_modal)) {
243         if (!_modal) continue;
244         _modal = false;
245       } else if (state ==
246                  property->atom(otk::OBProperty::net_wm_state_maximized_vert)){
247         if (!_max_vert) continue;
248         _max_vert = false;
249         // XXX: resize the window etc
250       } else if (state ==
251                  property->atom(otk::OBProperty::net_wm_state_maximized_horz)){
252         if (!_max_horz) continue;
253         _max_horz = false;
254         // XXX: resize the window etc
255       } else if (state ==
256                  property->atom(otk::OBProperty::net_wm_state_shaded)) {
257         if (!_shaded) continue;
258         _shaded = false;
259         // XXX: show the client window
260       } else if (state ==
261                  property->atom(otk::OBProperty::net_wm_state_fullscreen)) {
262         if (!_fullscreen) continue;
263         _fullscreen = false;
264         // XXX: lower the window to its proper layer
265       } else if (state ==
266                  property->atom(otk::OBProperty::net_wm_state_floating)) {
267         if (!_floating) continue;
268         _floating = false;
269         // XXX: lower the window to its proper layer
270       }
271     }
272   }
273 }
274
275
276 void OBClient::update(const XClientMessageEvent &e)
277 {
278   if (e.format != 32) return;
279
280   const otk::OBProperty *property = Openbox::instance->property();
281   
282   if (e.message_type == property->atom(otk::OBProperty::wm_change_state))
283     setWMState(e.data.l[0]);
284   else if (e.message_type ==
285              property->atom(otk::OBProperty::net_wm_desktop))
286     setDesktop(e.data.l[0]);
287   else if (e.message_type == property->atom(otk::OBProperty::net_wm_state))
288     setState((StateAction)e.data.l[0], e.data.l[1], e.data.l[2]);
289 }
290
291 }