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