1 /*
2  * Various ICCCM related functions.
3  *
4  * This is ALL the code involving anything ICCCM related. for both WM and
5  * client.
6  */
7 
8 #ifdef HAVE_CONFIG_H
9 # include <config.h>
10 #endif /* ifdef HAVE_CONFIG_H */
11 
12 #include <stdlib.h>
13 #include <string.h>
14 
15 #include "Ecore.h"
16 #include "ecore_x_private.h"
17 #include "Ecore_X.h"
18 #include "Ecore_X_Atoms.h"
19 
20 EAPI void
ecore_x_icccm_init(void)21 ecore_x_icccm_init(void)
22 {
23    LOGFN;
24 }
25 
26 EAPI void
ecore_x_icccm_state_set(Ecore_X_Window win,Ecore_X_Window_State_Hint state)27 ecore_x_icccm_state_set(Ecore_X_Window win,
28                         Ecore_X_Window_State_Hint state)
29 {
30    unsigned long c[2];
31 
32    LOGFN;
33    if (state == ECORE_X_WINDOW_STATE_HINT_WITHDRAWN)
34      c[0] = WithdrawnState;
35    else if (state == ECORE_X_WINDOW_STATE_HINT_NORMAL)
36      c[0] = NormalState;
37    else if (state == ECORE_X_WINDOW_STATE_HINT_ICONIC)
38      c[0] = IconicState;
39 
40    c[1] = None;
41    XChangeProperty(_ecore_x_disp, win, ECORE_X_ATOM_WM_STATE,
42                    ECORE_X_ATOM_WM_STATE, 32, PropModeReplace,
43                    (unsigned char *)c, 2);
44    if (_ecore_xlib_sync) ecore_x_sync();
45 }
46 
47 EAPI Ecore_X_Window_State_Hint
ecore_x_icccm_state_get(Ecore_X_Window win)48 ecore_x_icccm_state_get(Ecore_X_Window win)
49 {
50    unsigned char *prop_ret = NULL;
51    Atom type_ret;
52    unsigned long bytes_after, num_ret;
53    int format_ret;
54    Ecore_X_Window_State_Hint hint;
55 
56    LOGFN;
57    hint = ECORE_X_WINDOW_STATE_HINT_NONE;
58    XGetWindowProperty(_ecore_x_disp, win, ECORE_X_ATOM_WM_STATE,
59                       0, 0x7fffffff, False, ECORE_X_ATOM_WM_STATE,
60                       &type_ret, &format_ret, &num_ret, &bytes_after,
61                       &prop_ret);
62    if (_ecore_xlib_sync) ecore_x_sync();
63    if ((prop_ret) && (num_ret == 2))
64      {
65         if (prop_ret[0] == WithdrawnState)
66           hint = ECORE_X_WINDOW_STATE_HINT_WITHDRAWN;
67         else if (prop_ret[0] == NormalState)
68           hint = ECORE_X_WINDOW_STATE_HINT_NORMAL;
69         else if (prop_ret[0] == IconicState)
70           hint = ECORE_X_WINDOW_STATE_HINT_ICONIC;
71      }
72 
73    if (prop_ret)
74      XFree(prop_ret);
75 
76    return hint;
77 }
78 
79 EAPI void
ecore_x_icccm_delete_window_send(Ecore_X_Window win,Ecore_X_Time t)80 ecore_x_icccm_delete_window_send(Ecore_X_Window win,
81                                  Ecore_X_Time t)
82 {
83    LOGFN;
84    ecore_x_client_message32_send(win, ECORE_X_ATOM_WM_PROTOCOLS,
85                                  ECORE_X_EVENT_MASK_NONE,
86                                  ECORE_X_ATOM_WM_DELETE_WINDOW,
87                                  t, 0, 0, 0);
88 }
89 
90 EAPI void
ecore_x_icccm_take_focus_send(Ecore_X_Window win,Ecore_X_Time t)91 ecore_x_icccm_take_focus_send(Ecore_X_Window win,
92                               Ecore_X_Time t)
93 {
94    LOGFN;
95    ecore_x_client_message32_send(win, ECORE_X_ATOM_WM_PROTOCOLS,
96                                  ECORE_X_EVENT_MASK_NONE,
97                                  ECORE_X_ATOM_WM_TAKE_FOCUS,
98                                  t, 0, 0, 0);
99 }
100 
101 EAPI void
ecore_x_icccm_save_yourself_send(Ecore_X_Window win,Ecore_X_Time t)102 ecore_x_icccm_save_yourself_send(Ecore_X_Window win,
103                                  Ecore_X_Time t)
104 {
105    LOGFN;
106    ecore_x_client_message32_send(win, ECORE_X_ATOM_WM_PROTOCOLS,
107                                  ECORE_X_EVENT_MASK_NONE,
108                                  ECORE_X_ATOM_WM_SAVE_YOURSELF,
109                                  t, 0, 0, 0);
110 }
111 
112 EAPI void
ecore_x_icccm_move_resize_send(Ecore_X_Window win,int x,int y,int w,int h)113 ecore_x_icccm_move_resize_send(Ecore_X_Window win,
114                                int x,
115                                int y,
116                                int w,
117                                int h)
118 {
119    XEvent ev;
120 
121    LOGFN;
122    ev.type = ConfigureNotify;
123    ev.xconfigure.display = _ecore_x_disp;
124    ev.xconfigure.event = win;
125    ev.xconfigure.window = win;
126    ev.xconfigure.x = x;
127    ev.xconfigure.y = y;
128    ev.xconfigure.width = w;
129    ev.xconfigure.height = h;
130    ev.xconfigure.border_width = 0;
131    ev.xconfigure.above = None;
132    ev.xconfigure.override_redirect = False;
133    XSendEvent(_ecore_x_disp, win, False, StructureNotifyMask, &ev);
134    if (_ecore_xlib_sync) ecore_x_sync();
135 }
136 
137 EAPI void
ecore_x_icccm_hints_set(Ecore_X_Window win,Eina_Bool accepts_focus,Ecore_X_Window_State_Hint initial_state,Ecore_X_Pixmap icon_pixmap,Ecore_X_Pixmap icon_mask,Ecore_X_Window icon_window,Ecore_X_Window window_group,Eina_Bool is_urgent)138 ecore_x_icccm_hints_set(Ecore_X_Window win,
139                         Eina_Bool accepts_focus,
140                         Ecore_X_Window_State_Hint initial_state,
141                         Ecore_X_Pixmap icon_pixmap,
142                         Ecore_X_Pixmap icon_mask,
143                         Ecore_X_Window icon_window,
144                         Ecore_X_Window window_group,
145                         Eina_Bool is_urgent)
146 {
147    XWMHints *hints;
148 
149    hints = XAllocWMHints();
150    if (!hints)
151      return;
152 
153    LOGFN;
154    hints->flags = InputHint | StateHint;
155    hints->input = accepts_focus;
156    if (initial_state == ECORE_X_WINDOW_STATE_HINT_WITHDRAWN)
157      hints->initial_state = WithdrawnState;
158    else if (initial_state == ECORE_X_WINDOW_STATE_HINT_NORMAL)
159      hints->initial_state = NormalState;
160    else if (initial_state == ECORE_X_WINDOW_STATE_HINT_ICONIC)
161      hints->initial_state = IconicState;
162 
163    if (icon_pixmap != 0)
164      {
165         hints->icon_pixmap = icon_pixmap;
166         hints->flags |= IconPixmapHint;
167      }
168 
169    if (icon_mask != 0)
170      {
171         hints->icon_mask = icon_mask;
172         hints->flags |= IconMaskHint;
173      }
174 
175    if (icon_window != 0)
176      {
177         hints->icon_window = icon_window;
178         hints->flags |= IconWindowHint;
179      }
180 
181    if (window_group != 0)
182      {
183         hints->window_group = window_group;
184         hints->flags |= WindowGroupHint;
185      }
186 
187    if (is_urgent)
188      hints->flags |= XUrgencyHint;
189 
190    XSetWMHints(_ecore_x_disp, win, hints);
191    if (_ecore_xlib_sync) ecore_x_sync();
192    XFree(hints);
193 }
194 
195 EAPI Eina_Bool
ecore_x_icccm_hints_get(Ecore_X_Window win,Eina_Bool * accepts_focus,Ecore_X_Window_State_Hint * initial_state,Ecore_X_Pixmap * icon_pixmap,Ecore_X_Pixmap * icon_mask,Ecore_X_Window * icon_window,Ecore_X_Window * window_group,Eina_Bool * is_urgent)196 ecore_x_icccm_hints_get(Ecore_X_Window win,
197                         Eina_Bool *accepts_focus,
198                         Ecore_X_Window_State_Hint *initial_state,
199                         Ecore_X_Pixmap *icon_pixmap,
200                         Ecore_X_Pixmap *icon_mask,
201                         Ecore_X_Window *icon_window,
202                         Ecore_X_Window *window_group,
203                         Eina_Bool *is_urgent)
204 {
205    XWMHints *hints;
206 
207    LOGFN;
208    if (accepts_focus)
209      *accepts_focus = EINA_TRUE;
210 
211    if (initial_state)
212      *initial_state = ECORE_X_WINDOW_STATE_HINT_NORMAL;
213 
214    if (icon_pixmap)
215      *icon_pixmap = 0;
216 
217    if (icon_mask)
218      *icon_mask = 0;
219 
220    if (icon_window)
221      *icon_window = 0;
222 
223    if (window_group)
224      *window_group = 0;
225 
226    if (is_urgent)
227      *is_urgent = EINA_FALSE;
228 
229    hints = XGetWMHints(_ecore_x_disp, win);
230    if (_ecore_xlib_sync) ecore_x_sync();
231    if (hints)
232      {
233         if ((hints->flags & InputHint) && (accepts_focus))
234           {
235              if (hints->input)
236                *accepts_focus = EINA_TRUE;
237              else
238                *accepts_focus = EINA_FALSE;
239           }
240 
241         if ((hints->flags & StateHint) && (initial_state))
242           {
243              if (hints->initial_state == WithdrawnState)
244                *initial_state = ECORE_X_WINDOW_STATE_HINT_WITHDRAWN;
245              else if (hints->initial_state == NormalState)
246                *initial_state = ECORE_X_WINDOW_STATE_HINT_NORMAL;
247              else if (hints->initial_state == IconicState)
248                *initial_state = ECORE_X_WINDOW_STATE_HINT_ICONIC;
249           }
250 
251         if ((hints->flags & IconPixmapHint) && (icon_pixmap))
252           *icon_pixmap = hints->icon_pixmap;
253 
254         if ((hints->flags & IconMaskHint) && (icon_mask))
255           *icon_mask = hints->icon_mask;
256 
257         if ((hints->flags & IconWindowHint) && (icon_window))
258           *icon_window = hints->icon_window;
259 
260         if ((hints->flags & WindowGroupHint) && (window_group))
261           *window_group = hints->window_group;
262 
263         if ((hints->flags & XUrgencyHint) && (is_urgent))
264           *is_urgent = EINA_TRUE;
265 
266         XFree(hints);
267         return EINA_TRUE;
268      }
269 
270    return EINA_FALSE;
271 }
272 
273 EAPI void
ecore_x_icccm_size_pos_hints_set(Ecore_X_Window win,Eina_Bool request_pos,Ecore_X_Gravity gravity,int min_w,int min_h,int max_w,int max_h,int base_w,int base_h,int step_x,int step_y,double min_aspect,double max_aspect)274 ecore_x_icccm_size_pos_hints_set(Ecore_X_Window win,
275                                  Eina_Bool request_pos,
276                                  Ecore_X_Gravity gravity,
277                                  int min_w,
278                                  int min_h,
279                                  int max_w,
280                                  int max_h,
281                                  int base_w,
282                                  int base_h,
283                                  int step_x,
284                                  int step_y,
285                                  double min_aspect,
286                                  double max_aspect)
287 {
288    XSizeHints hint;
289    long mask;
290 
291    LOGFN;
292    if (!XGetWMNormalHints(_ecore_x_disp, win, &hint, &mask))
293      memset(&hint, 0, sizeof(XSizeHints));
294    if (_ecore_xlib_sync) ecore_x_sync();
295 
296    hint.flags = 0;
297    if (request_pos)
298      hint.flags |= USPosition;
299 
300    if (gravity != ECORE_X_GRAVITY_NW)
301      {
302         hint.flags |= PWinGravity;
303         hint.win_gravity = gravity;
304      }
305 
306    if ((min_w > 0) || (min_h > 0))
307      {
308         hint.flags |= PMinSize;
309         hint.min_width = min_w;
310         hint.min_height = min_h;
311      }
312 
313    if ((max_w > 0) || (max_h > 0))
314      {
315         hint.flags |= PMaxSize;
316         hint.max_width = max_w;
317         hint.max_height = max_h;
318      }
319 
320    if ((base_w > 0) || (base_h > 0))
321      {
322         hint.flags |= PBaseSize;
323         hint.base_width = base_w;
324         hint.base_height = base_h;
325      }
326 
327    if ((step_x > 1) || (step_y > 1))
328      {
329         hint.flags |= PResizeInc;
330         hint.width_inc = step_x;
331         hint.height_inc = step_y;
332      }
333 
334    if ((min_aspect > 0.0) || (max_aspect > 0.0))
335      {
336         hint.flags |= PAspect;
337         hint.min_aspect.x = min_aspect * 10000;
338         hint.min_aspect.y = 10000;
339         hint.max_aspect.x = max_aspect * 10000;
340         hint.max_aspect.y = 10000;
341      }
342 
343    XSetWMNormalHints(_ecore_x_disp, win, &hint);
344    if (_ecore_xlib_sync) ecore_x_sync();
345 }
346 
347 EAPI Eina_Bool
ecore_x_icccm_size_pos_hints_get(Ecore_X_Window win,Eina_Bool * request_pos,Ecore_X_Gravity * gravity,int * min_w,int * min_h,int * max_w,int * max_h,int * base_w,int * base_h,int * step_x,int * step_y,double * min_aspect,double * max_aspect)348 ecore_x_icccm_size_pos_hints_get(Ecore_X_Window win,
349                                  Eina_Bool *request_pos,
350                                  Ecore_X_Gravity *gravity,
351                                  int *min_w,
352                                  int *min_h,
353                                  int *max_w,
354                                  int *max_h,
355                                  int *base_w,
356                                  int *base_h,
357                                  int *step_x,
358                                  int *step_y,
359                                  double *min_aspect,
360                                  double *max_aspect)
361 {
362    XSizeHints hint;
363    long mask;
364 
365    int minw = 0, minh = 0;
366    int maxw = 32767, maxh = 32767;
367    int basew = -1, baseh = -1;
368    int stepx = -1, stepy = -1;
369    double mina = 0.0, maxa = 0.0;
370 
371    LOGFN;
372    if (!XGetWMNormalHints(_ecore_x_disp, win, &hint, &mask))
373      {
374         if (_ecore_xlib_sync) ecore_x_sync();
375         return EINA_FALSE;
376      }
377 
378    if ((hint.flags & USPosition) || ((hint.flags & PPosition)))
379      {
380         if (request_pos)
381           *request_pos = EINA_TRUE;
382      }
383    else if (request_pos)
384      *request_pos = EINA_FALSE;
385 
386    if (hint.flags & PWinGravity)
387      {
388         if (gravity)
389           *gravity = hint.win_gravity;
390      }
391    else if (gravity)
392      *gravity = ECORE_X_GRAVITY_NW;
393 
394    if (hint.flags & PMinSize)
395      {
396         minw = hint.min_width;
397         minh = hint.min_height;
398      }
399 
400    if (hint.flags & PMaxSize)
401      {
402         maxw = hint.max_width;
403         maxh = hint.max_height;
404         if (maxw < minw)
405           maxw = minw;
406 
407         if (maxh < minh)
408           maxh = minh;
409      }
410 
411    if (hint.flags & PBaseSize)
412      {
413         basew = hint.base_width;
414         baseh = hint.base_height;
415         if (basew > minw)
416           minw = basew;
417 
418         if (baseh > minh)
419           minh = baseh;
420      }
421 
422    if (hint.flags & PResizeInc)
423      {
424         stepx = hint.width_inc;
425         stepy = hint.height_inc;
426         if (stepx < 1)
427           stepx = 1;
428 
429         if (stepy < 1)
430           stepy = 1;
431      }
432 
433    if (hint.flags & PAspect)
434      {
435         if (hint.min_aspect.y > 0)
436           mina = ((double)hint.min_aspect.x) / ((double)hint.min_aspect.y);
437 
438         if (hint.max_aspect.y > 0)
439           maxa = ((double)hint.max_aspect.x) / ((double)hint.max_aspect.y);
440      }
441 
442    if (min_w)
443      *min_w = minw;
444 
445    if (min_h)
446      *min_h = minh;
447 
448    if (max_w)
449      *max_w = maxw;
450 
451    if (max_h)
452      *max_h = maxh;
453 
454    if (base_w)
455      *base_w = basew;
456 
457    if (base_h)
458      *base_h = baseh;
459 
460    if (step_x)
461      *step_x = stepx;
462 
463    if (step_y)
464      *step_y = stepy;
465 
466    if (min_aspect)
467      *min_aspect = mina;
468 
469    if (max_aspect)
470      *max_aspect = maxa;
471 
472    return EINA_TRUE;
473 }
474 
475 EAPI void
ecore_x_icccm_title_set(Ecore_X_Window win,const char * t)476 ecore_x_icccm_title_set(Ecore_X_Window win,
477                         const char *t)
478 {
479    char *list[1];
480    XTextProperty xprop;
481    int ret;
482 
483    if (!t)
484      return;
485 
486    LOGFN;
487    xprop.value = NULL;
488 #ifdef X_HAVE_UTF8_STRING
489    list[0] = strdup(t);
490    ret =
491      Xutf8TextListToTextProperty(_ecore_x_disp, list, 1, XUTF8StringStyle,
492                                  &xprop);
493 #else /* ifdef X_HAVE_UTF8_STRING */
494    list[0] = strdup(t);
495    ret =
496      XmbTextListToTextProperty(_ecore_x_disp, list, 1, XStdICCTextStyle,
497                                &xprop);
498 #endif /* ifdef X_HAVE_UTF8_STRING */
499    if (_ecore_xlib_sync) ecore_x_sync();
500    if (ret >= Success)
501      {
502         XSetWMName(_ecore_x_disp, win, &xprop);
503         if (_ecore_xlib_sync) ecore_x_sync();
504         if (xprop.value)
505           XFree(xprop.value);
506      }
507    else if (XStringListToTextProperty(list, 1, &xprop) >= Success)
508      {
509         XSetWMName(_ecore_x_disp, win, &xprop);
510         if (_ecore_xlib_sync) ecore_x_sync();
511         if (xprop.value)
512           XFree(xprop.value);
513      }
514 
515    free(list[0]);
516 }
517 
518 EAPI char *
ecore_x_icccm_title_get(Ecore_X_Window win)519 ecore_x_icccm_title_get(Ecore_X_Window win)
520 {
521    XTextProperty xprop;
522 
523    LOGFN;
524    xprop.value = NULL;
525    if (XGetWMName(_ecore_x_disp, win, &xprop) >= Success)
526      {
527         if (_ecore_xlib_sync) ecore_x_sync();
528         if (xprop.value)
529           {
530              char **list = NULL;
531              char *t = NULL;
532              int num = 0;
533              int ret;
534 
535              if (xprop.encoding == ECORE_X_ATOM_UTF8_STRING)
536                t = strdup((char *)xprop.value);
537              else
538                {
539                   /* convert to utf8 */
540 #ifdef X_HAVE_UTF8_STRING
541                   ret = Xutf8TextPropertyToTextList(_ecore_x_disp, &xprop,
542                                                     &list, &num);
543 #else /* ifdef X_HAVE_UTF8_STRING */
544                   ret = XmbTextPropertyToTextList(_ecore_x_disp, &xprop,
545                                                   &list, &num);
546 #endif /* ifdef X_HAVE_UTF8_STRING */
547                   if (_ecore_xlib_sync) ecore_x_sync();
548 
549                   if ((ret == XLocaleNotSupported) ||
550                       (ret == XNoMemory) || (ret == XConverterNotFound))
551                     t = strdup((char *)xprop.value);
552                   else if ((ret >= Success) && (num > 0))
553                     t = strdup(list[0]);
554 
555                   if (list)
556                     XFreeStringList(list);
557                }
558 
559              if (xprop.value)
560                XFree(xprop.value);
561 
562              return t;
563           }
564      }
565    else
566      {
567         if (_ecore_xlib_sync) ecore_x_sync();
568      }
569 
570    return NULL;
571 }
572 
573 /**
574  * Set protocol atoms explicitly
575  * @param win The Window
576  * @param protos An array of protocol atoms
577  * @param num the number of members of the array
578  */
579 EAPI void
ecore_x_icccm_protocol_atoms_set(Ecore_X_Window win,Ecore_X_Atom * protos,int num)580 ecore_x_icccm_protocol_atoms_set(Ecore_X_Window win,
581                                  Ecore_X_Atom *protos,
582                                  int num)
583 {
584    Atom *protos2 = alloca(sizeof(Atom) * num);
585    int i;
586 
587    for (i = 0; i < num; i++) protos2[i] = protos[i];
588    LOGFN;
589    if (num > 0)
590      XSetWMProtocols(_ecore_x_disp, win, protos2, num);
591    else
592      XDeleteProperty(_ecore_x_disp, win, ECORE_X_ATOM_WM_PROTOCOLS);
593    if (_ecore_xlib_sync) ecore_x_sync();
594 }
595 
596 /**
597  * Set or unset a wm protocol property.
598  * @param win The Window
599  * @param protocol The protocol to enable/disable
600  * @param on On/Off
601  */
602 EAPI void
ecore_x_icccm_protocol_set(Ecore_X_Window win,Ecore_X_WM_Protocol protocol,Eina_Bool on)603 ecore_x_icccm_protocol_set(Ecore_X_Window win,
604                            Ecore_X_WM_Protocol protocol,
605                            Eina_Bool on)
606 {
607    Atom *protos = NULL;
608    Atom proto;
609    int protos_count = 0;
610    int already_set = 0;
611    int i;
612 
613    /* Check for invalid values */
614    if (protocol >= ECORE_X_WM_PROTOCOL_NUM)
615      return;
616 
617    LOGFN;
618    proto = _ecore_x_atoms_wm_protocols[protocol];
619 
620    if (!XGetWMProtocols(_ecore_x_disp, win, &protos, &protos_count))
621      {
622         protos = NULL;
623         protos_count = 0;
624      }
625    if (_ecore_xlib_sync) ecore_x_sync();
626    for (i = 0; i < protos_count; i++)
627      {
628         if (protos[i] == proto)
629           {
630              already_set = 1;
631              break;
632           }
633      }
634 
635    if (on)
636      {
637         Atom *new_protos = NULL;
638 
639         if (already_set)
640           goto leave;
641 
642         new_protos = malloc((protos_count + 1) * sizeof(Atom));
643         if (!new_protos)
644           goto leave;
645 
646         for (i = 0; i < protos_count; i++)
647           new_protos[i] = protos[i];
648         new_protos[protos_count] = proto;
649         XSetWMProtocols(_ecore_x_disp, win, new_protos, protos_count + 1);
650         if (_ecore_xlib_sync) ecore_x_sync();
651         free(new_protos);
652      }
653    else
654      {
655         if (!already_set)
656           goto leave;
657 
658         for (i = 0; i < protos_count; i++)
659           {
660              if (protos[i] == proto)
661                {
662                   int j;
663 
664                   for (j = i + 1; j < protos_count; j++)
665                     protos[j - 1] = protos[j];
666                   if (protos_count > 1)
667                     XSetWMProtocols(_ecore_x_disp, win, protos,
668                                     protos_count - 1);
669                   else
670                     XDeleteProperty(_ecore_x_disp, win,
671                                     ECORE_X_ATOM_WM_PROTOCOLS);
672                   if (_ecore_xlib_sync) ecore_x_sync();
673 
674                   goto leave;
675                }
676           }
677      }
678 
679 leave:
680    if (protos)
681      XFree(protos);
682 }
683 
684 /**
685  * Determines whether a protocol is set for a window.
686  * @param win The Window
687  * @param protocol The protocol to query
688  * @return 1 if the protocol is set, else 0.
689  */
690 EAPI Eina_Bool
ecore_x_icccm_protocol_isset(Ecore_X_Window win,Ecore_X_WM_Protocol protocol)691 ecore_x_icccm_protocol_isset(Ecore_X_Window win,
692                              Ecore_X_WM_Protocol protocol)
693 {
694    Atom proto, *protos = NULL;
695    int i, protos_count = 0;
696    Eina_Bool ret = EINA_FALSE;
697 
698    /* check for invalid values */
699    if (protocol >= ECORE_X_WM_PROTOCOL_NUM)
700      return EINA_FALSE;
701 
702    LOGFN;
703    proto = _ecore_x_atoms_wm_protocols[protocol];
704 
705    if (!XGetWMProtocols(_ecore_x_disp, win, &protos, &protos_count))
706      return EINA_FALSE;
707    if (_ecore_xlib_sync) ecore_x_sync();
708 
709    for (i = 0; i < protos_count; i++)
710      if (protos[i] == proto)
711        {
712           ret = EINA_TRUE;
713           break;
714        }
715 
716    if (protos)
717      XFree(protos);
718 
719    return ret;
720 }
721 
722 /**
723  * Set a window name & class.
724  * @param win The window
725  * @param n The name string
726  * @param c The class string
727  *
728  * Set a window name * class
729  */
730 EAPI void
ecore_x_icccm_name_class_set(Ecore_X_Window win,const char * n,const char * c)731 ecore_x_icccm_name_class_set(Ecore_X_Window win,
732                              const char *n,
733                              const char *c)
734 {
735    XClassHint *xch;
736 
737    xch = XAllocClassHint();
738    if (!xch)
739      return;
740 
741    LOGFN;
742    xch->res_name = (char *)n;
743    xch->res_class = (char *)c;
744    XSetClassHint(_ecore_x_disp, win, xch);
745    if (_ecore_xlib_sync) ecore_x_sync();
746    XFree(xch);
747 }
748 
749 /**
750  * Get a window name & class.
751  * @param win The window
752  * @param n The name string
753  * @param c The class string
754  *
755  * Get a window name * class
756  */
757 EAPI void
ecore_x_icccm_name_class_get(Ecore_X_Window win,char ** n,char ** c)758 ecore_x_icccm_name_class_get(Ecore_X_Window win,
759                              char **n,
760                              char **c)
761 {
762    XClassHint xch;
763 
764    LOGFN;
765    if (n)
766      *n = NULL;
767 
768    if (c)
769      *c = NULL;
770 
771    xch.res_name = NULL;
772    xch.res_class = NULL;
773    if (XGetClassHint(_ecore_x_disp, win, &xch))
774      {
775         if (n)
776           if (xch.res_name)
777             *n = strdup(xch.res_name);
778 
779         if (c)
780           if (xch.res_class)
781             *c = strdup(xch.res_class);
782 
783         XFree(xch.res_name);
784         XFree(xch.res_class);
785      }
786    if (_ecore_xlib_sync) ecore_x_sync();
787 }
788 
789 /**
790  * Get a window client machine string.
791  * @param win The window
792  * @return The windows client machine string
793  *
794  * Return the client machine of a window. String must be free'd when done with.
795  */
796 EAPI char *
ecore_x_icccm_client_machine_get(Ecore_X_Window win)797 ecore_x_icccm_client_machine_get(Ecore_X_Window win)
798 {
799    char *name;
800 
801    LOGFN;
802    name = ecore_x_window_prop_string_get(win, ECORE_X_ATOM_WM_CLIENT_MACHINE);
803    return name;
804 }
805 
806 /**
807  * Sets the WM_COMMAND property for @a win.
808  *
809  * @param win  The window.
810  * @param argc Number of arguments.
811  * @param argv Arguments.
812  */
813 EAPI void
ecore_x_icccm_command_set(Ecore_X_Window win,int argc,char ** argv)814 ecore_x_icccm_command_set(Ecore_X_Window win,
815                           int argc,
816                           char **argv)
817 {
818    LOGFN;
819    XSetCommand(_ecore_x_disp, win, argv, argc);
820    if (_ecore_xlib_sync) ecore_x_sync();
821 }
822 
823 /**
824  * Get the WM_COMMAND property for @a win.
825  *
826  * Return the command of a window. String must be free'd when done with.
827  *
828  * @param win  The window.
829  * @param argc Number of arguments.
830  * @param argv Arguments.
831  */
832 EAPI void
ecore_x_icccm_command_get(Ecore_X_Window win,int * argc,char *** argv)833 ecore_x_icccm_command_get(Ecore_X_Window win,
834                           int *argc,
835                           char ***argv)
836 {
837    int i, c;
838    char **v;
839    Eina_Bool success;
840 
841    if (argc)
842      *argc = 0;
843 
844    if (argv)
845      *argv = NULL;
846 
847    LOGFN;
848    success = XGetCommand(_ecore_x_disp, win, &v, &c);
849    if (_ecore_xlib_sync) ecore_x_sync();
850    if (!success) return;
851 
852    if (c < 1)
853      {
854         if (v)
855           XFreeStringList(v);
856 
857         return;
858      }
859 
860    if (argc)
861      *argc = c;
862 
863    if (argv)
864      {
865         (*argv) = malloc(c * sizeof(char *));
866         if (!*argv)
867           {
868              XFreeStringList(v);
869              if (argc)
870                *argc = 0;
871 
872              return;
873           }
874 
875         for (i = 0; i < c; i++)
876           {
877              if (v[i])
878                (*argv)[i] = strdup(v[i]);
879              else
880                (*argv)[i] = strdup("");
881           }
882      }
883 
884    XFreeStringList(v);
885 }
886 
887 /**
888  * Set a window icon name.
889  * @param win The window
890  * @param t The icon name string
891  *
892  * Set a window icon name
893  */
894 EAPI void
ecore_x_icccm_icon_name_set(Ecore_X_Window win,const char * t)895 ecore_x_icccm_icon_name_set(Ecore_X_Window win,
896                             const char *t)
897 {
898    char *list[1];
899    XTextProperty xprop;
900    int ret;
901 
902    LOGFN;
903    xprop.value = NULL;
904 #ifdef X_HAVE_UTF8_STRING
905    list[0] = strdup(t);
906    ret = Xutf8TextListToTextProperty(_ecore_x_disp, list, 1,
907                                      XUTF8StringStyle, &xprop);
908 #else /* ifdef X_HAVE_UTF8_STRING */
909    list[0] = strdup(t);
910    ret = XmbTextListToTextProperty(_ecore_x_disp, list, 1,
911                                    XStdICCTextStyle, &xprop);
912 #endif /* ifdef X_HAVE_UTF8_STRING */
913    if (_ecore_xlib_sync) ecore_x_sync();
914    if (ret >= Success)
915      {
916         XSetWMIconName(_ecore_x_disp, win, &xprop);
917         if (_ecore_xlib_sync) ecore_x_sync();
918         if (xprop.value)
919           XFree(xprop.value);
920      }
921    else if (XStringListToTextProperty(list, 1, &xprop) >= Success)
922      {
923         XSetWMIconName(_ecore_x_disp, win, &xprop);
924         if (_ecore_xlib_sync) ecore_x_sync();
925         if (xprop.value)
926           XFree(xprop.value);
927      }
928 
929    free(list[0]);
930 }
931 
932 /**
933  * Get a window icon name.
934  * @param win The window
935  * @return The windows icon name string
936  *
937  * Return the icon name of a window. String must be free'd when done with.
938  */
939 EAPI char *
ecore_x_icccm_icon_name_get(Ecore_X_Window win)940 ecore_x_icccm_icon_name_get(Ecore_X_Window win)
941 {
942    XTextProperty xprop;
943 
944    LOGFN;
945    xprop.value = NULL;
946    if (XGetWMIconName(_ecore_x_disp, win, &xprop) >= Success)
947      {
948         if (_ecore_xlib_sync) ecore_x_sync();
949         if (xprop.value)
950           {
951              char **list = NULL;
952              char *t = NULL;
953              int num = 0;
954              int ret;
955 
956              if (xprop.encoding == ECORE_X_ATOM_UTF8_STRING)
957                t = strdup((char *)xprop.value);
958              else
959                {
960                   /* convert to utf8 */
961 #ifdef X_HAVE_UTF8_STRING
962                   ret = Xutf8TextPropertyToTextList(_ecore_x_disp, &xprop,
963                                                     &list, &num);
964 #else /* ifdef X_HAVE_UTF8_STRING */
965                   ret = XmbTextPropertyToTextList(_ecore_x_disp, &xprop,
966                                                   &list, &num);
967 #endif /* ifdef X_HAVE_UTF8_STRING */
968                   if (_ecore_xlib_sync) ecore_x_sync();
969 
970                   if ((ret == XLocaleNotSupported) ||
971                       (ret == XNoMemory) || (ret == XConverterNotFound))
972                     t = strdup((char *)xprop.value);
973                   else if (ret >= Success)
974                     {
975                        if ((num >= 1) && (list))
976                          t = strdup(list[0]);
977 
978                        if (list)
979                          XFreeStringList(list);
980                     }
981                }
982 
983              if (xprop.value)
984                XFree(xprop.value);
985 
986              return t;
987           }
988      }
989    else
990      {
991         if (_ecore_xlib_sync) ecore_x_sync();
992      }
993 
994    return NULL;
995 }
996 
997 /**
998  * Add a subwindow to the list of windows that need a different colormap installed.
999  * @param win The toplevel window
1000  * @param subwin The subwindow to be added to the colormap windows list
1001  */
1002 EAPI void
ecore_x_icccm_colormap_window_set(Ecore_X_Window win,Ecore_X_Window subwin)1003 ecore_x_icccm_colormap_window_set(Ecore_X_Window win,
1004                                   Ecore_X_Window subwin)
1005 {
1006    int num = 0, i;
1007    unsigned char *old_data = NULL;
1008    unsigned char *data = NULL;
1009    Window *oldset = NULL;
1010    Window *newset = NULL;
1011 
1012    LOGFN;
1013    if (!ecore_x_window_prop_property_get(win,
1014                                          ECORE_X_ATOM_WM_COLORMAP_WINDOWS,
1015                                          XA_WINDOW, 32, &old_data, &num))
1016      {
1017         newset = calloc(1, sizeof(Window));
1018         if (!newset)
1019           {
1020              if (old_data) free(old_data);
1021              return;
1022           }
1023 
1024         newset[0] = subwin;
1025         num = 1;
1026         data = (unsigned char *)newset;
1027      }
1028    else
1029      {
1030         newset = calloc(num + 1, sizeof(Window));
1031         oldset = (Window *)old_data;
1032         if (!newset)
1033           {
1034              if (old_data) free(old_data);
1035              return;
1036           }
1037 
1038         for (i = 0; i < num; ++i)
1039           {
1040              if (oldset[i] == subwin)
1041                {
1042                   free(old_data);
1043                   free(newset);
1044                   return;
1045                }
1046 
1047              newset[i] = oldset[i];
1048           }
1049 
1050         newset[num++] = subwin;
1051         data = (unsigned char *)newset;
1052      }
1053 
1054    ecore_x_window_prop_property_set(win,
1055                                     ECORE_X_ATOM_WM_COLORMAP_WINDOWS,
1056                                     XA_WINDOW, 32, data, num);
1057    free(newset);
1058    free(old_data);
1059 }
1060 
1061 /**
1062  * Remove a window from the list of colormap windows.
1063  * @param win The toplevel window
1064  * @param subwin The window to be removed from the colormap window list.
1065  */
1066 EAPI void
ecore_x_icccm_colormap_window_unset(Ecore_X_Window win,Ecore_X_Window subwin)1067 ecore_x_icccm_colormap_window_unset(Ecore_X_Window win,
1068                                     Ecore_X_Window subwin)
1069 {
1070    int num = 0, i, j, k = 0;
1071    unsigned char *old_data = NULL;
1072    unsigned char *data = NULL;
1073    Window *oldset = NULL;
1074    Window *newset = NULL;
1075 
1076    LOGFN;
1077    if (!ecore_x_window_prop_property_get(win,
1078                                          ECORE_X_ATOM_WM_COLORMAP_WINDOWS,
1079                                          XA_WINDOW, 32, &old_data, &num))
1080      {
1081         if (old_data) free(old_data);
1082         return;
1083      }
1084 
1085    oldset = (Window *)old_data;
1086    for (i = 0; i < num; i++)
1087      {
1088         if (oldset[i] == subwin)
1089           {
1090              if (num == 1)
1091                {
1092                   XDeleteProperty(_ecore_x_disp,
1093                                   win, ECORE_X_ATOM_WM_COLORMAP_WINDOWS);
1094                   if (_ecore_xlib_sync) ecore_x_sync();
1095                   free(old_data);
1096 
1097                   old_data = NULL;
1098                   return;
1099                }
1100              else
1101                {
1102                   newset = calloc(num - 1, sizeof(Window));
1103                   data = (unsigned char *)newset;
1104                   for (j = 0; j < num; ++j)
1105                     if (oldset[j] != subwin)
1106                       newset[k++] = oldset[j];
1107 
1108                   ecore_x_window_prop_property_set(
1109                     win,
1110                     ECORE_X_ATOM_WM_COLORMAP_WINDOWS,
1111                     XA_WINDOW,
1112                     32,
1113                     data,
1114                     k);
1115                   free(old_data);
1116 
1117                   old_data = NULL;
1118                   free(newset);
1119                   return;
1120                }
1121           }
1122      }
1123 
1124    if (old_data)
1125      free(old_data);
1126 }
1127 
1128 /**
1129  * Specify that a window is transient for another top-level window and should be handled accordingly.
1130  * @param win the transient window
1131  * @param forwin the toplevel window
1132  */
1133 EAPI void
ecore_x_icccm_transient_for_set(Ecore_X_Window win,Ecore_X_Window forwin)1134 ecore_x_icccm_transient_for_set(Ecore_X_Window win,
1135                                 Ecore_X_Window forwin)
1136 {
1137    LOGFN;
1138    XSetTransientForHint(_ecore_x_disp, win, forwin);
1139    if (_ecore_xlib_sync) ecore_x_sync();
1140 }
1141 
1142 /**
1143  * Remove the transient_for setting from a window.
1144  * @param win The window
1145  */
1146 EAPI void
ecore_x_icccm_transient_for_unset(Ecore_X_Window win)1147 ecore_x_icccm_transient_for_unset(Ecore_X_Window win)
1148 {
1149    LOGFN;
1150    XDeleteProperty(_ecore_x_disp, win, ECORE_X_ATOM_WM_TRANSIENT_FOR);
1151    if (_ecore_xlib_sync) ecore_x_sync();
1152 }
1153 
1154 /**
1155  * Get the window this window is transient for, if any.
1156  * @param win The window to check
1157  * @return The window ID of the top-level window, or 0 if the property does not exist.
1158  */
1159 EAPI Ecore_X_Window
ecore_x_icccm_transient_for_get(Ecore_X_Window win)1160 ecore_x_icccm_transient_for_get(Ecore_X_Window win)
1161 {
1162    Window forwin;
1163    Eina_Bool success;
1164 
1165    LOGFN;
1166    success = XGetTransientForHint(_ecore_x_disp, win, &forwin);
1167    if (_ecore_xlib_sync) ecore_x_sync();
1168    if (success)
1169      return (Ecore_X_Window)forwin;
1170    else
1171      return 0;
1172 }
1173 
1174 /**
1175  * Set the window role hint.
1176  * @param win The window
1177  * @param role The role string
1178  */
1179 EAPI void
ecore_x_icccm_window_role_set(Ecore_X_Window win,const char * role)1180 ecore_x_icccm_window_role_set(Ecore_X_Window win,
1181                               const char *role)
1182 {
1183    LOGFN;
1184    ecore_x_window_prop_string_set(win, ECORE_X_ATOM_WM_WINDOW_ROLE,
1185                                   (char *)role);
1186 }
1187 
1188 /**
1189  * Get the window role.
1190  * @param win The window
1191  * @return The window's role string.
1192  */
1193 EAPI char *
ecore_x_icccm_window_role_get(Ecore_X_Window win)1194 ecore_x_icccm_window_role_get(Ecore_X_Window win)
1195 {
1196    LOGFN;
1197    return ecore_x_window_prop_string_get(win, ECORE_X_ATOM_WM_WINDOW_ROLE);
1198 }
1199 
1200 /**
1201  * Set the window's client leader.
1202  * @param win The window
1203  * @param l The client leader window
1204  *
1205  * All non-transient top-level windows created by an app other than
1206  * the main window must have this property set to the app's main window.
1207  */
1208 EAPI void
ecore_x_icccm_client_leader_set(Ecore_X_Window win,Ecore_X_Window l)1209 ecore_x_icccm_client_leader_set(Ecore_X_Window win,
1210                                 Ecore_X_Window l)
1211 {
1212    LOGFN;
1213    ecore_x_window_prop_window_set(win, ECORE_X_ATOM_WM_CLIENT_LEADER,
1214                                   &l, 1);
1215 }
1216 
1217 /**
1218  * Get the window's client leader.
1219  * @param win The window
1220  * @return The window's client leader window, or 0 if unset */
1221 EAPI Ecore_X_Window
ecore_x_icccm_client_leader_get(Ecore_X_Window win)1222 ecore_x_icccm_client_leader_get(Ecore_X_Window win)
1223 {
1224    Ecore_X_Window l;
1225 
1226    LOGFN;
1227    if (ecore_x_window_prop_window_get(win, ECORE_X_ATOM_WM_CLIENT_LEADER,
1228                                       &l, 1) > 0)
1229      return l;
1230 
1231    return 0;
1232 }
1233 
1234 EAPI void
ecore_x_icccm_iconic_request_send(Ecore_X_Window win,Ecore_X_Window root)1235 ecore_x_icccm_iconic_request_send(Ecore_X_Window win,
1236                                   Ecore_X_Window root)
1237 {
1238    XEvent xev = { 0 };
1239 
1240    if (!win)
1241      return;
1242 
1243    LOGFN;
1244    if (!root)
1245      root = DefaultRootWindow(_ecore_x_disp);
1246 
1247    xev.xclient.type = ClientMessage;
1248    xev.xclient.serial = 0;
1249    xev.xclient.send_event = True;
1250    xev.xclient.display = _ecore_x_disp;
1251    xev.xclient.window = win;
1252    xev.xclient.format = 32;
1253    xev.xclient.message_type = ECORE_X_ATOM_WM_CHANGE_STATE;
1254    xev.xclient.data.l[0] = IconicState;
1255 
1256    XSendEvent(_ecore_x_disp, root, False,
1257               SubstructureNotifyMask | SubstructureRedirectMask, &xev);
1258    if (_ecore_xlib_sync) ecore_x_sync();
1259 }
1260 
1261 /* FIXME: there are older E hints, gnome hints and mwm hints and new netwm */
1262 /*        hints. each should go in their own file/section so we know which */
1263 /*        is which. also older kde hints too. we should try support as much */
1264 /*        as makese sense to support */
1265