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