chiark / gitweb /
Imported Debian patch 1.0.0-5
[e16] / src / ewmh.c
1 /*
2  * Copyright (C) 2003-2009 Kim Woelders
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to
6  * deal in the Software without restriction, including without limitation the
7  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8  * sell copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies of the Software, its documentation and marketing & publicity
13  * materials, and acknowledgment shall be given in the documentation, materials
14  * and software packages that this Software was used.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23 /*
24  * Extended Window Manager Hints.
25  */
26 #include "E.h"
27 #include "desktops.h"
28 #include "e16-ecore_hints.h"
29 #include "ewins.h"
30 #include "hints.h"
31
32 /*
33  * _NET_WM_MOVERESIZE client message actions
34  */
35 #define _NET_WM_MOVERESIZE_SIZE_TOPLEFT     0
36 #define _NET_WM_MOVERESIZE_SIZE_TOP         1
37 #define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT    2
38 #define _NET_WM_MOVERESIZE_SIZE_RIGHT       3
39 #define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4
40 #define _NET_WM_MOVERESIZE_SIZE_BOTTOM      5
41 #define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT  6
42 #define _NET_WM_MOVERESIZE_SIZE_LEFT        7
43 #define _NET_WM_MOVERESIZE_MOVE             8
44 #define _NET_WM_MOVERESIZE_SIZE_KEYBOARD    9
45 #define _NET_WM_MOVERESIZE_MOVE_KEYBOARD   10
46 #define _NET_WM_MOVERESIZE_CANCEL          11
47
48 /* Window state property change actions */
49 #define _NET_WM_STATE_REMOVE    0
50 #define _NET_WM_STATE_ADD       1
51 #define _NET_WM_STATE_TOGGLE    2
52
53 /* Source indication */
54 #define _NET_WM_SOURCE_UNKNOWN  0
55 #define _NET_WM_SOURCE_APP      1
56 #define _NET_WM_SOURCE_USER     2
57
58 #define OPSRC(src) (((src) == _NET_WM_SOURCE_USER) ? _NET_WM_SOURCE_USER : _NET_WM_SOURCE_APP)
59
60 /*
61  * Set/clear Atom in list
62  */
63 static void
64 atom_list_set(Ecore_X_Atom * atoms, int size, int *count, Ecore_X_Atom atom,
65               int set)
66 {
67    int                 i, n, in_list;
68
69    n = *count;
70
71    /* Check if atom is in list or not (+get index) */
72    for (i = 0; i < n; i++)
73       if (atoms[i] == atom)
74          break;
75    in_list = i < n;
76
77    if (set && !in_list)
78      {
79         /* Add it (if space left) */
80         if (n < size)
81            atoms[n++] = atom;
82         *count = n;
83      }
84    else if (!set && in_list)
85      {
86         /* Remove it */
87         atoms[i] = atoms[--n];
88         *count = n;
89      }
90 }
91
92 /*
93  * Initialize EWMH stuff
94  */
95 void
96 EWMH_Init(Window win_wm_check)
97 {
98    Ecore_X_Atom        atom_list[64];
99    int                 atom_count;
100
101 #ifndef USE_ECORE_X
102    ecore_x_netwm_init();
103 #endif
104
105    atom_count = 0;
106
107    atom_list[atom_count++] = ECORE_X_ATOM_NET_SUPPORTED;
108    atom_list[atom_count++] = ECORE_X_ATOM_NET_SUPPORTING_WM_CHECK;
109
110    atom_list[atom_count++] = ECORE_X_ATOM_NET_NUMBER_OF_DESKTOPS;
111    atom_list[atom_count++] = ECORE_X_ATOM_NET_DESKTOP_GEOMETRY;
112    atom_list[atom_count++] = ECORE_X_ATOM_NET_DESKTOP_NAMES;
113    atom_list[atom_count++] = ECORE_X_ATOM_NET_CURRENT_DESKTOP;
114    atom_list[atom_count++] = ECORE_X_ATOM_NET_DESKTOP_VIEWPORT;
115    atom_list[atom_count++] = ECORE_X_ATOM_NET_WORKAREA;
116    atom_list[atom_count++] = ECORE_X_ATOM_NET_VIRTUAL_ROOTS;
117    atom_list[atom_count++] = ECORE_X_ATOM_NET_SHOWING_DESKTOP;
118
119    atom_list[atom_count++] = ECORE_X_ATOM_NET_ACTIVE_WINDOW;
120    atom_list[atom_count++] = ECORE_X_ATOM_NET_CLIENT_LIST;
121    atom_list[atom_count++] = ECORE_X_ATOM_NET_CLIENT_LIST_STACKING;
122
123    atom_list[atom_count++] = ECORE_X_ATOM_NET_CLOSE_WINDOW;
124    atom_list[atom_count++] = ECORE_X_ATOM_NET_MOVERESIZE_WINDOW;
125    atom_list[atom_count++] = ECORE_X_ATOM_NET_WM_MOVERESIZE;
126
127    atom_list[atom_count++] = ECORE_X_ATOM_NET_WM_NAME;
128    atom_list[atom_count++] = ECORE_X_ATOM_NET_WM_ICON_NAME;
129    atom_list[atom_count++] = ECORE_X_ATOM_NET_WM_DESKTOP;
130
131    atom_list[atom_count++] = ECORE_X_ATOM_NET_WM_WINDOW_TYPE;
132    atom_list[atom_count++] = ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DESKTOP;
133    atom_list[atom_count++] = ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DOCK;
134    atom_list[atom_count++] = ECORE_X_ATOM_NET_WM_WINDOW_TYPE_TOOLBAR;
135    atom_list[atom_count++] = ECORE_X_ATOM_NET_WM_WINDOW_TYPE_MENU;
136    atom_list[atom_count++] = ECORE_X_ATOM_NET_WM_WINDOW_TYPE_UTILITY;
137    atom_list[atom_count++] = ECORE_X_ATOM_NET_WM_WINDOW_TYPE_SPLASH;
138    atom_list[atom_count++] = ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DIALOG;
139    atom_list[atom_count++] = ECORE_X_ATOM_NET_WM_WINDOW_TYPE_NORMAL;
140
141    atom_list[atom_count++] = ECORE_X_ATOM_NET_WM_STATE;
142    atom_list[atom_count++] = ECORE_X_ATOM_NET_WM_STATE_MODAL;
143    atom_list[atom_count++] = ECORE_X_ATOM_NET_WM_STATE_STICKY;
144    atom_list[atom_count++] = ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_VERT;
145    atom_list[atom_count++] = ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_HORZ;
146    atom_list[atom_count++] = ECORE_X_ATOM_NET_WM_STATE_SHADED;
147    atom_list[atom_count++] = ECORE_X_ATOM_NET_WM_STATE_SKIP_TASKBAR;
148    atom_list[atom_count++] = ECORE_X_ATOM_NET_WM_STATE_SKIP_PAGER;
149    atom_list[atom_count++] = ECORE_X_ATOM_NET_WM_STATE_HIDDEN;
150    atom_list[atom_count++] = ECORE_X_ATOM_NET_WM_STATE_FULLSCREEN;
151    atom_list[atom_count++] = ECORE_X_ATOM_NET_WM_STATE_ABOVE;
152    atom_list[atom_count++] = ECORE_X_ATOM_NET_WM_STATE_BELOW;
153    atom_list[atom_count++] = ECORE_X_ATOM_NET_WM_STATE_DEMANDS_ATTENTION;
154
155    atom_list[atom_count++] = ECORE_X_ATOM_NET_WM_ALLOWED_ACTIONS;
156    atom_list[atom_count++] = ECORE_X_ATOM_NET_WM_ACTION_MOVE;
157    atom_list[atom_count++] = ECORE_X_ATOM_NET_WM_ACTION_RESIZE;
158    atom_list[atom_count++] = ECORE_X_ATOM_NET_WM_ACTION_MINIMIZE;
159    atom_list[atom_count++] = ECORE_X_ATOM_NET_WM_ACTION_SHADE;
160    atom_list[atom_count++] = ECORE_X_ATOM_NET_WM_ACTION_STICK;
161    atom_list[atom_count++] = ECORE_X_ATOM_NET_WM_ACTION_MAXIMIZE_HORZ;
162    atom_list[atom_count++] = ECORE_X_ATOM_NET_WM_ACTION_MAXIMIZE_VERT;
163    atom_list[atom_count++] = ECORE_X_ATOM_NET_WM_ACTION_FULLSCREEN;
164    atom_list[atom_count++] = ECORE_X_ATOM_NET_WM_ACTION_CHANGE_DESKTOP;
165    atom_list[atom_count++] = ECORE_X_ATOM_NET_WM_ACTION_CLOSE;
166    atom_list[atom_count++] = ECORE_X_ATOM_NET_WM_ACTION_ABOVE;
167    atom_list[atom_count++] = ECORE_X_ATOM_NET_WM_ACTION_BELOW;
168
169    atom_list[atom_count++] = ECORE_X_ATOM_NET_WM_STRUT_PARTIAL;
170    atom_list[atom_count++] = ECORE_X_ATOM_NET_WM_STRUT;
171
172    atom_list[atom_count++] = ECORE_X_ATOM_NET_FRAME_EXTENTS;
173    atom_list[atom_count++] = ECORE_X_ATOM_NET_WM_WINDOW_OPACITY;
174
175    ecore_x_window_prop_atom_set(WinGetXwin(VROOT),
176                                 ECORE_X_ATOM_NET_SUPPORTED, atom_list,
177                                 atom_count);
178
179    /* Set WM info properties */
180    ecore_x_netwm_wm_identify(WinGetXwin(VROOT), win_wm_check, e_wm_name);
181 }
182
183 /*
184  * Desktops
185  */
186
187 void
188 EWMH_SetDesktopCount(void)
189 {
190    ecore_x_netwm_desk_count_set(WinGetXwin(VROOT), DesksGetNumber());
191 }
192
193 void
194 EWMH_SetDesktopRoots(void)
195 {
196    int                 i, n_desks;
197    Ecore_X_Window     *wl;
198
199    n_desks = DesksGetNumber();
200    wl = EMALLOC(Ecore_X_Window, n_desks);
201    if (!wl)
202       return;
203
204    for (i = 0; i < n_desks; i++)
205       wl[i] = EoGetXwin(DeskGet(i));
206
207    ecore_x_netwm_desk_roots_set(WinGetXwin(VROOT), wl, n_desks);
208
209    Efree(wl);
210 }
211
212 void
213 EWMH_SetDesktopNames(void)
214 {
215    /* Fall back to defaults */
216    ecore_x_netwm_desk_names_set(WinGetXwin(VROOT), NULL, DesksGetNumber());
217 }
218
219 void
220 EWMH_SetDesktopSize(void)
221 {
222    int                 ax, ay;
223
224    DesksGetAreaSize(&ax, &ay);
225    ecore_x_netwm_desk_size_set(WinGetXwin(VROOT), ax * WinGetW(VROOT),
226                                ay * WinGetH(VROOT));
227 }
228
229 void
230 EWMH_SetWorkArea(void)
231 {
232    unsigned int       *p_coord;
233    int                 n_coord, i, n_desks;
234
235    n_desks = DesksGetNumber();
236    n_coord = 4 * n_desks;
237    p_coord = EMALLOC(unsigned int, n_coord);
238
239    if (!p_coord)
240       return;
241
242    for (i = 0; i < n_desks; i++)
243      {
244         p_coord[4 * i] = 0;
245         p_coord[4 * i + 1] = 0;
246         p_coord[4 * i + 2] = WinGetW(VROOT);
247         p_coord[4 * i + 3] = WinGetH(VROOT);
248      }
249
250    ecore_x_netwm_desk_workareas_set(WinGetXwin(VROOT), p_coord, n_desks);
251
252    Efree(p_coord);
253 }
254
255 void
256 EWMH_SetCurrentDesktop(void)
257 {
258    ecore_x_netwm_desk_current_set(WinGetXwin(VROOT), DesksGetCurrentNum());
259 }
260
261 void
262 EWMH_SetDesktopViewport(void)
263 {
264    unsigned int       *p_coord;
265    int                 n_coord, i, ax, ay, n_desks;
266
267    n_desks = DesksGetNumber();
268    n_coord = 2 * n_desks;
269    p_coord = EMALLOC(unsigned int, n_coord);
270
271    if (!p_coord)
272       return;
273
274    for (i = 0; i < n_desks; i++)
275      {
276         DeskGetArea(DeskGet(i), &ax, &ay);
277         p_coord[2 * i] = ax * WinGetW(VROOT);
278         p_coord[2 * i + 1] = ay * WinGetH(VROOT);
279      }
280
281    ecore_x_netwm_desk_viewports_set(WinGetXwin(VROOT), p_coord, n_desks);
282
283    Efree(p_coord);
284 }
285
286 void
287 EWMH_SetShowingDesktop(int on)
288 {
289    ecore_x_netwm_showing_desktop_set(WinGetXwin(VROOT), on);
290 }
291
292 /*
293  * Window status
294  */
295
296 void
297 EWMH_SetClientList(void)
298 {
299    Ecore_X_Window     *wl;
300    int                 i, num;
301    EWin               *const *lst;
302
303    /* Mapping order */
304    lst = EwinListOrderGet(&num);
305    if (num > 0)
306      {
307         wl = EMALLOC(Ecore_X_Window, num);
308         for (i = 0; i < num; i++)
309            wl[i] = EwinGetClientXwin(lst[i]);
310         ecore_x_netwm_client_list_set(WinGetXwin(VROOT), wl, num);
311         Efree(wl);
312      }
313    else
314      {
315         ecore_x_netwm_client_list_set(WinGetXwin(VROOT), NULL, 0);
316      }
317 }
318
319 void
320 EWMH_SetClientStacking(void)
321 {
322    Ecore_X_Window     *wl;
323    int                 i, num;
324    EWin               *const *lst;
325
326    /* Stacking order */
327    lst = EwinListStackGet(&num);
328    if (num > 0)
329      {
330         wl = EMALLOC(Ecore_X_Window, num);
331         for (i = 0; i < num; i++)
332            wl[i] = EwinGetClientXwin(lst[num - i - 1]);
333         ecore_x_netwm_client_list_stacking_set(WinGetXwin(VROOT), wl, num);
334         Efree(wl);
335      }
336    else
337      {
338         ecore_x_netwm_client_list_stacking_set(WinGetXwin(VROOT), NULL, 0);
339      }
340 }
341
342 void
343 EWMH_SetActiveWindow(Window win)
344 {
345    static Window       win_last_set = None;
346
347    if (win == win_last_set)
348       return;
349
350    ecore_x_netwm_client_active_set(WinGetXwin(VROOT), win);
351    win_last_set = win;
352 }
353
354 /*
355  * Functions that set X11-properties from E-window internals
356  */
357
358 void
359 EWMH_SetWindowName(Window win, const char *name)
360 {
361    const char         *str;
362
363    str = EstrInt2Enc(name, 1);
364    ecore_x_netwm_name_set(win, str);
365    EstrInt2EncFree(str, 1);
366 }
367
368 void
369 EWMH_SetWindowDesktop(const EWin * ewin)
370 {
371    unsigned int        val;
372
373    if (EoIsSticky(ewin))
374       val = 0xFFFFFFFF;
375    else
376       val = EoGetDeskNum(ewin);
377    ecore_x_netwm_desktop_set(EwinGetClientXwin(ewin), val);
378 }
379
380 void
381 EWMH_SetWindowState(const EWin * ewin)
382 {
383    Ecore_X_Atom        atom_list[64];
384    int                 len = sizeof(atom_list) / sizeof(Ecore_X_Atom);
385    int                 atom_count;
386
387    atom_count = 0;
388    atom_list_set(atom_list, len, &atom_count, ECORE_X_ATOM_NET_WM_STATE_MODAL,
389                  ewin->state.modal);
390    atom_list_set(atom_list, len, &atom_count, ECORE_X_ATOM_NET_WM_STATE_STICKY,
391                  EoIsSticky(ewin));
392    atom_list_set(atom_list, len, &atom_count, ECORE_X_ATOM_NET_WM_STATE_SHADED,
393                  ewin->state.shaded);
394    atom_list_set(atom_list, len, &atom_count,
395                  ECORE_X_ATOM_NET_WM_STATE_SKIP_TASKBAR,
396                  ewin->props.skip_ext_task);
397    atom_list_set(atom_list, len, &atom_count, ECORE_X_ATOM_NET_WM_STATE_HIDDEN,
398                  ewin->state.iconified || ewin->state.shaded);
399    atom_list_set(atom_list, len, &atom_count,
400                  ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_VERT,
401                  ewin->state.maximized_vert);
402    atom_list_set(atom_list, len, &atom_count,
403                  ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_HORZ,
404                  ewin->state.maximized_horz);
405    atom_list_set(atom_list, len, &atom_count,
406                  ECORE_X_ATOM_NET_WM_STATE_FULLSCREEN, ewin->state.fullscreen);
407    atom_list_set(atom_list, len, &atom_count,
408                  ECORE_X_ATOM_NET_WM_STATE_SKIP_PAGER,
409                  ewin->props.skip_ext_pager);
410    atom_list_set(atom_list, len, &atom_count, ECORE_X_ATOM_NET_WM_STATE_ABOVE,
411                  EoGetLayer(ewin) >= 6);
412    atom_list_set(atom_list, len, &atom_count, ECORE_X_ATOM_NET_WM_STATE_BELOW,
413                  EoGetLayer(ewin) <= 2);
414    atom_list_set(atom_list, len, &atom_count,
415                  ECORE_X_ATOM_NET_WM_STATE_DEMANDS_ATTENTION,
416                  ewin->state.attention);
417
418    ecore_x_window_prop_atom_set(EwinGetClientXwin(ewin),
419                                 ECORE_X_ATOM_NET_WM_STATE, atom_list,
420                                 atom_count);
421 }
422
423 void
424 EWMH_SetWindowBorder(const EWin * ewin)
425 {
426    unsigned int        val[4];
427
428    if (ewin->border)
429      {
430         int                 bl, br, bt, bb;
431
432         EwinBorderGetSize(ewin, &bl, &br, &bt, &bb);
433         val[0] = (unsigned int)bl;
434         val[1] = (unsigned int)br;
435         val[2] = (unsigned int)bt;
436         val[3] = (unsigned int)bb;
437      }
438    else
439       val[0] = val[1] = val[2] = val[3] = 0;
440
441    ecore_x_window_prop_card32_set(EwinGetClientXwin(ewin),
442                                   ECORE_X_ATOM_NET_FRAME_EXTENTS, val, 4);
443 }
444
445 void
446 EWMH_SetWindowOpacity(const EWin * ewin)
447 {
448    ecore_x_netwm_opacity_set(EwinGetClientXwin(ewin), ewin->ewmh.opacity);
449    ecore_x_netwm_opacity_set(EoGetXwin(ewin), ewin->ewmh.opacity);
450 }
451
452 /*
453  * Functions that set E-window internals from X11-properties
454  */
455
456 static void
457 EWMH_GetWindowName(EWin * ewin)
458 {
459    char               *val;
460
461    _EFREE(ewin->ewmh.wm_name);
462
463    ecore_x_netwm_name_get(EwinGetClientXwin(ewin), &val);
464    if (!val)
465       return;
466    ewin->ewmh.wm_name = EstrUtf82Int(val, 0);
467    Efree(val);
468
469    EwinChange(ewin, EWIN_CHANGE_NAME);
470 }
471
472 static void
473 EWMH_GetWindowIconName(EWin * ewin)
474 {
475    char               *val;
476
477    _EFREE(ewin->ewmh.wm_icon_name);
478
479    ecore_x_netwm_icon_name_get(EwinGetClientXwin(ewin), &val);
480    if (!val)
481       return;
482    ewin->ewmh.wm_icon_name = EstrUtf82Int(val, 0);
483    Efree(val);
484
485    EwinChange(ewin, EWIN_CHANGE_ICON_NAME);
486 }
487
488 static void
489 EWMH_GetWindowDesktop(EWin * ewin)
490 {
491    int                 num;
492    unsigned int        desk;
493
494    num = ecore_x_netwm_desktop_get(EwinGetClientXwin(ewin), &desk);
495    if (num <= 0)
496       return;
497
498    if (desk == 0xFFFFFFFF)
499      {
500         /* It is possible to distinguish between "sticky" and "on all desktops". */
501         /* E doesn't */
502         EoSetSticky(ewin, 1);
503      }
504    else
505      {
506         EoSetDesk(ewin, DeskGet(desk));
507         EoSetSticky(ewin, 0);
508      }
509    EwinChange(ewin, EWIN_CHANGE_DESKTOP);
510 }
511
512 static void
513 EWMH_GetWindowState(EWin * ewin)
514 {
515    Ecore_X_Atom       *p_atoms, atom;
516    int                 i, n_atoms;
517
518    n_atoms = ecore_x_window_prop_atom_list_get(EwinGetClientXwin(ewin),
519                                                ECORE_X_ATOM_NET_WM_STATE,
520                                                &p_atoms);
521    if (n_atoms <= 0)
522       return;
523
524    /* We must clear/set all according to not present/present */
525 /* EoSetSticky(ewin, 0); Do not override if set via _NET_WM_DESKTOP */
526    ewin->state.shaded = 0;
527    ewin->state.modal = 0;
528    ewin->props.skip_ext_task = ewin->props.skip_ext_pager = 0;
529    ewin->state.maximized_horz = ewin->state.maximized_vert = 0;
530    ewin->state.fullscreen = ewin->state.attention = 0;
531 /* ewin->layer = No ... TBD */
532
533    for (i = 0; i < n_atoms; i++)
534      {
535         atom = p_atoms[i];
536         if (atom == ECORE_X_ATOM_NET_WM_STATE_MODAL)
537            ewin->state.modal = 1;
538         else if (atom == ECORE_X_ATOM_NET_WM_STATE_STICKY)
539            EoSetSticky(ewin, 1);
540         else if (atom == ECORE_X_ATOM_NET_WM_STATE_SHADED)
541            ewin->state.shaded = 1;
542         else if (atom == ECORE_X_ATOM_NET_WM_STATE_SKIP_TASKBAR)
543            ewin->props.skip_ext_task = 1;
544         else if (atom == ECORE_X_ATOM_NET_WM_STATE_SKIP_PAGER)
545            ewin->props.skip_ext_pager = 1;
546         else if (atom == ECORE_X_ATOM_NET_WM_STATE_HIDDEN)
547            ;                    /* ewin->state.iconified = 1; No - WM_STATE does this */
548         else if (atom == ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_VERT)
549            ewin->state.maximized_vert = 1;
550         else if (atom == ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_HORZ)
551            ewin->state.maximized_horz = 1;
552         else if (atom == ECORE_X_ATOM_NET_WM_STATE_FULLSCREEN)
553            ewin->state.fullscreen = 1;
554         else if (atom == ECORE_X_ATOM_NET_WM_STATE_ABOVE)
555            EoSetLayer(ewin, 6);
556         else if (atom == ECORE_X_ATOM_NET_WM_STATE_BELOW)
557            EoSetLayer(ewin, 2);
558         else if (atom == ECORE_X_ATOM_NET_WM_STATE_DEMANDS_ATTENTION)
559            ewin->state.attention = 1;
560      }
561    Efree(p_atoms);
562 }
563
564 static void
565 EWMH_GetWindowType(EWin * ewin)
566 {
567    Ecore_X_Atom       *p_atoms, atom;
568    int                 n_atoms, i;
569
570    ewin->ewmh.type.all = 0;
571
572    n_atoms = ecore_x_window_prop_atom_list_get(EwinGetClientXwin(ewin),
573                                                ECORE_X_ATOM_NET_WM_WINDOW_TYPE,
574                                                &p_atoms);
575    if (n_atoms <= 0)
576      {
577         if (EwinIsTransient(ewin))
578            ewin->ewmh.type.b.dialog = 1;
579         else
580            ewin->ewmh.type.b.normal = 1;
581         return;
582      }
583
584    for (i = 0; i < n_atoms; i++)
585      {
586         atom = p_atoms[i];
587         if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DESKTOP)
588            ewin->ewmh.type.b.desktop = 1;
589         else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DOCK)
590            ewin->ewmh.type.b.dock = 1;
591         else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_UTILITY)
592            ewin->ewmh.type.b.utility = 1;
593         else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_TOOLBAR)
594            ewin->ewmh.type.b.toolbar = 1;
595         else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_MENU)
596            ewin->ewmh.type.b.menu = 1;
597         else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_SPLASH)
598            ewin->ewmh.type.b.splash = 1;
599         else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DIALOG)
600            ewin->ewmh.type.b.dialog = 1;
601         else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_NORMAL)
602            ewin->ewmh.type.b.normal = 1;
603      }
604
605    Efree(p_atoms);
606 }
607
608 static void
609 EWMH_GetWindowIcons(EWin * ewin)
610 {
611    unsigned int       *val;
612    int                 num;
613
614    Efree(ewin->ewmh.wm_icon);
615    ewin->ewmh.wm_icon = NULL;
616
617    num = ecore_x_window_prop_card32_list_get(EwinGetClientXwin(ewin),
618                                              ECORE_X_ATOM_NET_WM_ICON, &val);
619    ewin->ewmh.wm_icon_len = num;
620    if (num <= 0)
621       return;
622
623    if (num < 2 || num < (int)(2 + val[0] * val[1]))
624      {
625         Eprintf
626            ("*** EWMH_GetWindowIcons Icon data/size mismatch (ignoring): %s: N=%d WxH=%dx%d\n",
627             EwinGetTitle(ewin), num, val[0], (num >= 2) ? val[1] : 0);
628         Efree(val);
629         return;
630      }
631
632    ewin->ewmh.wm_icon = val;
633
634    EwinChange(ewin, EWIN_CHANGE_ICON_PMAP);
635 }
636
637 static void
638 EWMH_GetWindowUserTime(EWin * ewin)
639 {
640 #if 0                           /* TBD */
641    int                 num;
642    unsigned int        ts;
643
644    num = ecore_x_netwm_user_time_get(EwinGetClientXwin(ewin), &ts);
645    if (num <= 0)
646       return;
647
648    Eprintf("EWMH_GetWindowUserTime %#x\n", ts);
649 #else
650    ewin = NULL;
651 #endif
652 }
653
654 static void
655 EWMH_GetWindowStartupId(EWin * ewin)
656 {
657 #define TryGroup(e) (((e)->icccm.group != None) && ((e)->icccm.group != EwinGetClientXwin(e)))
658    char               *str;
659
660    if (!Conf.testing.enable_startup_id)
661       return;
662
663    ecore_x_netwm_startup_id_get(EwinGetClientXwin(ewin), &str);
664    if (!str && TryGroup(ewin))
665       ecore_x_netwm_startup_id_get(ewin->icccm.group, &str);
666    if (str && EDebug(1))
667       Eprintf("Startup id: %s: %s\n", EwinGetTitle(ewin), str);
668 }
669
670 static void
671 EWMH_GetWindowMisc(EWin * ewin)
672 {
673    int                 num;
674    Ecore_X_Window      win;
675
676    num = ecore_x_window_prop_window_get(EwinGetClientXwin(ewin),
677                                         ECORE_X_ATOM_NET_SUPPORTING_WM_CHECK,
678                                         &win, 1);
679    if (num <= 0)
680       return;
681
682    ewin->props.vroot = 1;
683    EoSetDesk(ewin, DesksGetCurrent());
684 }
685
686 static void
687 EWMH_GetWindowOpacity(EWin * ewin)
688 {
689    int                 num;
690    unsigned int        opacity;
691
692    num = ecore_x_netwm_opacity_get(EwinGetClientXwin(ewin), &opacity);
693    if (num <= 0)
694       return;
695
696    if (ewin->ewmh.opacity == opacity)
697       return;
698
699    ewin->ewmh.opacity = opacity;
700
701    EwinChange(ewin, EWIN_CHANGE_OPACITY);
702 }
703
704 static void
705 EWMH_GetWindowStrut(EWin * ewin)
706 {
707    int                 num;
708    unsigned int        val[12];
709
710    num = ecore_x_window_prop_card32_get(EwinGetClientXwin(ewin),
711                                         ECORE_X_ATOM_NET_WM_STRUT_PARTIAL, val,
712                                         12);
713
714    if (num < 4)
715       num = ecore_x_window_prop_card32_get(EwinGetClientXwin(ewin),
716                                            ECORE_X_ATOM_NET_WM_STRUT, val, 4);
717    if (num < 4)
718       return;
719
720    ewin->strut.left = val[0];
721    ewin->strut.right = val[1];
722    ewin->strut.top = val[2];
723    ewin->strut.bottom = val[3];
724 #if 0                           /* FIXME - Handle in placement code */
725    if (num < 12)
726       return;
727    ewin->strut.left_start_y = val[4];
728    ewin->strut.left_end_y = val[5];
729    ewin->strut.right_start_y = val[6];
730    ewin->strut.right_end_y = val[7];
731    ewin->strut.top_start_x = val[8];
732    ewin->strut.top_end_x = val[9];
733    ewin->strut.bottom_start_x = val[10];
734    ewin->strut.bottom_end_x = val[11];
735 #endif
736 }
737
738 void
739 EWMH_SetWindowActions(const EWin * ewin)
740 {
741    Ecore_X_Atom        aa[12];
742    int                 num;
743
744    num = 0;
745    if (!ewin->state.inhibit_move)
746       aa[num++] = ECORE_X_ATOM_NET_WM_ACTION_MOVE;
747    if (!ewin->state.inhibit_resize)
748       aa[num++] = ECORE_X_ATOM_NET_WM_ACTION_RESIZE;
749    if (!ewin->state.inhibit_iconify)
750       aa[num++] = ECORE_X_ATOM_NET_WM_ACTION_MINIMIZE;
751    if (!ewin->state.inhibit_shade)
752       aa[num++] = ECORE_X_ATOM_NET_WM_ACTION_SHADE;
753    if (!ewin->state.inhibit_stick)
754       aa[num++] = ECORE_X_ATOM_NET_WM_ACTION_STICK;
755    if (!ewin->state.inhibit_max_hor)
756       aa[num++] = ECORE_X_ATOM_NET_WM_ACTION_MAXIMIZE_HORZ;
757    if (!ewin->state.inhibit_max_ver)
758       aa[num++] = ECORE_X_ATOM_NET_WM_ACTION_MAXIMIZE_VERT;
759    if (!ewin->state.inhibit_fullscreeen)
760       aa[num++] = ECORE_X_ATOM_NET_WM_ACTION_FULLSCREEN;
761    if (!ewin->state.inhibit_change_desk)
762       aa[num++] = ECORE_X_ATOM_NET_WM_ACTION_CHANGE_DESKTOP;
763    if (!ewin->state.inhibit_close)
764       aa[num++] = ECORE_X_ATOM_NET_WM_ACTION_CLOSE;
765    if (!ewin->state.inhibit_stacking)
766       aa[num++] = ECORE_X_ATOM_NET_WM_ACTION_ABOVE;
767    if (!ewin->state.inhibit_stacking)
768       aa[num++] = ECORE_X_ATOM_NET_WM_ACTION_BELOW;
769
770    ecore_x_window_prop_atom_set(EwinGetClientXwin(ewin),
771                                 ECORE_X_ATOM_NET_WM_ALLOWED_ACTIONS, aa, num);
772 }
773
774 void
775 EWMH_GetWindowHints(EWin * ewin)
776 {
777    EWMH_GetWindowMisc(ewin);
778    EWMH_GetWindowOpacity(ewin);
779    EWMH_GetWindowName(ewin);
780    EWMH_GetWindowIconName(ewin);
781    EWMH_GetWindowDesktop(ewin);
782    EWMH_GetWindowState(ewin);
783    EWMH_GetWindowType(ewin);
784    EWMH_GetWindowIcons(ewin);
785    EWMH_GetWindowStrut(ewin);
786    EWMH_GetWindowUserTime(ewin);
787    EWMH_GetWindowStartupId(ewin);
788 }
789
790 /*
791  * Delete all (_NET_...) properties set on window
792  */
793 void
794 EWMH_DelWindowHints(const EWin * ewin)
795 {
796    XDeleteProperty(disp, EwinGetClientXwin(ewin), ECORE_X_ATOM_NET_WM_DESKTOP);
797    XDeleteProperty(disp, EwinGetClientXwin(ewin), ECORE_X_ATOM_NET_WM_STATE);
798 }
799
800 /*
801  * Process property change
802  */
803 int
804 EWMH_ProcessPropertyChange(EWin * ewin, Atom atom_change)
805 {
806    if (atom_change == ECORE_X_ATOM_NET_WM_NAME)
807      {
808         EWMH_GetWindowName(ewin);
809         return 1;
810      }
811    if (atom_change == ECORE_X_ATOM_NET_WM_ICON_NAME)
812      {
813         EWMH_GetWindowIconName(ewin);
814         return 1;
815      }
816    if (atom_change == ECORE_X_ATOM_NET_WM_STRUT_PARTIAL ||
817        atom_change == ECORE_X_ATOM_NET_WM_STRUT)
818      {
819         EWMH_GetWindowStrut(ewin);
820         return 1;
821      }
822    if (atom_change == ECORE_X_ATOM_NET_WM_WINDOW_OPACITY)
823      {
824         EWMH_GetWindowOpacity(ewin);
825         return 1;
826      }
827    if (atom_change == ECORE_X_ATOM_NET_WM_USER_TIME)
828      {
829         EWMH_GetWindowUserTime(ewin);
830         return 1;
831      }
832
833    return 0;
834 }
835
836 /*
837  * Process configuration requests from clients
838  */
839 static int
840 do_set(int is_set, int action)
841 {
842    switch (action)
843      {
844      case _NET_WM_STATE_REMOVE:
845         return 0;
846      case _NET_WM_STATE_ADD:
847         return 1;
848      case _NET_WM_STATE_TOGGLE:
849         return !is_set;
850      }
851    return -1;
852 }
853
854 int
855 EWMH_ProcessClientClientMessage(EWin * ewin, XClientMessageEvent * ev)
856 {
857    int                 source;
858    Time                ts;
859
860    if (ev->message_type == ECORE_X_ATOM_NET_ACTIVE_WINDOW)
861      {
862         source = OPSRC(ev->data.l[0]);
863         ts = ev->data.l[1];
864 /*      cwin = ev->data.l[2]; */
865         EwinOpActivate(ewin, source, 1);
866         return 1;
867      }
868    if (ev->message_type == ECORE_X_ATOM_NET_CLOSE_WINDOW)
869      {
870 /*      ts = ev->data.l[0]; */
871         source = OPSRC(ev->data.l[1]);
872         EwinOpClose(ewin, source);
873         return 1;
874      }
875    if (ev->message_type == ECORE_X_ATOM_NET_WM_DESKTOP)
876      {
877         source = OPSRC(ev->data.l[1]);
878         if ((unsigned)ev->data.l[0] == 0xFFFFFFFF)
879           {
880              if (!EoIsSticky(ewin))
881                 EwinOpStick(ewin, source, 1);
882           }
883         else
884           {
885              if (EoIsSticky(ewin))
886                 EwinOpStick(ewin, source, 0);
887              else
888                 EwinMoveToDesktop(ewin, DeskGet(ev->data.l[0]));
889           }
890         return 1;
891      }
892    if (ev->message_type == ECORE_X_ATOM_NET_WM_STATE)
893      {
894         /*
895          * It is assumed(!) that only the MAXIMIZE H/V ones can be set
896          * in one message.
897          */
898         unsigned int        action;
899         Atom                atom, atom2;
900
901         action = ev->data.l[0];
902         atom = ev->data.l[1];
903         atom2 = ev->data.l[2];
904         source = OPSRC(ev->data.l[3]);
905         if (atom == ECORE_X_ATOM_NET_WM_STATE_MODAL)
906           {
907              action = do_set(ewin->state.modal, action);
908              /* TBD */
909              ewin->state.modal = action;
910           }
911         else if (atom == ECORE_X_ATOM_NET_WM_STATE_STICKY)
912           {
913              action = do_set(EoIsSticky(ewin), action);
914              EwinOpStick(ewin, source, action);
915           }
916         else if (atom == ECORE_X_ATOM_NET_WM_STATE_SHADED)
917           {
918              action = do_set(ewin->state.shaded, action);
919              EwinOpShade(ewin, source, action);
920           }
921         else if (atom == ECORE_X_ATOM_NET_WM_STATE_SKIP_TASKBAR)
922           {
923              action = do_set(ewin->props.skip_ext_task, action);
924              ewin->props.skip_ext_task = action;
925              EWMH_SetWindowState(ewin);
926           }
927         else if (atom == ECORE_X_ATOM_NET_WM_STATE_SKIP_PAGER)
928           {
929              action = do_set(ewin->props.skip_ext_pager, action);
930              ewin->props.skip_ext_pager = action;
931              EWMH_SetWindowState(ewin);
932           }
933         else if (atom == ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_VERT ||
934                  atom == ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_HORZ)
935           {
936              int                 maxh, maxv;
937
938              maxh = ewin->state.maximized_horz;
939              maxv = ewin->state.maximized_vert;
940              if (atom2 == ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_VERT ||
941                  atom2 == ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_HORZ)
942                {
943                   /* (ok - ok) */
944                   maxh = do_set(maxh, action);
945                   maxv = do_set(maxv, action);
946                }
947              else if (atom == ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_VERT)
948                {
949                   maxv = do_set(maxv, action);
950                }
951              else
952                {
953                   maxh = do_set(maxh, action);
954                }
955
956              if ((ewin->state.maximized_horz != maxh) ||
957                  (ewin->state.maximized_vert != maxv))
958                {
959                   MaxSizeHV(ewin, "available", maxh, maxv);
960                   EWMH_SetWindowState(ewin);
961                }
962           }
963         else if (atom == ECORE_X_ATOM_NET_WM_STATE_FULLSCREEN)
964           {
965              action = do_set(ewin->state.fullscreen, action);
966              if (ewin->state.fullscreen != action)
967                 EwinOpFullscreen(ewin, source, action);
968           }
969         else if (atom == ECORE_X_ATOM_NET_WM_STATE_ABOVE)
970           {
971              action = do_set(EoGetLayer(ewin) >= 6, action);
972              if (action)
973                {
974                   if (EoGetLayer(ewin) < 6)
975                      EwinOpSetLayer(ewin, source, 6);
976                }
977              else
978                {
979                   if (EoGetLayer(ewin) >= 6)
980                      EwinOpSetLayer(ewin, source, 4);
981                }
982           }
983         else if (atom == ECORE_X_ATOM_NET_WM_STATE_BELOW)
984           {
985              action = do_set(EoGetLayer(ewin) <= 2, action);
986              if (action)
987                {
988                   if (EoGetLayer(ewin) > 2)
989                      EwinOpSetLayer(ewin, source, 2);
990                }
991              else
992                {
993                   if (EoGetLayer(ewin) <= 2)
994                      EwinOpSetLayer(ewin, source, 4);
995                }
996           }
997         else if (atom == ECORE_X_ATOM_NET_WM_STATE_DEMANDS_ATTENTION)
998           {
999              action = do_set(ewin->state.attention, action);
1000              ewin->state.attention = action;
1001              EWMH_SetWindowState(ewin);
1002           }
1003         return 1;
1004      }
1005    if (ev->message_type == ECORE_X_ATOM_NET_MOVERESIZE_WINDOW)
1006      {
1007         int                 flags, grav, x, y, w, h;
1008
1009         flags = ev->data.l[0];
1010         grav = flags & 0xf;     /* 0 means use client gravity */
1011         x = (flags & 0x0100) ? ev->data.l[1] : EoGetX(ewin);
1012         y = (flags & 0x0200) ? ev->data.l[2] : EoGetY(ewin);
1013         w = (flags & 0x0400) ? ev->data.l[3] : ewin->client.w;
1014         h = (flags & 0x0800) ? ev->data.l[4] : ewin->client.h;
1015 /*      source = OPSRC((flags & 0xF000) >> 12); */
1016         EwinMoveResizeWithGravity(ewin, x, y, w, h, grav);
1017         return 1;
1018      }
1019    if (ev->message_type == ECORE_X_ATOM_NET_WM_MOVERESIZE)
1020      {
1021 /*      source = OPSRC(ev->data.l[4]); */
1022         switch (ev->data.l[2])
1023           {
1024           case _NET_WM_MOVERESIZE_SIZE_TOPLEFT:
1025           case _NET_WM_MOVERESIZE_SIZE_TOPRIGHT:
1026           case _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT:
1027           case _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT:
1028              ActionResizeStart(ewin, 0, MODE_RESIZE);
1029              break;
1030           case _NET_WM_MOVERESIZE_SIZE_RIGHT:
1031           case _NET_WM_MOVERESIZE_SIZE_LEFT:
1032              ActionResizeStart(ewin, 0, MODE_RESIZE_H);
1033              break;
1034           case _NET_WM_MOVERESIZE_SIZE_TOP:
1035           case _NET_WM_MOVERESIZE_SIZE_BOTTOM:
1036              ActionResizeStart(ewin, 0, MODE_RESIZE_V);
1037              break;
1038
1039           case _NET_WM_MOVERESIZE_MOVE:
1040              ActionMoveStart(ewin, 0, 0, 0);
1041              break;
1042
1043           case _NET_WM_MOVERESIZE_SIZE_KEYBOARD:
1044              ActionResizeStart(ewin, 1, MODE_RESIZE);
1045              break;
1046           case _NET_WM_MOVERESIZE_MOVE_KEYBOARD:
1047              ActionMoveStart(ewin, 1, 0, 0);
1048              break;
1049           case _NET_WM_MOVERESIZE_CANCEL:
1050              ActionsEnd(ewin);
1051              break;
1052           }
1053         return 1;
1054      }
1055    if (ev->message_type == ECORE_X_ATOM_NET_RESTACK_WINDOW)
1056      {
1057 /*      source = OPSRC(ev->data.l[0]); */
1058         /* FIXME - Implement */
1059         return 1;
1060      }
1061
1062    return 0;
1063 }
1064
1065 int
1066 EWMH_ProcessRootClientMessage(XClientMessageEvent * ev)
1067 {
1068    if (ev->message_type == ECORE_X_ATOM_NET_CURRENT_DESKTOP)
1069      {
1070         DeskGotoNum(ev->data.l[0]);
1071         return 1;
1072      }
1073    if (ev->message_type == ECORE_X_ATOM_NET_DESKTOP_VIEWPORT)
1074      {
1075         DeskCurrentGotoArea(ev->data.l[0] / WinGetW(VROOT),
1076                             ev->data.l[1] / WinGetH(VROOT));
1077         return 1;
1078      }
1079    if (ev->message_type == ECORE_X_ATOM_NET_SHOWING_DESKTOP)
1080      {
1081         EwinsShowDesktop(ev->data.l[0]);
1082         return 1;
1083      }
1084 #if 0                           /* These messages are sent to dedicated window */
1085    if (ev->message_type == ECORE_X_ATOM_NET_STARTUP_INFO_BEGIN)
1086      {
1087         Eprintf("ECORE_X_ATOM_NET_STARTUP_INFO_BEGIN: %lx: %s\n",
1088                 ev->window, (char *)ev->data.l);
1089         return 1;
1090      }
1091    if (ev->message_type == ECORE_X_ATOM_NET_STARTUP_INFO)
1092      {
1093         Eprintf("ECORE_X_ATOM_NET_STARTUP_INFO      : %lx: %s\n",
1094                 ev->window, (char *)ev->data.l);
1095         return 1;
1096      }
1097 #endif
1098
1099 #if 0                           /* Obsolete? */
1100    EWin               *ewin;
1101
1102    ewin = EwinFindByClient(ev->window);
1103    if (ewin == NULL)
1104      {
1105         /* Some misbehaving clients go here */
1106         if (ev->message_type == ECORE_X_ATOM_NET_WM_DESKTOP)
1107           {
1108              ecore_x_netwm_desktop_set(ev->window, ev->data.l[0]);
1109              return 1;
1110           }
1111         else if (ev->message_type == ECORE_X_ATOM_NET_WM_STATE)
1112           {
1113              ecore_x_window_prop_atom_list_change(ev->window,
1114                                                   ECORE_X_ATOM_NET_WM_STATE,
1115                                                   ev->data.l[1], ev->data.l[0]);
1116              if (ev->data.l[2] ==
1117                  (long)ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_HORZ ||
1118                  ev->data.l[2] ==
1119                  (long)ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_VERT)
1120                 ecore_x_window_prop_atom_list_change(ev->window,
1121                                                      ECORE_X_ATOM_NET_WM_STATE,
1122                                                      ev->data.l[2],
1123                                                      ev->data.l[0]);
1124              return 1;
1125           }
1126      }
1127 #endif
1128    return 0;
1129 }