1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2 // -- Netclient.cpp --
3 // Copyright (c) 2001 - 2003 Jason 'vanRijn' Kasper <vR at movingparts dot net>
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a
6 // copy of this software and associated documentation files (the "Software"),
7 // to deal in the Software without restriction, including without limitation
8 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 // and/or sell copies of the Software, and to permit persons to whom the
10 // Software is furnished to do so, subject to the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included in
13 // all copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 // DEALINGS IN THE SOFTWARE.
22
23 // E_O_H_VR
24
25 // Methods, ideas, implementations taken from Openbox's XAtom class *sigh*
26
27 #include "Netclient.h"
28 #include <string.h>
29
Netclient(const bt::Display & display)30 Netclient::Netclient (const bt::Display &display)
31 : bt::EWMH(display), _display(display)
32 {
33 init_icccm();
34 init_extras();
35 init_blackbox();
36 }
37
~Netclient()38 Netclient::~Netclient ()
39 {
40 }
41
init_icccm(void)42 void Netclient::init_icccm(void) {
43 char* atoms[9] = {
44 "WM_COLORMAP_WINDOWS",
45 "WM_PROTOCOLS",
46 "WM_NAME",
47 "WM_STATE",
48 "WM_CLASS",
49 "WM_CHANGE_STATE",
50 "WM_DELETE_WINDOW",
51 "WM_TAKE_FOCUS",
52 "_MOTIF_WM_HINTS"
53 };
54 Atom atoms_return[9];
55 XInternAtoms(_display.XDisplay(), atoms, 9, False, atoms_return);
56 xa_wm_colormap_windows = atoms_return[0];
57 xa_wm_protocols = atoms_return[1];
58 xa_wm_name = atoms_return[2];
59 xa_wm_state = atoms_return[3];
60 xa_wm_class = atoms_return[4];
61 xa_wm_change_state = atoms_return[5];
62 xa_wm_delete_window = atoms_return[6];
63 xa_wm_take_focus = atoms_return[7];
64 motif_wm_hints = atoms_return[8];
65
66 }
67
init_extras(void)68 void Netclient::init_extras(void) {
69 char* atoms[4] = {
70 "_OPENBOX_SHOW_ROOT_MENU",
71 "_OPENBOX_SHOW_WORKSPACE_MENU",
72 "ENLIGHTENMENT_DESKTOP",
73 "_NET_VIRTUAL_ROOTS"
74 };
75 Atom atoms_return[4];
76 XInternAtoms(_display.XDisplay(), atoms, 2, False, atoms_return);
77 openbox_show_root_menu = atoms_return[0];
78 openbox_show_workspace_menu = atoms_return[1];
79 enlightenment_desktop = atoms_return[2];
80 net_virtual_roots = atoms_return[3];
81
82 }
83
init_blackbox(void)84 void Netclient::init_blackbox(void) {
85 char* atoms[3] = {
86 "_BLACKBOX_HINTS",
87 "_BLACKBOX_ATTRIBUTES",
88 "_BLACKBOX_CHANGE_ATTRIBUTES"
89 };
90 Atom atoms_return[3];
91 XInternAtoms(_display.XDisplay(), atoms, 3, False, atoms_return);
92 blackbox_hints = atoms_return[0];
93 blackbox_attributes = atoms_return[1];
94 blackbox_change_attributes = atoms_return[2];
95
96 }
97
getWindowTitle(Window win) const98 std::string Netclient::getWindowTitle(Window win) const
99 {
100
101 std::string _title = "";
102
103 // try ewmh
104 if (! getValue(win, wmName(), utf8, _title)) {
105 // try old x stuff
106 getValue(win, XA_WM_NAME, ansi, _title);
107 }
108
109 if (_title.empty())
110 _title = "Unnamed";
111
112 return _title;
113 }
114
getDesktop(Window win) const115 unsigned int Netclient::getDesktop(Window win) const {
116 unsigned long _desktop = 0ul;
117
118 if (! getValue(win, wmDesktop(), XA_CARDINAL, _desktop))
119 _desktop = 0ul;
120
121 return static_cast<unsigned int>(_desktop);
122 }
123
124 /*
125 * Internal getValue function used by all of the typed getValue functions.
126 * Gets an property's value from a window.
127 * Returns True if the property was successfully retrieved; False if the
128 * property did not exist on the window, or has a different type/size format
129 * than the user tried to retrieve.
130 */
getValue(Window win,Atom atom,Atom type,unsigned long & nelements,unsigned char ** value,int size) const131 bool Netclient::getValue(Window win, Atom atom, Atom type,
132 unsigned long &nelements, unsigned char **value,
133 int size) const {
134 assert(win != None); assert(atom != None); assert(type != None);
135 assert(size == 8 || size == 16 || size == 32);
136 assert(nelements > 0);
137 unsigned char *c_val = 0; // value alloc'd in Xlib, must be XFree()d
138 Atom ret_type;
139 int ret_size;
140 unsigned long ret_bytes;
141 int result;
142 unsigned long maxread = nelements;
143 bool ret = False;
144 int bsize;
145
146 // try get the first element
147 result = XGetWindowProperty(_display.XDisplay(), win, atom, 0l, 1l, False,
148 AnyPropertyType, &ret_type, &ret_size,
149 &nelements, &ret_bytes, &c_val);
150 ret = (result == Success && ret_type == type && ret_size == size &&
151 nelements > 0);
152 if (ret) {
153 bsize = (size == 32) ? sizeof(long) : size/8;
154 if (ret_bytes == 0 || maxread <= nelements) {
155 // we got the whole property's value
156 *value = new unsigned char[nelements * bsize + 1];
157 memcpy(*value, c_val, nelements * bsize + 1);
158 } else {
159 // get the entire property since it is larger than one long
160 XFree(c_val);
161 // the number of longs that need to be retreived to get the property's
162 // entire value. The last + 1 is the first long that we retrieved above.
163 int remain = (ret_bytes - 1)/sizeof(long) + 1 + 1;
164 if (remain > bsize * (signed)maxread) // dont get more than the max
165 remain = bsize * (signed)maxread;
166 result = XGetWindowProperty(_display.XDisplay(), win, atom, 0l, remain, False, type,
167 &ret_type, &ret_size, &nelements, &ret_bytes,
168 &c_val);
169 ret = (result == Success && ret_type == type && ret_size == size &&
170 ret_bytes == 0);
171 /*
172 If the property has changed type/size, or has grown since our first
173 read of it, then stop here and try again. If it shrank, then this will
174 still work.
175 */
176 if (! ret)
177 return getValue(win, atom, type, maxread, value, size);
178
179 *value = new unsigned char[nelements * bsize + 1];
180 memcpy(*value, c_val, nelements * bsize + 1);
181 }
182 }
183 if (c_val) XFree(c_val);
184 return ret;
185 }
186
187
188 /*
189 * Gets a 32-bit property's value from a window.
190 */
getValue(Window win,Atom atom,Atom type,unsigned long & nelements,unsigned long ** value) const191 bool Netclient::getValue(Window win, Atom atom, Atom type,
192 unsigned long &nelements,
193 unsigned long **value) const {
194 return getValue(win, atom, type, nelements,
195 reinterpret_cast<unsigned char **>(value), 32);
196 }
197
198
199 /*
200 * Gets a single 32-bit property's value from a window.
201 */
getValue(Window win,Atom atom,Atom type,unsigned long & value) const202 bool Netclient::getValue(Window win, Atom atom, Atom type,
203 unsigned long &value) const {
204 unsigned long *temp;
205 unsigned long num = 1;
206 if (! getValue(win, atom, type, num,
207 reinterpret_cast<unsigned char **>(&temp), 32))
208 return False;
209
210 value = temp[0];
211 delete [] temp;
212 return True;
213 }
214
215
216 /*
217 * Gets an string property's value from a window.
218 */
getValue(Window win,Atom atom,StringType type,std::string & value) const219 bool Netclient::getValue(Window win, Atom atom, StringType type,
220 std::string &value) const {
221 unsigned long n = 1;
222 StringVect s;
223 if (getValue(win, atom, type, n, s)) {
224 value = s[0];
225 return True;
226 }
227 return False;
228 }
229
230
getValue(Window win,Atom atom,StringType type,unsigned long & nelements,StringVect & strings) const231 bool Netclient::getValue(Window win, Atom atom, StringType type,
232 unsigned long &nelements, StringVect &strings) const {
233 assert(win != None); assert(atom != None);
234 assert(nelements > 0);
235
236 Atom t;
237 switch (type) {
238 case ansi: t = XA_STRING; break;
239 case utf8: t = utf8String(); break;
240 default: assert(False); return False; // unhandled StringType
241 }
242
243 unsigned char *value;
244 unsigned long elements = (unsigned) -1;
245 if (!getValue(win, atom, t, elements, &value, 8) || elements < 1)
246 return False;
247
248 std::string s(reinterpret_cast<char *>(value), elements);
249 delete [] value;
250
251 std::string::const_iterator it = s.begin(), end = s.end();
252 unsigned long num = 0;
253 while(num < nelements) {
254 std::string::const_iterator tmp = it; // current string.begin()
255 it = std::find(tmp, end, '\0'); // look for null between tmp and end
256 strings.push_back(std::string(tmp, it)); // s[tmp:it)
257 ++num;
258 if (it == end) break;
259 ++it;
260 if (it == end) break;
261 }
262
263 nelements = num;
264
265 return True;
266 }
267
268
269 /*
270 * Removes a property entirely from a window.
271 */
eraseValue(Window win,Atom atom) const272 void Netclient::eraseValue(Window win, Atom atom) const {
273 XDeleteProperty(_display.XDisplay(), win, atom);
274 }
275
276
sendClientMessage(Window target,Atom type,Window about,long data,long data1,long data2,long data3,long data4) const277 void Netclient::sendClientMessage(Window target, Atom type, Window about,
278 long data, long data1, long data2,
279 long data3, long data4) const {
280 assert(target != None);
281
282 XEvent e;
283 e.xclient.type = ClientMessage;
284 e.xclient.format = 32;
285 e.xclient.message_type = type;
286 e.xclient.window = about;
287 e.xclient.data.l[0] = data;
288 e.xclient.data.l[1] = data1;
289 e.xclient.data.l[2] = data2;
290 e.xclient.data.l[3] = data3;
291 e.xclient.data.l[4] = data4;
292
293 XSendEvent(_display.XDisplay(), target, False,
294 SubstructureRedirectMask | SubstructureNotifyMask,
295 &e);
296 }
297
isAtomSupported(Window win,Atom atom) const298 bool Netclient::isAtomSupported(Window win, Atom atom) const {
299
300 bool supported = False;
301
302 bt::EWMH::AtomList atoms;
303
304 if (readSupported(win, atoms) && atoms.size() > 0) {
305 if (std::find(atoms.begin(), atoms.end(), atom) != atoms.end()) {
306 supported = True;
307 }
308 }
309
310 return supported;
311 }
312
getNetVirtualRootList(Window win)313 Window * Netclient::getNetVirtualRootList(Window win) {
314
315 Atom type_ret;
316 int format_ret;
317 unsigned long nitems_ret, unused;
318 unsigned char *data_ret;
319 Window *winsReturn = 0;
320
321 int e = XGetWindowProperty(_display.XDisplay(), win, xaNetVirtualRoots(),
322 0, 0, False, XA_WINDOW, &type_ret,
323 &format_ret, &nitems_ret, &unused, &data_ret);
324
325 if (e == Success && type_ret == XA_WINDOW && format_ret == 32) {
326 Window *wins = (Window *) data_ret;
327
328 winsReturn = new Window[nitems_ret];
329 while (nitems_ret--) winsReturn[nitems_ret] = wins[nitems_ret];
330 }
331
332 if ( data_ret )
333 XFree(data_ret);
334
335 return winsReturn;
336
337 }
338