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