1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2 // EWMH.cc for Blackbox - an X11 Window manager
3 // Copyright (c) 2001 - 2005 Sean 'Shaleh' Perry <shaleh@debian.org>
4 // Copyright (c) 1997 - 2000, 2002 - 2005
5 //         Bradley T Hughes <bhughes at trolltech.com>
6 //
7 // Permission is hereby granted, free of charge, to any person obtaining a
8 // copy of this software and associated documentation files (the "Software"),
9 // to deal in the Software without restriction, including without limitation
10 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 // and/or sell copies of the Software, and to permit persons to whom the
12 // Software is furnished to do so, subject to the following conditions:
13 //
14 // The above copyright notice and this permission notice shall be included in
15 // all copies or substantial portions of the Software.
16 //
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 // DEALINGS IN THE SOFTWARE.
24 
25 #include "EWMH.hh"
26 
27 #include <X11/Xatom.h>
28 #include <X11/Xlib.h>
29 
30 #include <stdio.h>
31 
32 
EWMH(const Display & _display)33 bt::EWMH::EWMH(const Display &_display)
34   : display(_display)
35 {
36   const struct AtomRef {
37     const char *name;
38     Atom *atom;
39   } refs[] = {
40     { "UTF8_STRING", &utf8_string },
41     { "_NET_SUPPORTED", &net_supported },
42     { "_NET_CLIENT_LIST", &net_client_list },
43     { "_NET_CLIENT_LIST_STACKING", &net_client_list_stacking },
44     { "_NET_NUMBER_OF_DESKTOPS", &net_number_of_desktops },
45     { "_NET_DESKTOP_GEOMETRY", &net_desktop_geometry },
46     { "_NET_DESKTOP_VIEWPORT", &net_desktop_viewport },
47     { "_NET_CURRENT_DESKTOP", &net_current_desktop },
48     { "_NET_DESKTOP_NAMES", &net_desktop_names },
49     { "_NET_ACTIVE_WINDOW", &net_active_window },
50     { "_NET_WORKAREA", &net_workarea },
51     { "_NET_SUPPORTING_WM_CHECK", &net_supporting_wm_check },
52     { "_NET_VIRTUAL_ROOTS", &net_virtual_roots },
53     { "_NET_DESKTOP_LAYOUT", &net_desktop_layout },
54     { "_NET_SHOWING_DESKTOP", &net_showing_desktop },
55     { "_NET_CLOSE_WINDOW", &net_close_window },
56     { "_NET_MOVERESIZE_WINDOW", &net_moveresize_window },
57     { "_NET_WM_MOVERESIZE", &net_wm_moveresize },
58     { "_NET_RESTACK_WINDOW", &net_restack_window },
59     { "_NET_REQUEST_FRAME_EXTENTS", &net_request_frame_extents },
60     { "_NET_WM_NAME", &net_wm_name },
61     { "_NET_WM_VISIBLE_NAME", &net_wm_visible_name },
62     { "_NET_WM_ICON_NAME", &net_wm_icon_name },
63     { "_NET_WM_VISIBLE_ICON_NAME", &net_wm_visible_icon_name },
64     { "_NET_WM_DESKTOP", &net_wm_desktop },
65     { "_NET_WM_WINDOW_TYPE", &net_wm_window_type },
66     { "_NET_WM_WINDOW_TYPE_DESKTOP", &net_wm_window_type_desktop },
67     { "_NET_WM_WINDOW_TYPE_DOCK", &net_wm_window_type_dock },
68     { "_NET_WM_WINDOW_TYPE_TOOLBAR", &net_wm_window_type_toolbar },
69     { "_NET_WM_WINDOW_TYPE_MENU", &net_wm_window_type_menu },
70     { "_NET_WM_WINDOW_TYPE_UTILITY", &net_wm_window_type_utility },
71     { "_NET_WM_WINDOW_TYPE_SPLASH", &net_wm_window_type_splash },
72     { "_NET_WM_WINDOW_TYPE_DIALOG", &net_wm_window_type_dialog },
73     { "_NET_WM_WINDOW_TYPE_NORMAL", &net_wm_window_type_normal },
74     { "_NET_WM_STATE", &net_wm_state },
75     { "_NET_WM_STATE_MODAL", &net_wm_state_modal },
76     { "_NET_WM_STATE_STICKY", &net_wm_state_sticky },
77     { "_NET_WM_STATE_MAXIMIZED_VERT", &net_wm_state_maximized_vert },
78     { "_NET_WM_STATE_MAXIMIZED_HORZ", &net_wm_state_maximized_horz },
79     { "_NET_WM_STATE_SHADED", &net_wm_state_shaded },
80     { "_NET_WM_STATE_SKIP_TASKBAR", &net_wm_state_skip_taskbar },
81     { "_NET_WM_STATE_SKIP_PAGER", &net_wm_state_skip_pager },
82     { "_NET_WM_STATE_HIDDEN", &net_wm_state_hidden },
83     { "_NET_WM_STATE_FULLSCREEN", &net_wm_state_fullscreen },
84     { "_NET_WM_STATE_ABOVE", &net_wm_state_above },
85     { "_NET_WM_STATE_BELOW", &net_wm_state_below },
86     { "_NET_WM_STATE_DEMANDS_ATTENTION", &net_wm_state_demands_attention },
87     { "_NET_WM_ALLOWED_ACTIONS", &net_wm_allowed_actions },
88     { "_NET_WM_ACTION_MOVE", &net_wm_action_move },
89     { "_NET_WM_ACTION_RESIZE", &net_wm_action_resize },
90     { "_NET_WM_ACTION_MINIMIZE", &net_wm_action_minimize },
91     { "_NET_WM_ACTION_SHADE", &net_wm_action_shade },
92     { "_NET_WM_ACTION_STICK", &net_wm_action_stick },
93     { "_NET_WM_ACTION_MAXIMIZE_HORZ", &net_wm_action_maximize_horz },
94     { "_NET_WM_ACTION_MAXIMIZE_VERT", &net_wm_action_maximize_vert },
95     { "_NET_WM_ACTION_FULLSCREEN", &net_wm_action_fullscreen },
96     { "_NET_WM_ACTION_CHANGE_DESKTOP", &net_wm_action_change_desktop },
97     { "_NET_WM_ACTION_CLOSE", &net_wm_action_close },
98     { "_NET_WM_STRUT", &net_wm_strut },
99     { "_NET_WM_STRUT_PARTIAL", &net_wm_strut_partial },
100     { "_NET_WM_ICON_GEOMETRY", &net_wm_icon_geometry },
101     { "_NET_WM_ICON", &net_wm_icon },
102     { "_NET_WM_PID", &net_wm_pid },
103     { "_NET_WM_HANDLED_ICONS", &net_wm_handled_icons },
104     { "_NET_WM_USER_TIME", &net_wm_user_time },
105     { "_NET_FRAME_EXTENTS", &net_frame_extents },
106     { "_NET_WM_PING", &net_wm_ping },
107     { "_NET_WM_SYNC_REQUEST", &net_wm_sync_request }
108   };
109 
110   static const int AtomCount =
111     sizeof(refs) / (sizeof(const char *) + sizeof(Atom *));
112   char *names[AtomCount];
113   Atom atoms[AtomCount];
114 
115   for (int i = 0; i < AtomCount; ++i)
116     names[i] = const_cast<char *>(refs[i].name);
117 
118   XInternAtoms(display.XDisplay(), names, AtomCount, false, atoms);
119 
120   for (int i = 0; i < AtomCount; ++i)
121     *refs[i].atom = atoms[i];
122 }
123 
124 
125 // root window properties
126 
setSupported(Window target,Atom atoms[],unsigned int count) const127 void bt::EWMH::setSupported(Window target, Atom atoms[],
128                              unsigned int count) const {
129   setProperty(target, XA_ATOM, net_supported,
130               reinterpret_cast<unsigned char *>(atoms), count);
131 }
132 
133 
readSupported(Window target,AtomList & atoms) const134 bool bt::EWMH::readSupported(Window target, AtomList& atoms) const {
135   unsigned char* data = 0;
136   unsigned long nitems;
137   if (getListProperty(target, XA_ATOM, net_supported, &data, &nitems)) {
138     Atom* values = reinterpret_cast<Atom*>(data);
139 
140     atoms.reserve(nitems);
141     atoms.assign(values, values + nitems);
142 
143     XFree(data);
144   }
145 
146   return (!atoms.empty());
147 }
148 
149 
setClientList(Window target,WindowList & windows) const150 void bt::EWMH::setClientList(Window target, WindowList& windows) const {
151   setProperty(target, XA_WINDOW, net_client_list,
152               reinterpret_cast<unsigned char *>(&windows[0]), windows.size());
153 }
154 
155 
readClientList(Window target,WindowList & windows) const156 bool bt::EWMH::readClientList(Window target, WindowList& windows) const {
157   unsigned char* data = 0;
158   unsigned long nitems;
159   if (getListProperty(target, XA_WINDOW, net_client_list, &data, &nitems)) {
160     Window* values = reinterpret_cast<Window*>(data);
161 
162     windows.reserve(nitems);
163     windows.assign(values, values + nitems);
164 
165     XFree(data);
166   }
167 
168   return (!windows.empty());
169 }
170 
171 
setClientListStacking(Window target,WindowList & windows) const172 void bt::EWMH::setClientListStacking(Window target,
173                                       WindowList& windows) const {
174   setProperty(target, XA_WINDOW, net_client_list_stacking,
175               reinterpret_cast<unsigned char *>(&windows[0]), windows.size());
176 }
177 
178 
readClientListStacking(Window target,WindowList & windows) const179 bool bt::EWMH::readClientListStacking(Window target,
180                                        WindowList& windows) const {
181   unsigned char* data = 0;
182   unsigned long nitems;
183   if (getListProperty(target, XA_WINDOW, net_client_list_stacking,
184                       &data, &nitems)) {
185     Window* values = reinterpret_cast<Window*>(data);
186 
187     windows.reserve(nitems);
188     windows.assign(values, values + nitems);
189 
190     XFree(data);
191   }
192 
193   return (!windows.empty());
194 }
195 
196 
setNumberOfDesktops(Window target,unsigned int number) const197 void bt::EWMH::setNumberOfDesktops(Window target, unsigned int number) const {
198   const unsigned long x = number;
199   setProperty(target, XA_CARDINAL, net_number_of_desktops,
200               reinterpret_cast<const unsigned char *>(&x), 1);
201 }
202 
203 
readNumberOfDesktops(Window target,unsigned int * number) const204 bool bt::EWMH::readNumberOfDesktops(Window target,
205                                      unsigned int* number) const {
206   unsigned char* data = 0;
207   if (getProperty(target, XA_CARDINAL, net_number_of_desktops, &data)) {
208     *number =
209       static_cast<unsigned int>(*(reinterpret_cast<unsigned long *>(data)));
210 
211     XFree(data);
212     return true;
213   }
214   return false;
215 }
216 
217 
setDesktopGeometry(Window target,unsigned int width,unsigned int height) const218 void bt::EWMH::setDesktopGeometry(Window target,
219                                    unsigned int width,
220                                    unsigned int height) const {
221   const unsigned long geometry[] =
222     { static_cast<unsigned long>(width), static_cast<unsigned long> (height) };
223   setProperty(target, XA_CARDINAL, net_desktop_geometry,
224               reinterpret_cast<const unsigned char *>(geometry), 2);
225 }
226 
227 
readDesktopGeometry(Window target,unsigned int * width,unsigned int * height) const228 bool bt::EWMH::readDesktopGeometry(Window target,
229                                     unsigned int* width,
230                                     unsigned int* height) const {
231   unsigned char* data = 0;
232   unsigned long nitems;
233   if (getListProperty(target, XA_CARDINAL, net_desktop_geometry,
234                       &data, &nitems) && nitems == 2) {
235     unsigned long *values = reinterpret_cast<unsigned long *>(data);
236 
237     *width  = static_cast<unsigned int>(values[0]);
238     *height = static_cast<unsigned int>(values[1]);
239 
240     XFree(data);
241     return true;
242   }
243 
244   return false;
245 }
246 
247 
setDesktopViewport(Window target,int x,int y) const248 void bt::EWMH::setDesktopViewport(Window target, int x, int y) const {
249   const unsigned long viewport[] =
250     { static_cast<unsigned long>(x), static_cast<unsigned long>(y) };
251   setProperty(target, XA_CARDINAL, net_desktop_viewport,
252               reinterpret_cast<const unsigned char *>(viewport), 2);
253 }
254 
255 
readDesktopViewport(Window target,int * x,int * y) const256 bool bt::EWMH::readDesktopViewport(Window target, int *x, int *y) const {
257   unsigned char* data = 0;
258   unsigned long nitems;
259   if (getListProperty(target, XA_CARDINAL, net_desktop_viewport,
260                       &data, &nitems) && nitems == 2) {
261     const long * const values = reinterpret_cast<long *>(data);
262 
263     *x = static_cast<int>(values[0]);
264     *y = static_cast<int>(values[1]);
265 
266     XFree(data);
267     return true;
268   }
269 
270   return false;
271 }
272 
273 
setWorkarea(Window target,unsigned long workareas[],unsigned int count) const274 void bt::EWMH::setWorkarea(Window target, unsigned long workareas[],
275                             unsigned int count) const {
276   setProperty(target, XA_CARDINAL, net_workarea,
277               reinterpret_cast<unsigned char *>(workareas), count * 4);
278 }
279 
280 
setCurrentDesktop(Window target,unsigned int number) const281 void bt::EWMH::setCurrentDesktop(Window target, unsigned int number) const {
282   const unsigned long x = static_cast<unsigned long>(number);
283   setProperty(target, XA_CARDINAL, net_current_desktop,
284               reinterpret_cast<const unsigned char *>(&x), 1);
285 }
286 
287 
readCurrentDesktop(Window target,unsigned int * number) const288 bool bt::EWMH::readCurrentDesktop(Window target, unsigned int* number) const {
289   unsigned char* data = 0;
290   if (getProperty(target, XA_CARDINAL, net_current_desktop, &data)) {
291     *number =
292       static_cast<unsigned int>(*(reinterpret_cast<unsigned long *>(data)));
293 
294     XFree(data);
295     return true;
296   }
297   return false;
298 }
299 
300 
setDesktopNames(Window target,const std::vector<bt::ustring> & names) const301 void bt::EWMH::setDesktopNames(Window target,
302                                 const std::vector<bt::ustring> &names) const {
303   if (!hasUnicode())
304     return; // cannot convert UTF-32 to UTF-8
305 
306   std::string s;
307   std::vector<bt::ustring>::const_iterator it = names.begin();
308   const std::vector<bt::ustring>::const_iterator end = names.end();
309   for (; it != end; ++it)
310     s += toUtf8(*it) + '\0';
311 
312   XChangeProperty(display.XDisplay(), target, net_desktop_names, utf8_string,
313                   8, PropModeReplace,
314                   reinterpret_cast<const unsigned char *>(s.c_str()),
315                   s.length());
316 }
317 
318 
readDesktopNames(Window target,std::vector<bt::ustring> & names) const319 bool bt::EWMH::readDesktopNames(Window target,
320                                  std::vector<bt::ustring> &names) const {
321   if (!hasUnicode())
322     return false; // cannot convert UTF-8 to UTF-32
323 
324   unsigned char *data = 0;
325   unsigned long nitems;
326   if (getListProperty(target, utf8_string, net_desktop_names,
327                       &data, &nitems) && nitems > 0) {
328     char *tmp = reinterpret_cast<char *>(data);
329     for (unsigned int i = 0; i < nitems; ++i) {
330       if (data[i] == '\0') {
331         const std::string str(tmp, reinterpret_cast<char *>(data) + i);
332         names.push_back(toUtf32(str));
333         tmp = reinterpret_cast<char *>(data) + i + 1;
334       }
335     }
336     XFree(data);
337   }
338 
339   return (!names.empty());
340 }
341 
342 
setActiveWindow(Window target,Window data) const343 void bt::EWMH::setActiveWindow(Window target, Window data) const {
344   setProperty(target, XA_WINDOW, net_active_window,
345               reinterpret_cast<unsigned char *>(&data), 1);
346 }
347 
348 
setSupportingWMCheck(Window target,Window data) const349 void bt::EWMH::setSupportingWMCheck(Window target, Window data) const {
350   setProperty(target, XA_WINDOW, net_supporting_wm_check,
351               reinterpret_cast<unsigned char *>(&data), 1);
352 }
353 
354 
readSupportingWMCheck(Window target,Window * window) const355 bool bt::EWMH::readSupportingWMCheck(Window target, Window* window) const {
356   unsigned char* data = 0;
357   if (getProperty(target, XA_WINDOW, net_supporting_wm_check, &data)) {
358     *window = * (reinterpret_cast<Window*>(data));
359 
360     XFree(data);
361     return true;
362   }
363   return false;
364 }
365 
366 
setVirtualRoots(Window target,WindowList & windows) const367 void bt::EWMH::setVirtualRoots(Window target, WindowList &windows) const {
368   setProperty(target, XA_WINDOW, net_virtual_roots,
369               reinterpret_cast<unsigned char *>(&windows[0]), windows.size());
370 }
371 
372 
readVirtualRoots(Window target,WindowList & windows) const373 bool bt::EWMH::readVirtualRoots(Window target, WindowList &windows) const {
374   unsigned char* data = 0;
375   unsigned long nitems;
376   if (getListProperty(target, XA_WINDOW, net_virtual_roots, &data, &nitems)) {
377     Window* values = reinterpret_cast<Window*>(data);
378 
379     windows.reserve(nitems);
380     windows.assign(values, values + nitems);
381 
382     XFree(data);
383   }
384 
385   return (!windows.empty());
386 }
387 
388 
389 // application properties
390 
setWMName(Window target,const bt::ustring & name) const391 void bt::EWMH::setWMName(Window target, const bt::ustring &name) const {
392   if (!hasUnicode())
393     return; // cannot convert UTF-32 to UTF-8
394 
395   const std::string utf8 = toUtf8(name);
396   XChangeProperty(display.XDisplay(), target, net_wm_name, utf8_string,
397                   8, PropModeReplace,
398                   reinterpret_cast<const unsigned char *>(utf8.c_str()),
399                   utf8.length());
400 }
401 
402 
readWMName(Window target,bt::ustring & name) const403 bool bt::EWMH::readWMName(Window target, bt::ustring &name) const {
404   if (!hasUnicode())
405     return false; // cannot convert UTF-8 to UTF-32
406 
407   unsigned char* data = 0;
408   unsigned long nitems;
409   if (getListProperty(target, utf8_string, net_wm_name,
410                       &data, &nitems) && nitems > 0) {
411     name = toUtf32(reinterpret_cast<char*>(data));
412     XFree(data);
413   }
414 
415   return (!name.empty());
416 }
417 
418 
setWMVisibleName(Window target,const bt::ustring & name) const419 void bt::EWMH::setWMVisibleName(Window target,
420                                  const bt::ustring &name) const {
421   if (!hasUnicode())
422     return; // cannot convert UTF-32 to UTF-8
423 
424   const std::string utf8 = toUtf8(name);
425   XChangeProperty(display.XDisplay(), target, net_wm_visible_name, utf8_string,
426                   8, PropModeReplace,
427                   reinterpret_cast<const unsigned char *>(utf8.c_str()),
428                   utf8.length());
429 }
430 
431 
readWMIconName(Window target,bt::ustring & name) const432 bool bt::EWMH::readWMIconName(Window target, bt::ustring &name) const {
433   if (!hasUnicode())
434     return false; // cannot convert UTF-8 to UTF-32
435 
436   unsigned char* data = 0;
437   unsigned long nitems;
438   if (getListProperty(target, utf8_string, net_wm_icon_name,
439                       &data, &nitems) && nitems > 0) {
440     name = toUtf32(reinterpret_cast<char*>(data));
441     XFree(data);
442   }
443 
444   return (!name.empty());
445 }
446 
447 
setWMVisibleIconName(Window target,const bt::ustring & name) const448 void bt::EWMH::setWMVisibleIconName(Window target,
449                                      const bt::ustring &name) const {
450   if (!hasUnicode())
451     return; // cannot convert UTF-32 to UTF-8
452 
453   const std::string utf8 = toUtf8(name);
454   XChangeProperty(display.XDisplay(), target, net_wm_visible_icon_name, utf8_string,
455                   8, PropModeReplace,
456                   reinterpret_cast<const unsigned char *>(utf8.c_str()),
457                   utf8.length());
458 }
459 
460 
setWMDesktop(Window target,unsigned int desktop) const461 void bt::EWMH::setWMDesktop(Window target, unsigned int desktop) const {
462   const unsigned long x = desktop;
463   setProperty(target, XA_CARDINAL, net_wm_desktop,
464               reinterpret_cast<const unsigned char *>(&x), 1);
465 }
466 
467 
readWMDesktop(Window target,unsigned int & desktop) const468 bool bt::EWMH::readWMDesktop(Window target, unsigned int& desktop) const {
469   unsigned char* data = 0;
470   if (getProperty(target, XA_CARDINAL, net_wm_desktop, &data)) {
471     desktop =
472       static_cast<unsigned int>(*(reinterpret_cast<unsigned long *>(data)));
473 
474     XFree(data);
475     return true;
476   }
477   return false;
478 }
479 
480 
readWMWindowType(Window target,AtomList & types) const481 bool bt::EWMH::readWMWindowType(Window target, AtomList& types) const {
482   unsigned char* data = 0;
483   unsigned long nitems;
484   if (getListProperty(target, XA_ATOM, net_wm_window_type, &data, &nitems)) {
485     Atom* values = reinterpret_cast<Atom*>(data);
486 
487     types.reserve(nitems);
488     types.assign(values, values + nitems);
489 
490     XFree(data);
491   }
492 
493   return (!types.empty());
494 }
495 
496 
setWMState(Window target,AtomList & atoms) const497 void bt::EWMH::setWMState(Window target, AtomList& atoms) const {
498   setProperty(target, XA_ATOM, net_wm_state,
499               reinterpret_cast<unsigned char *>(&(atoms[0])), atoms.size());
500 }
501 
502 
readWMState(Window target,AtomList & states) const503 bool bt::EWMH::readWMState(Window target, AtomList& states) const {
504   unsigned char* data = 0;
505   unsigned long nitems;
506   if (getListProperty(target, XA_ATOM, net_wm_state, &data, &nitems)) {
507     Atom* values = reinterpret_cast<Atom*>(data);
508 
509     states.reserve(nitems);
510     states.assign(values, values + nitems);
511 
512     XFree(data);
513   }
514 
515   return (!states.empty());
516 }
517 
518 
setWMAllowedActions(Window target,AtomList & atoms) const519 void bt::EWMH::setWMAllowedActions(Window target, AtomList& atoms) const {
520   setProperty(target, XA_ATOM, net_wm_allowed_actions,
521               reinterpret_cast<unsigned char *>(&(atoms[0])), atoms.size());
522 }
523 
524 
readWMStrut(Window target,Strut * strut) const525 bool bt::EWMH::readWMStrut(Window target, Strut* strut) const {
526   Atom atom_return;
527   int size;
528   unsigned long nitems, bytes_left;
529   unsigned char *data;
530 
531   int ret = XGetWindowProperty(display.XDisplay(), target, net_wm_strut,
532                                0l, 4l, false,
533                                XA_CARDINAL, &atom_return, &size,
534                                &nitems, &bytes_left, &data);
535   if (ret != Success || nitems < 4)
536     return false;
537 
538   unsigned long* const values = reinterpret_cast<unsigned long*>(data);
539 
540   strut->left   = static_cast<unsigned int>(values[0]);
541   strut->right  = static_cast<unsigned int>(values[1]);
542   strut->top    = static_cast<unsigned int>(values[2]);
543   strut->bottom = static_cast<unsigned int>(values[3]);
544 
545   XFree(data);
546 
547   return true;
548 }
549 
550 
readWMStrutPartial(Window target,StrutPartial * strut) const551 bool bt::EWMH::readWMStrutPartial(Window target, StrutPartial* strut) const {
552   Atom atom_return;
553   int size;
554   unsigned long nitems, bytes_left;
555   unsigned char *data;
556 
557   int ret = XGetWindowProperty(display.XDisplay(), target, net_wm_strut_partial,
558                                0l, 12l, false,
559                                XA_CARDINAL, &atom_return, &size,
560                                &nitems, &bytes_left, &data);
561   if (ret != Success || nitems < 4)
562     return false;
563 
564   unsigned long * const values = reinterpret_cast<unsigned long *>(data);
565 
566   strut->left         = static_cast<unsigned int>(values[0]);
567   strut->right        = static_cast<unsigned int>(values[1]);
568   strut->top          = static_cast<unsigned int>(values[2]);
569   strut->bottom       = static_cast<unsigned int>(values[3]);
570   strut->left_start   = static_cast<unsigned int>(values[4]);
571   strut->left_end     = static_cast<unsigned int>(values[5]);
572   strut->right_start  = static_cast<unsigned int>(values[6]);
573   strut->right_end    = static_cast<unsigned int>(values[7]);
574   strut->top_start    = static_cast<unsigned int>(values[8]);
575   strut->top_end      = static_cast<unsigned int>(values[9]);
576   strut->bottom_start = static_cast<unsigned int>(values[10]);
577   strut->bottom_end   = static_cast<unsigned int>(values[11]);
578 
579   XFree(data);
580 
581   return true;
582 }
583 
584 
readWMIconGeometry(Window target,int & x,int & y,unsigned int & width,unsigned int & height) const585 bool bt::EWMH::readWMIconGeometry(Window target, int &x, int &y,
586                                    unsigned int &width,
587                                    unsigned int &height) const {
588   unsigned char *data = 0;
589   unsigned long nitems;
590   if (getListProperty(target, XA_CARDINAL, net_wm_icon_geometry,
591                       &data, &nitems) && nitems == 4) {
592     unsigned long *values = reinterpret_cast<unsigned long *>(data);
593 
594     x = static_cast<int>(values[0]);
595     y = static_cast<int>(values[1]);
596     width  = static_cast<unsigned int>(values[2]);
597     height = static_cast<unsigned int>(values[3]);
598 
599     XFree(data);
600     return true;
601   }
602 
603   return false;
604 }
605 
606 
readWMPid(Window target,unsigned int & pid) const607 bool bt::EWMH::readWMPid(Window target, unsigned int &pid) const {
608   unsigned char* data = 0;
609   if (getProperty(target, XA_CARDINAL, net_wm_pid, &data)) {
610     pid =
611       static_cast<unsigned int>(*(reinterpret_cast<unsigned long *>(data)));
612 
613     XFree(data);
614     return true;
615   }
616   return false;
617 }
618 
619 
readWMUserTime(Window target,Time & user_time) const620 bool bt::EWMH::readWMUserTime(Window target, Time &user_time) const {
621   unsigned char* data = 0;
622   if (getProperty(target, XA_CARDINAL, net_wm_user_time, &data)) {
623     user_time = *(reinterpret_cast<unsigned long *>(data));
624 
625     XFree(data);
626     return true;
627   }
628   return false;
629 }
630 
631 
632 // utility
633 
removeProperty(Window target,Atom atom) const634 void bt::EWMH::removeProperty(Window target, Atom atom) const {
635   XDeleteProperty(display.XDisplay(), target, atom);
636 }
637 
638 
setProperty(Window target,Atom type,Atom property,const unsigned char * data,unsigned long count) const639 void bt::EWMH::setProperty(Window target, Atom type, Atom property,
640                             const unsigned char *data,
641                             unsigned long count) const {
642   XChangeProperty(display.XDisplay(), target, property, type,
643                   32, PropModeReplace, data, count);
644 }
645 
646 
getProperty(Window target,Atom type,Atom property,unsigned char ** data) const647 bool bt::EWMH::getProperty(Window target, Atom type, Atom property,
648                             unsigned char** data) const {
649   Atom atom_return;
650   int size;
651   unsigned long nitems, bytes_left;
652 
653   int ret = XGetWindowProperty(display.XDisplay(), target, property,
654                                0l, 1l, false,
655                                type, &atom_return, &size,
656                                &nitems, &bytes_left, data);
657   if (ret != Success || nitems != 1)
658     return false;
659 
660   return true;
661 }
662 
663 
getListProperty(Window target,Atom type,Atom property,unsigned char ** data,unsigned long * count) const664 bool bt::EWMH::getListProperty(Window target, Atom type, Atom property,
665                                 unsigned char** data,
666                                 unsigned long* count) const {
667   Atom atom_return;
668   int size;
669   unsigned long nitems, bytes_left;
670 
671   int ret = XGetWindowProperty(display.XDisplay(), target, property,
672                                0l, 1l, false,
673                                type, &atom_return, &size,
674                                &nitems, &bytes_left, data);
675   if (ret != Success || nitems < 1)
676     return false;
677 
678   if (bytes_left != 0) {
679     XFree(*data);
680     unsigned long remain = ((size / 8) * nitems) + bytes_left;
681     ret = XGetWindowProperty(display.XDisplay(), target,
682                              property, 0l, remain, false,
683                              type, &atom_return, &size,
684                              &nitems, &bytes_left, data);
685     if (ret != Success)
686       return false;
687   }
688 
689   *count = nitems;
690   return true;
691 }
692 
693 
isSupportedWMWindowType(Atom atom) const694 bool bt::EWMH::isSupportedWMWindowType(Atom atom) const {
695   /*
696     the implementation looks silly I know.  You are probably thinking
697     "why not just do:
698     return (atom > net_wm_window_type && atom <= net_wm_window_type_normal)?".
699     Well the problem is it assumes the atoms were created in a contiguous
700     range. This happens to be true if we created them but could be false if we
701     were started after some EWMH app which allocated the windows in an odd
702     order.  So the following is guaranteed to work even if it looks silly and
703     requires more effort to maintain.
704   */
705   return (atom == net_wm_window_type_desktop ||
706           atom == net_wm_window_type_dock ||
707           atom == net_wm_window_type_toolbar ||
708           atom == net_wm_window_type_menu ||
709           atom == net_wm_window_type_utility ||
710           atom == net_wm_window_type_splash ||
711           atom == net_wm_window_type_dialog ||
712           atom == net_wm_window_type_normal);
713 }
714