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