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