chiark / gitweb /
New option: movres.ignore_transience.
[e16] / src / icccm.c
1 /*
2  * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors
3  * Copyright (C) 2004-2008 Kim Woelders
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy
6  * of this software and associated documentation files (the "Software"), to
7  * deal in the Software without restriction, including without limitation the
8  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9  * sell copies of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies of the Software, its documentation and marketing & publicity
14  * materials, and acknowledgment shall be given in the documentation, materials
15  * and software packages that this Software was used.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24 #include "E.h"
25 #include "desktops.h"
26 #include "e16-ecore_hints.h"
27 #include "ewins.h"
28 #include "hints.h"
29 #include "session.h"
30 #include "xwin.h"
31 #include <X11/Xutil.h>
32 #if USE_XSYNC
33 #include "timers.h"
34 #include <X11/extensions/sync.h>
35 #endif
36
37 static void         ICCCM_SetIconSizes(void);
38
39 void
40 ICCCM_Init(void)
41 {
42 #ifndef USE_ECORE_X
43    ecore_x_icccm_init();
44 #endif
45
46    ICCCM_SetIconSizes();
47
48    if (Mode.wm.window)
49      {
50         Atom                wm_props[1];
51
52         wm_props[0] = ECORE_X_ATOM_WM_DELETE_WINDOW;
53         XSetWMProtocols(disp, WinGetXwin(VROOT), wm_props, 1);
54      }
55 }
56
57 int
58 ICCCM_ProcessClientClientMessage(EWin * ewin, XClientMessageEvent * event)
59 {
60    if (event->message_type == ECORE_X_ATOM_WM_CHANGE_STATE)
61      {
62         if (event->data.l[0] == IconicState)
63           {
64              EwinIconify(ewin);
65           }
66         return 1;
67      }
68
69    return 0;
70 }
71
72 int
73 ICCCM_ProcessRootClientMessage(XClientMessageEvent * event)
74 {
75    Atom                a;
76
77    if (event->message_type == ECORE_X_ATOM_WM_PROTOCOLS)
78      {
79         a = event->data.l[0];
80         if (a == ECORE_X_ATOM_WM_DELETE_WINDOW)
81            SessionExit(EEXIT_EXIT, NULL);
82         return 1;
83      }
84
85    return 0;
86 }
87
88 void
89 ICCCM_GetTitle(EWin * ewin)
90 {
91    _EFREE(EwinGetIcccmName(ewin));
92
93    EwinGetIcccmName(ewin) = ecore_x_icccm_title_get(EwinGetClientXwin(ewin));
94
95    EwinChange(ewin, EWIN_CHANGE_NAME);
96 }
97
98 static void
99 ICCCM_GetColormap(EWin * ewin)
100 {
101    XWindowAttributes   xwa;
102
103    ewin->client.cmap = None;
104    if (XGetWindowAttributes(disp, EwinGetClientXwin(ewin), &xwa)
105        && xwa.colormap)
106       ewin->client.cmap = xwa.colormap;
107 }
108
109 void
110 ICCCM_Delete(const EWin * ewin)
111 {
112    if (EwinIsInternal(ewin))
113      {
114         EwinHide((EWin *) ewin);
115         return;
116      }
117
118    if (ewin->icccm.delete_window)
119       ecore_x_icccm_delete_window_send(EwinGetClientXwin(ewin), CurrentTime);
120    else
121       XKillClient(disp, EwinGetClientXwin(ewin));
122 }
123
124 #if 0                           /* Deprecated */
125 void
126 ICCCM_Save(const EWin * ewin)
127 {
128    if (EwinIsInternal(ewin))
129       return;
130
131    ecore_x_icccm_send_save_yourself(EwinGetClientXwin(ewin));
132 }
133 #endif
134
135 void
136 ICCCM_Iconify(const EWin * ewin)
137 {
138    EUnmapWindow(EwinGetClientWin(ewin));
139    ecore_x_icccm_state_set_iconic(EwinGetClientXwin(ewin));
140 }
141
142 void
143 ICCCM_DeIconify(const EWin * ewin)
144 {
145    EMapWindow(EwinGetClientWin(ewin));
146    ecore_x_icccm_state_set_normal(EwinGetClientXwin(ewin));
147 }
148
149 void
150 ICCCM_Withdraw(const EWin * ewin)
151 {
152    /* We have a choice of deleting the WM_STATE property
153     * or changing the value to Withdrawn. Since twm/fvwm does
154     * it that way, we change it to Withdrawn.
155     */
156    ecore_x_icccm_state_set_withdrawn(EwinGetClientXwin(ewin));
157
158    XRemoveFromSaveSet(disp, EwinGetClientXwin(ewin));
159 }
160
161 void
162 ICCCM_SizeMatch(const EWin * ewin, int wi, int hi, int *pwo, int *pho)
163 {
164    int                 w, h;
165    int                 i, j;
166    double              aspect, dw, dh;
167
168    w = wi;
169    h = hi;
170
171    if (w < ewin->icccm.width_min)
172       w = ewin->icccm.width_min;
173    if (w > ewin->icccm.width_max)
174       w = ewin->icccm.width_max;
175    if (h < ewin->icccm.height_min)
176       h = ewin->icccm.height_min;
177    if (h > ewin->icccm.height_max)
178       h = ewin->icccm.height_max;
179    if ((w > 0) && (h > 0))
180      {
181         w -= ewin->icccm.base_w;
182         h -= ewin->icccm.base_h;
183         if ((w > 0) && (h > 0))
184           {
185              aspect = ((double)w) / ((double)h);
186              dw = ewin->icccm.w_inc / 4.;
187              dh = ewin->icccm.h_inc / 4.;
188              if (Mode.mode == MODE_RESIZE_H)
189                {
190                   if (aspect < ewin->icccm.aspect_min)
191                      w = (int)((double)h * ewin->icccm.aspect_min + dw);
192                   else if (aspect > ewin->icccm.aspect_max)
193                      w = (int)((double)h * ewin->icccm.aspect_max + dw);
194                }
195              else if (Mode.mode == MODE_RESIZE_V)
196                {
197                   if (aspect < ewin->icccm.aspect_min)
198                      h = (int)((double)w / ewin->icccm.aspect_min + dh);
199                   else if (aspect > ewin->icccm.aspect_max)
200                      h = (int)((double)w / ewin->icccm.aspect_max + dh);
201                }
202              else
203                {
204                   if (aspect < ewin->icccm.aspect_min)
205                     {
206                        if (ewin->icccm.aspect_min >= 1.)
207                           h = (int)((double)w / ewin->icccm.aspect_min + dh);
208                        else
209                           w = (int)((double)h * ewin->icccm.aspect_min + dw);
210                     }
211                   else if (aspect > ewin->icccm.aspect_max)
212                     {
213                        if (ewin->icccm.aspect_max >= 1.)
214                           h = (int)((double)w / ewin->icccm.aspect_max + dh);
215                        else
216                           w = (int)((double)h * ewin->icccm.aspect_max + dw);
217                     }
218                }
219              i = w / ewin->icccm.w_inc;
220              j = h / ewin->icccm.h_inc;
221              w = i * ewin->icccm.w_inc;
222              h = j * ewin->icccm.h_inc;
223           }
224         w += ewin->icccm.base_w;
225         h += ewin->icccm.base_h;
226      }
227
228    *pwo = w;
229    *pho = h;
230 }
231
232 #if 0                           /* Unused */
233 void
234 ICCCM_MatchSize(EWin * ewin)
235 {
236    ICCCM_SizeMatch(ewin, ewin->client.w, ewin->client.h, &ewin->client.w,
237                    &ewin->client.h);
238 }
239 #endif
240
241 void
242 ICCCM_GetIncrementalSize(EWin * ewin, unsigned int w, unsigned int h,
243                          unsigned int *wi, unsigned int *hi)
244 {
245    *wi = (w - ewin->icccm.base_w) / ewin->icccm.w_inc;
246    *hi = (h - ewin->icccm.base_h) / ewin->icccm.h_inc;
247 }
248
249 void
250 ICCCM_SetSizeConstraints(EWin * ewin, unsigned int wmin, unsigned int hmin,
251                          unsigned int wmax, unsigned int hmax,
252                          unsigned int wbase, unsigned int hbase,
253                          unsigned int winc, unsigned int hinc,
254                          double amin, double amax)
255 {
256    ewin->icccm.width_min = wmin;
257    ewin->icccm.height_min = hmin;
258    ewin->icccm.width_max = wmax;
259    ewin->icccm.height_max = hmax;
260
261    ewin->icccm.base_w = wbase;
262    ewin->icccm.base_h = hbase;
263    ewin->icccm.w_inc = winc;
264    ewin->icccm.h_inc = hinc;
265
266    ewin->icccm.aspect_min = amin;
267    ewin->icccm.aspect_max = amax;
268
269    ewin->props.no_resize_h = (wmin == wmax);
270    ewin->props.no_resize_v = (hmin == hmax);
271 }
272
273 void
274 ICCCM_Configure(EWin * ewin)
275 {
276    XEvent              ev;
277    Window              child;
278
279    if (EwinIsInternal(ewin))
280       return;
281
282    ev.type = ConfigureNotify;
283    ev.xconfigure.display = disp;
284    ev.xconfigure.event = EwinGetClientXwin(ewin);
285    ev.xconfigure.window = EwinGetClientXwin(ewin);
286 #if 0                           /* FIXME - Remove? */
287    Desk               *dsk;
288
289    dsk = EoGetDesk(ewin);
290    ev.xconfigure.x = EoGetX(dsk) + ewin->client.x;
291    ev.xconfigure.y = EoGetY(dsk) + ewin->client.y;
292 #else
293    ev.xconfigure.x = ewin->client.x;
294    ev.xconfigure.y = ewin->client.y;
295 #endif
296    if (Mode.wm.window)
297       ETranslateCoordinates(VROOT, RROOT,
298                             ev.xconfigure.x, ev.xconfigure.y,
299                             &ev.xconfigure.x, &ev.xconfigure.y, &child);
300    ev.xconfigure.width = ewin->client.w;
301    ev.xconfigure.height = ewin->client.h;
302    ev.xconfigure.border_width = 0;
303    ev.xconfigure.above = EoGetXwin(ewin);
304    ev.xconfigure.override_redirect = False;
305    EXSendEvent(EwinGetClientXwin(ewin), StructureNotifyMask, &ev);
306 }
307
308 void
309 ICCCM_AdoptStart(const EWin * ewin)
310 {
311    Window              win = EwinGetClientXwin(ewin);
312
313    if (!EwinIsInternal(ewin))
314       XAddToSaveSet(disp, win);
315 }
316
317 void
318 ICCCM_Adopt(const EWin * ewin)
319 {
320    Window              win = EwinGetClientXwin(ewin);
321
322    if (ewin->icccm.start_iconified)
323       ecore_x_icccm_state_set_iconic(win);
324    else
325       ecore_x_icccm_state_set_normal(win);
326 }
327
328 void
329 ICCCM_Cmap(EWin * ewin)
330 {
331    if (!ewin)
332      {
333         if (Mode.current_cmap)
334           {
335              XUninstallColormap(disp, Mode.current_cmap);
336              Mode.current_cmap = 0;
337           }
338         return;
339      }
340
341    if (EwinIsInternal(ewin))
342       return;
343
344    ICCCM_GetColormap(ewin);
345
346    if ((ewin->client.cmap) && (Mode.current_cmap != ewin->client.cmap))
347      {
348         XWindowAttributes   xwa;
349         int                 i, num;
350         Ecore_X_Window     *wlist;
351
352         num = ecore_x_window_prop_window_list_get(EwinGetClientXwin(ewin),
353                                                   ECORE_X_ATOM_WM_COLORMAP_WINDOWS,
354                                                   &wlist);
355         if (num > 0)
356           {
357              for (i = 0; i < num; i++)
358                {
359                   if (XGetWindowAttributes(disp, wlist[i], &xwa))
360                     {
361                        if (xwa.colormap != WinGetCmap(VROOT))
362                          {
363                             XInstallColormap(disp, xwa.colormap);
364                             Mode.current_cmap = xwa.colormap;
365                          }
366                     }
367                }
368              Efree(wlist);
369              return;
370           }
371         XInstallColormap(disp, ewin->client.cmap);
372         Mode.current_cmap = ewin->client.cmap;
373      }
374 }
375
376 void
377 ICCCM_Focus(const EWin * ewin)
378 {
379    if (EDebug(EDBUG_TYPE_FOCUS))
380      {
381         if (ewin)
382            Eprintf("ICCCM_Focus T=%#lx %#lx %s\n", Mode.events.time,
383                    EwinGetClientXwin(ewin), EwinGetTitle(ewin));
384         else
385            Eprintf("ICCCM_Focus None T=%#lx\n", Mode.events.time);
386      }
387
388    if (!ewin)
389      {
390         XSetInputFocus(disp, WinGetXwin(VROOT), RevertToPointerRoot,
391                        Mode.events.time);
392         HintsSetActiveWindow(None);
393         return;
394      }
395
396    if (ewin->icccm.take_focus)
397      {
398         ecore_x_icccm_take_focus_send(EwinGetClientXwin(ewin),
399                                       Mode.events.time);
400      }
401
402    XSetInputFocus(disp, EwinGetClientXwin(ewin), RevertToPointerRoot,
403                   Mode.events.time);
404
405    HintsSetActiveWindow(EwinGetClientXwin(ewin));
406 }
407
408 void
409 ICCCM_GetGeoms(EWin * ewin)
410 {
411    XSizeHints          hint;
412    long                mask;
413
414    if (XGetWMNormalHints(disp, EwinGetClientXwin(ewin), &hint, &mask))
415      {
416         if (!(ewin->state.placed))
417           {
418              if ((hint.flags & USPosition) || ((hint.flags & PPosition)))
419                {
420                   if ((hint.flags & PPosition) && (!EoIsSticky(ewin)))
421                     {
422                        Desk               *dsk;
423
424                        dsk = EoGetDesk(ewin);
425                        if (!dsk)
426                           dsk = DesksGetCurrent();
427                        ewin->client.x -= EoGetX(dsk);
428                        ewin->client.y -= EoGetY(dsk);
429                        if (ewin->client.x + ewin->client.w >= WinGetW(VROOT))
430                          {
431                             ewin->client.x += EoGetX(dsk);
432                          }
433                        else if (ewin->client.x < 0)
434                          {
435                             ewin->client.x += EoGetX(dsk);
436                          }
437                        if (ewin->client.y + ewin->client.h >= WinGetH(VROOT))
438                          {
439                             ewin->client.y += EoGetY(dsk);
440                          }
441                        else if (ewin->client.y < 0)
442                          {
443                             ewin->client.y += EoGetY(dsk);
444                          }
445                     }
446                   ewin->state.placed = 1;
447                }
448           }
449
450         if (hint.flags & PMinSize)
451           {
452              ewin->icccm.width_min = MAX(0, hint.min_width);
453              ewin->icccm.height_min = MAX(0, hint.min_height);
454           }
455         else
456           {
457              ewin->icccm.width_min = 0;
458              ewin->icccm.height_min = 0;
459           }
460
461         if (hint.flags & PMaxSize)
462           {
463              ewin->icccm.width_max = MIN(hint.max_width, 65535);
464              ewin->icccm.height_max = MIN(hint.max_height, 65535);
465           }
466         else
467           {
468              ewin->icccm.width_max = 65535;
469              ewin->icccm.height_max = 65535;
470           }
471
472         if (hint.flags & PResizeInc)
473           {
474              ewin->icccm.w_inc = MAX(1, hint.width_inc);
475              ewin->icccm.h_inc = MAX(1, hint.height_inc);
476           }
477         else
478           {
479              ewin->icccm.w_inc = 1;
480              ewin->icccm.h_inc = 1;
481           }
482
483         if (hint.flags & PAspect)
484           {
485              if ((hint.min_aspect.y > 0.0) && (hint.min_aspect.x > 0.0))
486                {
487                   ewin->icccm.aspect_min =
488                      ((double)hint.min_aspect.x) / ((double)hint.min_aspect.y);
489                }
490              else
491                {
492                   ewin->icccm.aspect_min = 0.0;
493                }
494              if ((hint.max_aspect.y > 0.0) && (hint.max_aspect.x > 0.0))
495                {
496                   ewin->icccm.aspect_max =
497                      ((double)hint.max_aspect.x) / ((double)hint.max_aspect.y);
498                }
499              else
500                {
501                   ewin->icccm.aspect_max = 65535.0;
502                }
503           }
504         else
505           {
506              ewin->icccm.aspect_min = 0.0;
507              ewin->icccm.aspect_max = 65535.0;
508           }
509
510         if (hint.flags & PBaseSize)
511           {
512              ewin->icccm.base_w = hint.base_width;
513              ewin->icccm.base_h = hint.base_height;
514           }
515         else
516           {
517              ewin->icccm.base_w = ewin->icccm.width_min;
518              ewin->icccm.base_h = ewin->icccm.height_min;
519           }
520
521         if (ewin->icccm.width_min < ewin->icccm.base_w)
522            ewin->icccm.width_min = ewin->icccm.base_w;
523         if (ewin->icccm.height_min < ewin->icccm.base_h)
524            ewin->icccm.height_min = ewin->icccm.base_h;
525
526         if (ewin->icccm.width_max < ewin->icccm.base_w)
527            ewin->icccm.width_max = ewin->icccm.base_w;
528         if (ewin->icccm.height_max < ewin->icccm.base_h)
529            ewin->icccm.height_max = ewin->icccm.base_h;
530
531         if (hint.flags & PWinGravity)
532            ewin->icccm.grav = hint.win_gravity;
533         else
534            ewin->icccm.grav = NorthWestGravity;
535      }
536
537    ewin->props.no_resize_h = (ewin->icccm.width_min == ewin->icccm.width_max);
538    ewin->props.no_resize_v = (ewin->icccm.height_min == ewin->icccm.height_max);
539
540    if (EDebug(EDBUG_TYPE_SNAPS))
541       Eprintf("Snap get icccm %#lx: %4d+%4d %4dx%4d: %s\n",
542               EwinGetClientXwin(ewin), ewin->client.x, ewin->client.y,
543               ewin->client.w, ewin->client.h, EwinGetTitle(ewin));
544 }
545
546 #define TryGroup(e) (((e)->icccm.group != None) && ((e)->icccm.group != EwinGetClientXwin(e)))
547
548 static void
549 ICCCM_GetWmClass(EWin * ewin)
550 {
551    _EFREE(EwinGetIcccmCName(ewin));
552    _EFREE(EwinGetIcccmClass(ewin));
553
554    ecore_x_icccm_name_class_get(EwinGetClientXwin(ewin),
555                                 &EwinGetIcccmCName(ewin),
556                                 &EwinGetIcccmClass(ewin));
557    if (!EwinGetIcccmCName(ewin) && TryGroup(ewin))
558       ecore_x_icccm_name_class_get(ewin->icccm.group,
559                                    &EwinGetIcccmCName(ewin),
560                                    &EwinGetIcccmClass(ewin));
561 }
562
563 static void
564 ICCCM_GetWmCommand(EWin * ewin)
565 {
566    int                 argc;
567    char              **argv, s[4096], *ss;
568
569    _EFREE(ewin->icccm.wm_command);
570
571    argc = ecore_x_window_prop_string_list_get(EwinGetClientXwin(ewin),
572                                               ECORE_X_ATOM_WM_COMMAND, &argv);
573    if ((argc < 0) && TryGroup(ewin))
574       argc = ecore_x_window_prop_string_list_get(ewin->icccm.group,
575                                                  ECORE_X_ATOM_WM_COMMAND,
576                                                  &argv);
577
578    ss = StrlistEncodeEscaped(s, sizeof(s), argv, argc);
579    ewin->icccm.wm_command = Estrdup(ss);
580    StrlistFree(argv, argc);
581 }
582
583 static void
584 ICCCM_GetWmClientMachine(EWin * ewin)
585 {
586    _EFREE(ewin->icccm.wm_machine);
587
588    ewin->icccm.wm_machine =
589       ecore_x_window_prop_string_get(EwinGetClientXwin(ewin),
590                                      ECORE_X_ATOM_WM_CLIENT_MACHINE);
591    if (!ewin->icccm.wm_machine && TryGroup(ewin))
592       ewin->icccm.wm_machine =
593          ecore_x_window_prop_string_get(ewin->icccm.group,
594                                         ECORE_X_ATOM_WM_CLIENT_MACHINE);
595 }
596
597 static void
598 ICCCM_GetWmIconName(EWin * ewin)
599 {
600    _EFREE(ewin->icccm.wm_icon_name);
601
602    ewin->icccm.wm_icon_name =
603       ecore_x_window_prop_string_get(EwinGetClientXwin(ewin),
604                                      ECORE_X_ATOM_WM_ICON_NAME);
605    if (!ewin->icccm.wm_icon_name && TryGroup(ewin))
606       ewin->icccm.wm_icon_name =
607          ecore_x_window_prop_string_get(ewin->icccm.group,
608                                         ECORE_X_ATOM_WM_ICON_NAME);
609 }
610
611 static void
612 ICCCM_GetWmWindowRole(EWin * ewin)
613 {
614    _EFREE(ewin->icccm.wm_role);
615    ewin->icccm.wm_role =
616       ecore_x_window_prop_string_get(EwinGetClientXwin(ewin),
617                                      ECORE_X_ATOM_WM_WINDOW_ROLE);
618 }
619
620 void
621 ICCCM_GetInfo(EWin * ewin)
622 {
623    ICCCM_GetWmClass(ewin);
624    ICCCM_GetWmCommand(ewin);
625    ICCCM_GetWmClientMachine(ewin);
626    ICCCM_GetWmIconName(ewin);
627    ICCCM_GetWmWindowRole(ewin);
628 }
629
630 static void
631 ICCCM_GetWmHints(EWin * ewin)
632 {
633    XWMHints           *hint;
634
635    hint = XGetWMHints(disp, EwinGetClientXwin(ewin));
636    if (!hint)
637       return;
638
639    /* I have to make sure the thing i'm docking is a dock app */
640    if ((hint->flags & StateHint) && (hint->initial_state == WithdrawnState))
641      {
642         if (hint->flags & (StateHint | IconWindowHint | IconPositionHint |
643                            WindowGroupHint))
644           {
645              if ((hint->icon_x == 0) && (hint->icon_y == 0)
646                  && hint->window_group == EwinGetClientXwin(ewin))
647                 ewin->state.docked = 1;
648           }
649      }
650
651    ewin->icccm.need_input =
652       ((hint->flags & InputHint) && (!hint->input)) ? 0 : 1;
653
654    ewin->icccm.start_iconified =
655       ((hint->flags & StateHint) &&
656        (hint->initial_state == IconicState)) ? 1 : 0;
657
658    if (hint->flags & IconPixmapHint)
659      {
660         if (ewin->icccm.icon_pmap != hint->icon_pixmap)
661           {
662              ewin->icccm.icon_pmap = hint->icon_pixmap;
663              EwinChange(ewin, EWIN_CHANGE_ICON_PMAP);
664           }
665      }
666    else
667      {
668         ewin->icccm.icon_pmap = None;
669      }
670
671    ewin->icccm.icon_mask =
672       (hint->flags & IconMaskHint) ? hint->icon_mask : None;
673
674    ewin->icccm.icon_win =
675       (hint->flags & IconWindowHint) ? hint->icon_window : None;
676
677    ewin->icccm.group =
678       (hint->flags & WindowGroupHint) ? hint->window_group : None;
679
680    if (hint->flags & XUrgencyHint)
681      {
682         if (!ewin->state.attention)
683            EwinChange(ewin, EWIN_CHANGE_ATTENTION);
684         ewin->icccm.urgency = 1;
685         ewin->state.attention = 1;
686      }
687    else
688      {
689         ewin->icccm.urgency = 0;
690      }
691
692    if (ewin->icccm.group == EwinGetClientXwin(ewin))
693      {
694         ewin->icccm.is_group_leader = 1;
695      }
696    else
697      {
698         ewin->icccm.is_group_leader = 0;
699      }
700
701    XFree(hint);
702 }
703
704 static void
705 ICCCM_GetWmProtocols(EWin * ewin)
706 {
707    Atom               *prop;
708    int                 i, num;
709
710    if (XGetWMProtocols(disp, EwinGetClientXwin(ewin), &prop, &num))
711      {
712         ewin->icccm.take_focus = 0;
713         ewin->icccm.delete_window = 0;
714         for (i = 0; i < num; i++)
715           {
716              if (prop[i] == ECORE_X_ATOM_WM_TAKE_FOCUS)
717                 ewin->icccm.take_focus = ewin->icccm.need_input = 1;
718              else if (prop[i] == ECORE_X_ATOM_WM_DELETE_WINDOW)
719                 ewin->icccm.delete_window = 1;
720 #if USE_XSYNC
721              else if (prop[i] == ECORE_X_ATOM_NET_WM_SYNC_REQUEST)
722                {
723                   unsigned int        c;
724
725                   ewin->ewmh.sync_request_enable = 1;
726                   ecore_x_window_prop_card32_get(EwinGetClientXwin(ewin),
727                                                  ECORE_X_ATOM_NET_WM_SYNC_REQUEST_COUNTER,
728                                                  &c, 1);
729                   ewin->ewmh.sync_request_counter = c;
730                }
731 #endif
732           }
733         XFree(prop);
734      }
735 }
736
737 static void
738 ICCCM_GetWmTransientFor(EWin * ewin)
739 {
740    Window              win;
741
742    ewin->icccm.transient = 0;
743    ewin->icccm.transient_for = None;
744    if (XGetTransientForHint(disp, EwinGetClientXwin(ewin), &win))
745      {
746         ewin->icccm.transient = 1;
747         ewin->icccm.transient_for = win;
748      }
749 }
750
751 static void
752 ICCCM_GetWmClientLeader(EWin * ewin)
753 {
754    int                 num;
755    Ecore_X_Window      cleader;
756
757    num = ecore_x_window_prop_window_get(EwinGetClientXwin(ewin),
758                                         ECORE_X_ATOM_WM_CLIENT_LEADER,
759                                         &cleader, 1);
760    if (num > 0)
761      {
762         ewin->icccm.client_leader = cleader;
763         if (!ewin->icccm.group)
764            ewin->icccm.group = cleader;
765      }
766 }
767
768 void
769 ICCCM_GetHints(EWin * ewin)
770 {
771    ICCCM_GetWmHints(ewin);
772    ICCCM_GetWmProtocols(ewin);
773    ICCCM_GetWmTransientFor(ewin);
774    ICCCM_GetWmClientLeader(ewin);
775 }
776
777 void
778 ICCCM_SetIconSizes(void)
779 {
780    XIconSize          *is;
781
782    is = XAllocIconSize();
783    is->min_width = 8;
784    is->min_height = 8;
785    is->max_width = 48;
786    is->max_height = 48;
787    is->width_inc = 1;
788    is->height_inc = 1;
789    XSetIconSizes(disp, WinGetXwin(VROOT), is, 1);
790    XFree(is);
791 }
792
793 /*
794  * Process received window property change
795  */
796 int
797 ICCCM_ProcessPropertyChange(EWin * ewin, Atom atom_change)
798 {
799    if (atom_change == ECORE_X_ATOM_WM_NAME)
800      {
801         ICCCM_GetTitle(ewin);
802         return 1;
803      }
804
805    /* ICCCM_GetHints */
806    if (atom_change == ECORE_X_ATOM_WM_HINTS)
807      {
808         ICCCM_GetWmHints(ewin);
809         return 1;
810      }
811    if (atom_change == ECORE_X_ATOM_WM_PROTOCOLS)
812      {
813         ICCCM_GetWmProtocols(ewin);
814         return 1;
815      }
816    if (atom_change == ECORE_X_ATOM_WM_TRANSIENT_FOR)
817      {
818         ICCCM_GetWmTransientFor(ewin);
819         return 1;
820      }
821    if (atom_change == ECORE_X_ATOM_WM_CLIENT_LEADER)
822      {
823         ICCCM_GetWmClientLeader(ewin);
824         return 1;
825      }
826
827    /* ICCCM_GetInfo */
828    if (atom_change == ECORE_X_ATOM_WM_ICON_NAME)
829      {
830         ICCCM_GetWmIconName(ewin);
831         return 1;
832      }
833 #if 1                           /* FIXME - Any reason to process these? */
834    if (atom_change == ECORE_X_ATOM_WM_CLASS)
835      {
836         ICCCM_GetWmClass(ewin);
837         return 1;
838      }
839    if (atom_change == ECORE_X_ATOM_WM_COMMAND)
840      {
841         ICCCM_GetWmCommand(ewin);
842         return 1;
843      }
844    if (atom_change == ECORE_X_ATOM_WM_CLIENT_MACHINE)
845      {
846         ICCCM_GetWmClientMachine(ewin);
847         return 1;
848      }
849    if (atom_change == ECORE_X_ATOM_WM_WINDOW_ROLE)
850      {
851         ICCCM_GetWmWindowRole(ewin);
852         return 1;
853      }
854 #endif
855
856    if (atom_change == ECORE_X_ATOM_WM_COLORMAP_WINDOWS)
857      {
858         ICCCM_Cmap(ewin);
859         return 1;
860      }
861
862    if (atom_change == ECORE_X_ATOM_WM_NORMAL_HINTS)
863      {
864         ICCCM_GetGeoms(ewin);
865         return 1;
866      }
867
868    return 0;
869 }
870
871 #if USE_XSYNC
872 int
873 EwinSyncRequestSend(EWin * ewin)
874 {
875    long long           count;
876
877    if (!ewin->ewmh.sync_request_enable || EServerIsGrabbed())
878       return 0;
879
880    count = ++ewin->ewmh.sync_request_count;
881
882    if (count == 0)
883       ewin->ewmh.sync_request_count = ++count;
884    ecore_x_client_message32_send(EwinGetClientXwin(ewin),
885                                  ECORE_X_ATOM_WM_PROTOCOLS,
886                                  StructureNotifyMask,
887                                  ECORE_X_ATOM_NET_WM_SYNC_REQUEST,
888                                  Mode.events.time,
889                                  (long)(count & 0xffffffff),
890                                  (long)(count >> 32), 0);
891
892    return 1;
893 }
894
895 void
896 EwinSyncRequestWait(EWin * ewin)
897 {
898    XSyncWaitCondition  xswc[2];
899    double              t;
900
901    if (!ewin->ewmh.sync_request_enable || EServerIsGrabbed())
902       return;
903
904    xswc[0].trigger.counter = ewin->ewmh.sync_request_counter;
905    xswc[0].trigger.value_type = XSyncAbsolute;
906    XSyncIntsToValue(&xswc[0].trigger.wait_value,
907                     ewin->ewmh.sync_request_count & 0xffffffff,
908                     ewin->ewmh.sync_request_count >> 32);
909    xswc[0].trigger.test_type = XSyncPositiveComparison;
910    XSyncIntsToValue(&xswc[0].event_threshold, 0, 0);
911
912    xswc[1].trigger.counter = Mode.display.server_time;
913    xswc[1].trigger.value_type = XSyncRelative;
914    XSyncIntsToValue(&xswc[1].trigger.wait_value, 200, 0);       /* 200 ms */
915    xswc[1].trigger.test_type = XSyncPositiveComparison;
916    XSyncIntsToValue(&xswc[1].event_threshold, 0, 0);
917
918    t = GetTime();
919    XSyncAwait(disp, xswc, 2);
920    if (EDebug(EDBUG_TYPE_SYNC))
921       Eprintf("Sync t=%#lx c=%llx: Delay=%8.6lf us\n",
922               xswc[0].trigger.counter, ewin->ewmh.sync_request_count,
923               GetTime() - t);
924 }
925 #endif /* USE_XSYNC */