1 /*
2 * Copyright (C) 2004-2021 Kim Woelders
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to
6 * deal in the Software without restriction, including without limitation the
7 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 * sell copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies of the Software, its documentation and marketing & publicity
13 * materials, and acknowledgment shall be given in the documentation, materials
14 * and software packages that this Software was used.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23 #include "config.h"
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <X11/Xatom.h>
30 #include <X11/Xlib.h>
31 #include <X11/Xutil.h>
32
33 /* Window property change actions (must match _NET_WM_STATE_... ones) */
34 #define EX_PROP_LIST_REMOVE 0
35 #define EX_PROP_LIST_ADD 1
36 #define EX_PROP_LIST_TOGGLE 2
37
38 #include "xprop.h"
39 #include "xwin.h"
40
41 #define _ex_disp disp
42
43 /*
44 * General stuff
45 */
46
47 EX_Atom
ex_atom_get(const char * name)48 ex_atom_get(const char *name)
49 {
50 return XInternAtom(_ex_disp, name, False);
51 }
52
53 void
ex_atoms_get(const char * const * names,unsigned int num,EX_Atom * atoms)54 ex_atoms_get(const char *const *names, unsigned int num, EX_Atom * atoms)
55 {
56 #if SIZEOF_INT == SIZEOF_LONG
57 XInternAtoms(_ex_disp, (char **)names, num, False, (Atom *) atoms);
58 #else
59 unsigned int i;
60 Atom *_atoms;
61
62 _atoms = EMALLOC(Atom, num);
63 if (!_atoms)
64 return;
65
66 XInternAtoms(_ex_disp, (char **)names, num, False, _atoms);
67 for (i = 0; i < num; i++)
68 atoms[i] = _atoms[i];
69
70 Efree(_atoms);
71 #endif
72 }
73
74 /*
75 * Send client message (format 32)
76 */
77 int
ex_client_message32_send(EX_Window win,EX_Atom type,unsigned int mask,unsigned int d0,unsigned int d1,unsigned int d2,unsigned int d3,unsigned int d4)78 ex_client_message32_send(EX_Window win, EX_Atom type,
79 unsigned int mask,
80 unsigned int d0, unsigned int d1,
81 unsigned int d2, unsigned int d3, unsigned int d4)
82 {
83 XEvent xev;
84
85 xev.xclient.type = ClientMessage;
86 xev.xclient.window = win;
87 xev.xclient.message_type = type;
88 xev.xclient.format = 32;
89 xev.xclient.data.l[0] = d0;
90 xev.xclient.data.l[1] = d1;
91 xev.xclient.data.l[2] = d2;
92 xev.xclient.data.l[3] = d3;
93 xev.xclient.data.l[4] = d4;
94
95 return XSendEvent(_ex_disp, win, False, mask, &xev);
96 }
97
98 /*
99 * Set size 32 item (array) property
100 */
101 static void
_ex_window_prop32_set(EX_Window win,EX_Atom atom,EX_Atom type,const unsigned int * val,int num)102 _ex_window_prop32_set(EX_Window win, EX_Atom atom,
103 EX_Atom type, const unsigned int *val, int num)
104 {
105 #if SIZEOF_INT == SIZEOF_LONG
106 XChangeProperty(_ex_disp, win, atom, type, 32, PropModeReplace,
107 (unsigned char *)val, num);
108 #else
109 unsigned long *pl;
110 int i;
111
112 pl = EMALLOC(unsigned long, num);
113
114 if (!pl)
115 return;
116 for (i = 0; i < num; i++)
117 pl[i] = val[i];
118 XChangeProperty(_ex_disp, win, atom, type, 32, PropModeReplace,
119 (unsigned char *)pl, num);
120 Efree(pl);
121 #endif
122 }
123
124 /*
125 * Get size 32 item (array) property
126 *
127 * If the property was successfully fetched the number of items stored in
128 * val is returned, otherwise -1 is returned.
129 * The returned array must be freed with free().
130 * Note: Return value 0 means that the property exists but has no elements.
131 */
132 static int
_ex_window_prop32_list_get(EX_Window win,EX_Atom atom,EX_Atom type,unsigned int ** val,int num)133 _ex_window_prop32_list_get(EX_Window win, EX_Atom atom,
134 EX_Atom type, unsigned int **val, int num)
135 {
136 unsigned char *prop_ret;
137 Atom type_ret;
138 unsigned long bytes_after, num_ret;
139 int format_ret;
140 unsigned int *lst;
141 int i;
142
143 prop_ret = NULL;
144 if (XGetWindowProperty(_ex_disp, win, atom, 0, 0x7fffffff, False,
145 type, &type_ret, &format_ret, &num_ret,
146 &bytes_after, &prop_ret) != Success)
147 return -1;
148
149 if (type_ret != type || format_ret != 32)
150 {
151 num = -1;
152 }
153 else if (num_ret == 0 || !prop_ret)
154 {
155 num = 0;
156 }
157 else
158 {
159 if (num >= 0)
160 {
161 if ((int)num_ret < num)
162 num = (int)num_ret;
163 lst = *val;
164 }
165 else
166 {
167 num = (int)num_ret;
168 lst = EMALLOC(unsigned int, num);
169
170 *val = lst;
171 if (!lst)
172 return 0;
173 }
174 for (i = 0; i < num; i++)
175 lst[i] = ((unsigned long *)prop_ret)[i];
176 }
177 if (prop_ret)
178 XFree(prop_ret);
179
180 return num;
181 }
182
183 void
ex_window_prop_del(EX_Window win,EX_Atom atom)184 ex_window_prop_del(EX_Window win, EX_Atom atom)
185 {
186 XDeleteProperty(_ex_disp, win, atom);
187 }
188
189 /*
190 * Set CARD32 (array) property
191 */
192 void
ex_window_prop_card32_set(EX_Window win,EX_Atom atom,const unsigned int * val,unsigned int num)193 ex_window_prop_card32_set(EX_Window win, EX_Atom atom,
194 const unsigned int *val, unsigned int num)
195 {
196 _ex_window_prop32_set(win, atom, XA_CARDINAL, val, (int)num);
197 }
198
199 /*
200 * Get CARD32 (array) property
201 *
202 * At most len items are returned in val.
203 * If the property was successfully fetched the number of items stored in
204 * val is returned, otherwise -1 is returned.
205 * Note: Return value 0 means that the property exists but has no elements.
206 */
207 int
ex_window_prop_card32_get(EX_Window win,EX_Atom atom,unsigned int * val,unsigned int len)208 ex_window_prop_card32_get(EX_Window win, EX_Atom atom,
209 unsigned int *val, unsigned int len)
210 {
211 return _ex_window_prop32_list_get(win, atom, XA_CARDINAL, &val, (int)len);
212 }
213
214 /*
215 * Get CARD32 (array) property of any length
216 *
217 * If the property was successfully fetched the number of items stored in
218 * val is returned, otherwise -1 is returned.
219 * Note: Return value 0 means that the property exists but has no elements.
220 */
221 int
ex_window_prop_card32_list_get(EX_Window win,EX_Atom atom,unsigned int ** plst)222 ex_window_prop_card32_list_get(EX_Window win, EX_Atom atom, unsigned int **plst)
223 {
224 return _ex_window_prop32_list_get(win, atom, XA_CARDINAL, plst, -1);
225 }
226
227 /*
228 * Set simple string list property
229 */
230 void
ex_window_prop_string_list_set(EX_Window win,EX_Atom atom,char ** lst,int num)231 ex_window_prop_string_list_set(EX_Window win, EX_Atom atom, char **lst, int num)
232 {
233 XTextProperty xtp;
234
235 if (XmbTextListToTextProperty(_ex_disp, lst, num,
236 XStdICCTextStyle, &xtp) != Success)
237 return;
238 XSetTextProperty(_ex_disp, win, &xtp, atom);
239 XFree(xtp.value);
240 }
241
242 /*
243 * Get simple string list property
244 *
245 * If the property was successfully fetched the number of items stored in
246 * lst is returned, otherwise -1 is returned.
247 * Note: Return value 0 means that the property exists but has no elements.
248 */
249 int
ex_window_prop_string_list_get(EX_Window win,EX_Atom atom,char *** plst)250 ex_window_prop_string_list_get(EX_Window win, EX_Atom atom, char ***plst)
251 {
252 char **pstr = NULL;
253 XTextProperty xtp;
254 int i, items;
255 char **list;
256 Status s;
257
258 *plst = NULL;
259
260 if (!XGetTextProperty(_ex_disp, win, &xtp, atom))
261 return -1;
262
263 if (xtp.format == 8)
264 {
265 s = XmbTextPropertyToTextList(_ex_disp, &xtp, &list, &items);
266 if (s == Success)
267 {
268 if (items > 0)
269 {
270 pstr = EMALLOC(char *, items);
271
272 if (!pstr)
273 goto done;
274 for (i = 0; i < items; i++)
275 pstr[i] = (list[i] && (*list[i] || i < items - 1)) ?
276 Estrdup(list[i]) : NULL;
277 }
278 if (list)
279 XFreeStringList(list);
280 goto done;
281 }
282 }
283
284 /* Bad format or XmbTextPropertyToTextList failed - Now what? */
285 items = 1;
286 pstr = EMALLOC(char *, 1);
287
288 if (!pstr)
289 goto done;
290 pstr[0] = (xtp.value) ? Estrdup((char *)xtp.value) : NULL;
291
292 done:
293 XFree(xtp.value);
294
295 *plst = pstr;
296 if (!pstr)
297 items = 0;
298 return items;
299 }
300
301 /*
302 * Set simple string property
303 */
304 void
ex_window_prop_string_set(EX_Window win,EX_Atom atom,const char * str)305 ex_window_prop_string_set(EX_Window win, EX_Atom atom, const char *str)
306 {
307 ex_window_prop_string_list_set(win, atom, (char **)(&str), 1);
308 }
309
310 /*
311 * Get simple string property
312 */
313 char *
ex_window_prop_string_get(EX_Window win,EX_Atom atom)314 ex_window_prop_string_get(EX_Window win, EX_Atom atom)
315 {
316 XTextProperty xtp;
317 char *str;
318 int items;
319 char **list;
320 Status s;
321
322 if (!XGetTextProperty(_ex_disp, win, &xtp, atom))
323 return NULL;
324
325 if (xtp.format == 8)
326 {
327 s = XmbTextPropertyToTextList(_ex_disp, &xtp, &list, &items);
328 if ((s == Success) && (items > 0))
329 {
330 str = (*list) ? Estrdup(*list) : NULL;
331 XFreeStringList(list);
332 }
333 else
334 str = (xtp.value) ? Estrdup((char *)xtp.value) : NULL;
335 }
336 else
337 str = (xtp.value) ? Estrdup((char *)xtp.value) : NULL;
338
339 XFree(xtp.value);
340
341 return str;
342 }
343
344 /*
345 * Set UTF-8 string property
346 */
347 static void
_ex_window_prop_string_utf8_set(EX_Window win,EX_Atom atom,const char * str)348 _ex_window_prop_string_utf8_set(EX_Window win, EX_Atom atom, const char *str)
349 {
350 XChangeProperty(_ex_disp, win, atom, ea_m.UTF8_STRING, 8,
351 PropModeReplace, (unsigned char *)str, strlen(str));
352 }
353
354 /*
355 * Get UTF-8 string property
356 */
357 static char *
_ex_window_prop_string_utf8_get(EX_Window win,EX_Atom atom)358 _ex_window_prop_string_utf8_get(EX_Window win, EX_Atom atom)
359 {
360 char *str;
361 unsigned char *prop_ret;
362 Atom type_ret;
363 unsigned long bytes_after, num_ret;
364 int format_ret;
365
366 str = NULL;
367 prop_ret = NULL;
368 XGetWindowProperty(_ex_disp, win, atom, 0, 0x7fffffff, False,
369 ea_m.UTF8_STRING, &type_ret,
370 &format_ret, &num_ret, &bytes_after, &prop_ret);
371 if (prop_ret && num_ret > 0 && format_ret == 8)
372 {
373 str = EMALLOC(char, num_ret + 1);
374
375 if (str)
376 {
377 memcpy(str, prop_ret, num_ret);
378 str[num_ret] = '\0';
379 }
380 }
381 if (prop_ret)
382 XFree(prop_ret);
383
384 return str;
385 }
386
387 /*
388 * Set X ID (array) property
389 */
390 void
ex_window_prop_xid_set(EX_Window win,EX_Atom atom,EX_Atom type,const EX_ID * lst,unsigned int num)391 ex_window_prop_xid_set(EX_Window win, EX_Atom atom, EX_Atom type,
392 const EX_ID * lst, unsigned int num)
393 {
394 _ex_window_prop32_set(win, atom, type, lst, (int)num);
395 }
396
397 /*
398 * Get X ID (array) property
399 *
400 * At most len items are returned in val.
401 * If the property was successfully fetched the number of items stored in
402 * val is returned, otherwise -1 is returned.
403 * Note: Return value 0 means that the property exists but has no elements.
404 */
405 int
ex_window_prop_xid_get(EX_Window win,EX_Atom atom,EX_Atom type,EX_ID * lst,unsigned int len)406 ex_window_prop_xid_get(EX_Window win, EX_Atom atom, EX_Atom type,
407 EX_ID * lst, unsigned int len)
408 {
409 return _ex_window_prop32_list_get(win, atom, type, &lst, (int)len);
410 }
411
412 /*
413 * Get X ID (array) property
414 *
415 * If the property was successfully fetched the number of items stored in
416 * val is returned, otherwise -1 is returned.
417 * The returned array must be freed with free().
418 * Note: Return value 0 means that the property exists but has no elements.
419 */
420 int
ex_window_prop_xid_list_get(EX_Window win,EX_Atom atom,EX_Atom type,EX_ID ** val)421 ex_window_prop_xid_list_get(EX_Window win, EX_Atom atom,
422 EX_Atom type, EX_ID ** val)
423 {
424 return _ex_window_prop32_list_get(win, atom, type, val, -1);
425 }
426
427 /*
428 * Remove/add/toggle X ID list item.
429 */
430 void
ex_window_prop_xid_list_change(EX_Window win,EX_Atom atom,EX_Atom type,EX_ID item,int op)431 ex_window_prop_xid_list_change(EX_Window win, EX_Atom atom,
432 EX_Atom type, EX_ID item, int op)
433 {
434 EX_ID *lst, *lst_r;
435 int i, num;
436
437 lst = NULL;
438 num = ex_window_prop_xid_list_get(win, atom, type, &lst);
439 if (num < 0)
440 return; /* Error - assuming invalid window */
441
442 /* Is it there? */
443 for (i = 0; i < num; i++)
444 {
445 if (lst[i] == item)
446 break;
447 }
448
449 if (i < num)
450 {
451 /* Was in list */
452 if (op == EX_PROP_LIST_ADD)
453 goto done;
454 /* Remove it */
455 num--;
456 for (; i < num; i++)
457 lst[i] = lst[i + 1];
458 }
459 else
460 {
461 /* Was not in list */
462 if (op == EX_PROP_LIST_REMOVE)
463 goto done;
464 /* Add it */
465 num++;
466 lst_r = EREALLOC(EX_ID, lst, num);
467 if (!lst_r)
468 goto done;
469 lst = lst_r;
470 lst[i] = item;
471 }
472
473 ex_window_prop_xid_set(win, atom, type, lst, num);
474
475 done:
476 Efree(lst);
477 }
478
479 /*
480 * Set Atom (array) property
481 */
482 void
ex_window_prop_atom_set(EX_Window win,EX_Atom atom,const EX_Atom * lst,unsigned int num)483 ex_window_prop_atom_set(EX_Window win, EX_Atom atom,
484 const EX_Atom * lst, unsigned int num)
485 {
486 ex_window_prop_xid_set(win, atom, XA_ATOM, lst, num);
487 }
488
489 /*
490 * Get Atom (array) property
491 *
492 * At most len items are returned in val.
493 * If the property was successfully fetched the number of items stored in
494 * val is returned, otherwise -1 is returned.
495 * Note: Return value 0 means that the property exists but has no elements.
496 */
497 int
ex_window_prop_atom_get(EX_Window win,EX_Atom atom,EX_Atom * lst,unsigned int len)498 ex_window_prop_atom_get(EX_Window win, EX_Atom atom,
499 EX_Atom * lst, unsigned int len)
500 {
501 return ex_window_prop_xid_get(win, atom, XA_ATOM, lst, len);
502 }
503
504 /*
505 * Get Atom (array) property
506 *
507 * If the property was successfully fetched the number of items stored in
508 * val is returned, otherwise -1 is returned.
509 * The returned array must be freed with free().
510 * Note: Return value 0 means that the property exists but has no elements.
511 */
512 int
ex_window_prop_atom_list_get(EX_Window win,EX_Atom atom,EX_Atom ** plst)513 ex_window_prop_atom_list_get(EX_Window win, EX_Atom atom, EX_Atom ** plst)
514 {
515 return ex_window_prop_xid_list_get(win, atom, XA_ATOM, plst);
516 }
517
518 /*
519 * Remove/add/toggle atom list item.
520 */
521 void
ex_window_prop_atom_list_change(EX_Window win,EX_Atom atom,EX_Atom item,int op)522 ex_window_prop_atom_list_change(EX_Window win, EX_Atom atom,
523 EX_Atom item, int op)
524 {
525 ex_window_prop_xid_list_change(win, atom, XA_ATOM, item, op);
526 }
527
528 /*
529 * Set Window (array) property
530 */
531 void
ex_window_prop_window_set(EX_Window win,EX_Atom atom,const EX_Window * lst,unsigned int num)532 ex_window_prop_window_set(EX_Window win, EX_Atom atom,
533 const EX_Window * lst, unsigned int num)
534 {
535 ex_window_prop_xid_set(win, atom, XA_WINDOW, lst, num);
536 }
537
538 /*
539 * Get Window (array) property
540 *
541 * At most len items are returned in val.
542 * If the property was successfully fetched the number of items stored in
543 * val is returned, otherwise -1 is returned.
544 * Note: Return value 0 means that the property exists but has no elements.
545 */
546 int
ex_window_prop_window_get(EX_Window win,EX_Atom atom,EX_Window * lst,unsigned int len)547 ex_window_prop_window_get(EX_Window win, EX_Atom atom,
548 EX_Window * lst, unsigned int len)
549 {
550 return ex_window_prop_xid_get(win, atom, XA_WINDOW, lst, len);
551 }
552
553 /*
554 * Get Window (array) property
555 *
556 * If the property was successfully fetched the number of items stored in
557 * val is returned, otherwise -1 is returned.
558 * The returned array must be freed with free().
559 * Note: Return value 0 means that the property exists but has no elements.
560 */
561 int
ex_window_prop_window_list_get(EX_Window win,EX_Atom atom,EX_Window ** plst)562 ex_window_prop_window_list_get(EX_Window win, EX_Atom atom, EX_Window ** plst)
563 {
564 return ex_window_prop_xid_list_get(win, atom, XA_WINDOW, plst);
565 }
566
567 #define S_ATOM_COUNT(s) (sizeof(s) / sizeof(EX_Atom))
568
569 /*
570 * Misc atom stuff
571 */
572
573 static const char *const ea_m_names[] = {
574 #define DEFINE_ATOM_MISC(a) #a,
575 #include "xpropdefs.h"
576 #undef DEFINE_ATOM_MISC
577 };
578
579 e_atoms_misc_t ea_m;
580
581 void
ex_atoms_init(void)582 ex_atoms_init(void)
583 {
584 ex_atoms_get(ea_m_names, E_ARRAY_SIZE(ea_m_names), (EX_Atom *) & ea_m);
585 }
586
587 /*
588 * ICCCM stuff
589 */
590
591 static const char *const ea_i_names[] = {
592 #define DEFINE_ATOM_ICCCM(a) #a,
593 #include "xpropdefs.h"
594 #undef DEFINE_ATOM_ICCCM
595 };
596
597 e_atoms_icccm_t ea_i;
598
599 void
ex_icccm_init(void)600 ex_icccm_init(void)
601 {
602 ex_atoms_get(ea_i_names, E_ARRAY_SIZE(ea_i_names), (EX_Atom *) & ea_i);
603 }
604
605 static void
ex_icccm_state_set(EX_Window win,unsigned int state)606 ex_icccm_state_set(EX_Window win, unsigned int state)
607 {
608 unsigned long c[2];
609
610 c[0] = state;
611 c[1] = 0;
612 XChangeProperty(_ex_disp, win, ea_i.WM_STATE, ea_i.WM_STATE,
613 32, PropModeReplace, (unsigned char *)c, 2);
614 }
615
616 void
ex_icccm_state_set_iconic(EX_Window win)617 ex_icccm_state_set_iconic(EX_Window win)
618 {
619 ex_icccm_state_set(win, IconicState);
620 }
621
622 void
ex_icccm_state_set_normal(EX_Window win)623 ex_icccm_state_set_normal(EX_Window win)
624 {
625 ex_icccm_state_set(win, NormalState);
626 }
627
628 void
ex_icccm_state_set_withdrawn(EX_Window win)629 ex_icccm_state_set_withdrawn(EX_Window win)
630 {
631 ex_icccm_state_set(win, WithdrawnState);
632 }
633
634 static void
ex_icccm_client_message_send(EX_Window win,EX_Atom atom,EX_Time ts)635 ex_icccm_client_message_send(EX_Window win, EX_Atom atom, EX_Time ts)
636 {
637 ex_client_message32_send(win, ea_i.WM_PROTOCOLS, NoEventMask,
638 atom, ts, 0, 0, 0);
639 }
640
641 void
ex_icccm_delete_window_send(EX_Window win,EX_Time ts)642 ex_icccm_delete_window_send(EX_Window win, EX_Time ts)
643 {
644 ex_icccm_client_message_send(win, ea_i.WM_DELETE_WINDOW, ts);
645 }
646
647 void
ex_icccm_take_focus_send(EX_Window win,EX_Time ts)648 ex_icccm_take_focus_send(EX_Window win, EX_Time ts)
649 {
650 ex_icccm_client_message_send(win, ea_i.WM_TAKE_FOCUS, ts);
651 }
652
653 #if 0
654 void
655 ex_icccm_save_yourself_send(EX_Window win, EX_Time ts)
656 {
657 ex_icccm_client_message_send(win, ea_i.WM_SAVE_YOURSELF, ts);
658 }
659 #endif
660
661 void
ex_icccm_title_set(EX_Window win,const char * title)662 ex_icccm_title_set(EX_Window win, const char *title)
663 {
664 ex_window_prop_string_set(win, ea_i.WM_NAME, title);
665 }
666
667 char *
ex_icccm_title_get(EX_Window win)668 ex_icccm_title_get(EX_Window win)
669 {
670 return ex_window_prop_string_get(win, ea_i.WM_NAME);
671 }
672
673 void
ex_icccm_name_class_set(EX_Window win,const char * name,const char * clss)674 ex_icccm_name_class_set(EX_Window win, const char *name, const char *clss)
675 {
676 XClassHint *xch;
677
678 xch = XAllocClassHint();
679 if (!xch)
680 return;
681 xch->res_name = (char *)name;
682 xch->res_class = (char *)clss;
683 XSetClassHint(_ex_disp, win, xch);
684 XFree(xch);
685 }
686
687 void
ex_icccm_name_class_get(EX_Window win,char ** name,char ** clss)688 ex_icccm_name_class_get(EX_Window win, char **name, char **clss)
689 {
690 XClassHint xch;
691
692 *name = *clss = NULL;
693 xch.res_name = NULL;
694 xch.res_class = NULL;
695 if (XGetClassHint(_ex_disp, win, &xch))
696 {
697 if (name && xch.res_name)
698 *name = Estrdup(xch.res_name);
699 if (clss && xch.res_class)
700 *clss = Estrdup(xch.res_class);
701 XFree(xch.res_name);
702 XFree(xch.res_class);
703 }
704 }
705
706 /*
707 * _NET_WM hints (EWMH)
708 */
709
710 static const char *const ea_n_names[] = {
711 #define DEFINE_ATOM_NETWM(a) #a,
712 #include "xpropdefs.h"
713 #undef DEFINE_ATOM_NETWM
714 };
715 e_atoms_netwm_t ea_n;
716
717 void
ex_netwm_init(void)718 ex_netwm_init(void)
719 {
720 ex_atoms_get(ea_n_names, E_ARRAY_SIZE(ea_n_names), (EX_Atom *) & ea_n);
721 }
722
723 /*
724 * WM identification
725 */
726 void
ex_netwm_wm_identify(EX_Window root,EX_Window check,const char * wm_name)727 ex_netwm_wm_identify(EX_Window root, EX_Window check, const char *wm_name)
728 {
729 unsigned int pid = getpid();
730
731 ex_window_prop_window_set(root, ea_n._NET_SUPPORTING_WM_CHECK, &check, 1);
732 ex_window_prop_window_set(check, ea_n._NET_SUPPORTING_WM_CHECK, &check, 1);
733 _ex_window_prop_string_utf8_set(check, ea_n._NET_WM_NAME, wm_name);
734 ex_window_prop_card32_set(check, ea_n._NET_WM_PID, &pid, 1);
735 }
736
737 /*
738 * Desktop configuration and status
739 */
740
741 void
ex_netwm_desk_count_set(EX_Window root,unsigned int n_desks)742 ex_netwm_desk_count_set(EX_Window root, unsigned int n_desks)
743 {
744 ex_window_prop_card32_set(root, ea_n._NET_NUMBER_OF_DESKTOPS, &n_desks, 1);
745 }
746
747 void
ex_netwm_desk_roots_set(EX_Window root,const EX_Window * vroots,unsigned int n_desks)748 ex_netwm_desk_roots_set(EX_Window root, const EX_Window * vroots,
749 unsigned int n_desks)
750 {
751 ex_window_prop_window_set(root, ea_n._NET_VIRTUAL_ROOTS, vroots, n_desks);
752 }
753
754 void
ex_netwm_desk_names_set(EX_Window root,const char ** names,unsigned int n_desks)755 ex_netwm_desk_names_set(EX_Window root, const char **names,
756 unsigned int n_desks)
757 {
758 char ss[32], *buf, *buf_r;
759 const char *s;
760 unsigned int i;
761 int l, len;
762
763 buf = NULL;
764 len = 0;
765
766 for (i = 0; i < n_desks; i++)
767 {
768 s = (names) ? names[i] : NULL;
769 if (!s)
770 {
771 /* Default to "Desk-<number>" */
772 sprintf(ss, "Desk-%u", i);
773 s = ss;
774 }
775
776 l = strlen(s) + 1;
777 buf_r = EREALLOC(char, buf, len + l);
778
779 if (!buf_r)
780 goto done;
781 buf = buf_r;
782 memcpy(buf + len, s, l);
783 len += l;
784 }
785
786 XChangeProperty(_ex_disp, root, ea_n._NET_DESKTOP_NAMES,
787 ea_m.UTF8_STRING, 8, PropModeReplace,
788 (unsigned char *)buf, len);
789
790 done:
791 Efree(buf);
792 }
793
794 void
ex_netwm_desk_size_set(EX_Window root,unsigned int width,unsigned int height)795 ex_netwm_desk_size_set(EX_Window root, unsigned int width, unsigned int height)
796 {
797 unsigned int size[2];
798
799 size[0] = width;
800 size[1] = height;
801 ex_window_prop_card32_set(root, ea_n._NET_DESKTOP_GEOMETRY, size, 2);
802 }
803
804 void
ex_netwm_desk_workareas_set(EX_Window root,const unsigned int * areas,unsigned int n_desks)805 ex_netwm_desk_workareas_set(EX_Window root, const unsigned int *areas,
806 unsigned int n_desks)
807 {
808 ex_window_prop_card32_set(root, ea_n._NET_WORKAREA, areas, 4 * n_desks);
809 }
810
811 void
ex_netwm_desk_current_set(EX_Window root,unsigned int desk)812 ex_netwm_desk_current_set(EX_Window root, unsigned int desk)
813 {
814 ex_window_prop_card32_set(root, ea_n._NET_CURRENT_DESKTOP, &desk, 1);
815 }
816
817 void
ex_netwm_desk_viewports_set(EX_Window root,const unsigned int * origins,unsigned int n_desks)818 ex_netwm_desk_viewports_set(EX_Window root, const unsigned int *origins,
819 unsigned int n_desks)
820 {
821 ex_window_prop_card32_set(root, ea_n._NET_DESKTOP_VIEWPORT,
822 origins, 2 * n_desks);
823 }
824
825 void
ex_netwm_showing_desktop_set(EX_Window root,int on)826 ex_netwm_showing_desktop_set(EX_Window root, int on)
827 {
828 unsigned int val;
829
830 val = (on) ? 1 : 0;
831 ex_window_prop_card32_set(root, ea_n._NET_SHOWING_DESKTOP, &val, 1);
832 }
833
834 /*
835 * Client status
836 */
837
838 /* Mapping order */
839 void
ex_netwm_client_list_set(EX_Window root,const EX_Window * p_clients,unsigned int n_clients)840 ex_netwm_client_list_set(EX_Window root, const EX_Window * p_clients,
841 unsigned int n_clients)
842 {
843 ex_window_prop_window_set(root, ea_n._NET_CLIENT_LIST, p_clients, n_clients);
844 }
845
846 /* Stacking order */
847 void
ex_netwm_client_list_stacking_set(EX_Window root,const EX_Window * p_clients,unsigned int n_clients)848 ex_netwm_client_list_stacking_set(EX_Window root,
849 const EX_Window * p_clients,
850 unsigned int n_clients)
851 {
852 ex_window_prop_window_set(root, ea_n._NET_CLIENT_LIST_STACKING,
853 p_clients, n_clients);
854 }
855
856 void
ex_netwm_client_active_set(EX_Window root,EX_Window win)857 ex_netwm_client_active_set(EX_Window root, EX_Window win)
858 {
859 ex_window_prop_window_set(root, ea_n._NET_ACTIVE_WINDOW, &win, 1);
860 }
861
862 /*
863 * Client window properties
864 */
865
866 void
ex_netwm_name_set(EX_Window win,const char * name)867 ex_netwm_name_set(EX_Window win, const char *name)
868 {
869 _ex_window_prop_string_utf8_set(win, ea_n._NET_WM_NAME, name);
870 }
871
872 int
ex_netwm_name_get(EX_Window win,char ** name)873 ex_netwm_name_get(EX_Window win, char **name)
874 {
875 char *s;
876
877 s = _ex_window_prop_string_utf8_get(win, ea_n._NET_WM_NAME);
878 *name = s;
879
880 return !!s;
881 }
882
883 void
ex_netwm_visible_name_set(EX_Window win,const char * name)884 ex_netwm_visible_name_set(EX_Window win, const char *name)
885 {
886 _ex_window_prop_string_utf8_set(win, ea_n._NET_WM_VISIBLE_NAME, name);
887 }
888
889 int
ex_netwm_visible_name_get(EX_Window win,char ** name)890 ex_netwm_visible_name_get(EX_Window win, char **name)
891 {
892 char *s;
893
894 s = _ex_window_prop_string_utf8_get(win, ea_n._NET_WM_VISIBLE_NAME);
895 *name = s;
896
897 return !!s;
898 }
899
900 void
ex_netwm_icon_name_set(EX_Window win,const char * name)901 ex_netwm_icon_name_set(EX_Window win, const char *name)
902 {
903 _ex_window_prop_string_utf8_set(win, ea_n._NET_WM_ICON_NAME, name);
904 }
905
906 int
ex_netwm_icon_name_get(EX_Window win,char ** name)907 ex_netwm_icon_name_get(EX_Window win, char **name)
908 {
909 char *s;
910
911 s = _ex_window_prop_string_utf8_get(win, ea_n._NET_WM_ICON_NAME);
912 *name = s;
913
914 return !!s;
915 }
916
917 void
ex_netwm_visible_icon_name_set(EX_Window win,const char * name)918 ex_netwm_visible_icon_name_set(EX_Window win, const char *name)
919 {
920 _ex_window_prop_string_utf8_set(win, ea_n._NET_WM_VISIBLE_ICON_NAME, name);
921 }
922
923 int
ex_netwm_visible_icon_name_get(EX_Window win,char ** name)924 ex_netwm_visible_icon_name_get(EX_Window win, char **name)
925 {
926 char *s;
927
928 s = _ex_window_prop_string_utf8_get(win, ea_n._NET_WM_VISIBLE_ICON_NAME);
929 *name = s;
930
931 return !!s;
932 }
933
934 void
ex_netwm_desktop_set(EX_Window win,unsigned int desk)935 ex_netwm_desktop_set(EX_Window win, unsigned int desk)
936 {
937 ex_window_prop_card32_set(win, ea_n._NET_WM_DESKTOP, &desk, 1);
938 }
939
940 int
ex_netwm_desktop_get(EX_Window win,unsigned int * desk)941 ex_netwm_desktop_get(EX_Window win, unsigned int *desk)
942 {
943 return ex_window_prop_card32_get(win, ea_n._NET_WM_DESKTOP, desk, 1);
944 }
945
946 int
ex_netwm_user_time_get(EX_Window win,unsigned int * ts)947 ex_netwm_user_time_get(EX_Window win, unsigned int *ts)
948 {
949 return ex_window_prop_card32_get(win, ea_n._NET_WM_USER_TIME, ts, 1);
950 }
951
952 void
ex_netwm_opacity_set(EX_Window win,unsigned int opacity)953 ex_netwm_opacity_set(EX_Window win, unsigned int opacity)
954 {
955 ex_window_prop_card32_set(win, ea_n._NET_WM_WINDOW_OPACITY, &opacity, 1);
956 }
957
958 int
ex_netwm_opacity_get(EX_Window win,unsigned int * opacity)959 ex_netwm_opacity_get(EX_Window win, unsigned int *opacity)
960 {
961 return ex_window_prop_card32_get(win, ea_n._NET_WM_WINDOW_OPACITY,
962 opacity, 1);
963 }
964
965 #if 0 /* Not used */
966 void
967 ex_netwm_startup_id_set(EX_Window win, const char *id)
968 {
969 _ex_window_prop_string_utf8_set(win, ea_n._NET_STARTUP_ID, id);
970 }
971 #endif
972
973 int
ex_netwm_startup_id_get(EX_Window win,char ** id)974 ex_netwm_startup_id_get(EX_Window win, char **id)
975 {
976 char *s;
977
978 s = _ex_window_prop_string_utf8_get(win, ea_n._NET_STARTUP_ID);
979 *id = s;
980
981 return !!s;
982 }
983