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