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