1 /*
2  * Copyright (C) 2003-2021 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  * Feeble attempt to collect hint stuff in one place
25  */
26 #include "config.h"
27 
28 #include <X11/Xlib.h>
29 #include <X11/Xatom.h>
30 
31 #include "E.h"
32 #include "borders.h"		/* FIXME - Should not be here */
33 #include "desktops.h"		/* FIXME - Should not be here */
34 #include "events.h"
35 #include "ewins.h"
36 #include "hints.h"
37 #include "xprop.h"
38 #include "xwin.h"
39 
40 static void         EHintsSetDeskInfo(void);
41 static void         EHintsSetAreaInfo(void);
42 
43 static unsigned int desk_info = 0;
44 
45 void
HintsInit(void)46 HintsInit(void)
47 {
48    EX_Window           win;
49 
50    win = XCreateSimpleWindow(disp, WinGetXwin(VROOT), -200, -200, 5, 5,
51 			     0, 0, 0);
52 
53    ex_atoms_init();
54    ICCCM_Init();
55    MWM_SetInfo();
56 #if ENABLE_GNOME
57    GNOME_SetHints(win);
58 #endif
59    EWMH_Init(win);
60 
61    ex_window_prop_string_set(WinGetXwin(VROOT), ea_m.ENLIGHTENMENT_VERSION,
62 			     e_wm_version);
63 
64    if (Mode.wm.window)
65      {
66 	HintsSetWindowName(VROOT, "Enlightenment");
67 	HintsSetWindowClass(VROOT, "Virtual-Root", "Enlightenment");
68      }
69 
70    Mode.root.ext_pmap = HintsGetRootPixmap(VROOT);
71    Mode.root.ext_pmap_valid = EXDrawableOk(Mode.root.ext_pmap);
72 }
73 
74 /*
75  * Functions that set X11-properties from E-internals
76  */
77 
78 void
HintsSetRootHints(Win win __UNUSED__)79 HintsSetRootHints(Win win __UNUSED__)
80 {
81    /* Nothing done here for now */
82 }
83 
84 void
HintsSetClientList(void)85 HintsSetClientList(void)
86 {
87 #if ENABLE_GNOME
88    GNOME_SetClientList();
89 #endif
90    EWMH_SetClientList();
91    EWMH_SetClientStacking();
92 }
93 
94 void
HintsSetClientStacking(void)95 HintsSetClientStacking(void)
96 {
97    EWMH_SetClientStacking();
98 }
99 
100 void
HintsSetDesktopConfig(void)101 HintsSetDesktopConfig(void)
102 {
103 #if ENABLE_GNOME
104    GNOME_SetDeskCount();
105    GNOME_SetDeskNames();
106 #endif
107    EWMH_SetDesktopCount();
108    EWMH_SetDesktopRoots();
109    EWMH_SetDesktopNames();
110    EWMH_SetWorkArea();
111 }
112 
113 void
HintsSetViewportConfig(void)114 HintsSetViewportConfig(void)
115 {
116 #if ENABLE_GNOME
117    GNOME_SetAreaCount();
118 #endif
119    EWMH_SetDesktopSize();
120 }
121 
122 void
HintsSetCurrentDesktop(void)123 HintsSetCurrentDesktop(void)
124 {
125 #if ENABLE_GNOME
126    GNOME_SetCurrentDesk();
127 #endif
128    EWMH_SetCurrentDesktop();
129    EHintsSetDeskInfo();
130 }
131 
132 void
HintsSetDesktopViewport(void)133 HintsSetDesktopViewport(void)
134 {
135 #if ENABLE_GNOME
136    GNOME_SetCurrentArea();
137 #endif
138    EWMH_SetDesktopViewport();
139    EHintsSetAreaInfo();
140 }
141 
142 void
HintsSetActiveWindow(EX_Window win)143 HintsSetActiveWindow(EX_Window win)
144 {
145    EWMH_SetActiveWindow(win);
146 }
147 
148 void
HintsSetWindowName(Win win,const char * name)149 HintsSetWindowName(Win win, const char *name)
150 {
151    if (!name)
152       return;
153 
154    ex_icccm_title_set(WinGetXwin(win), name);
155 
156    EWMH_SetWindowName(WinGetXwin(win), name);
157 }
158 
159 void
HintsSetWindowClass(Win win,const char * name,const char * clss)160 HintsSetWindowClass(Win win, const char *name, const char *clss)
161 {
162    if (!name)
163       name = "NoName";
164    if (!clss)
165       clss = "NoClass";
166 
167    ex_icccm_name_class_set(WinGetXwin(win), name, clss);
168 }
169 
170 void
HintsSetWindowDesktop(const EWin * ewin)171 HintsSetWindowDesktop(const EWin * ewin)
172 {
173 #if ENABLE_GNOME
174    GNOME_SetEwinDesk(ewin);
175 #endif
176    EWMH_SetWindowDesktop(ewin);
177 }
178 
179 void
HintsSetWindowArea(const EWin * ewin __UNUSED__)180 HintsSetWindowArea(const EWin * ewin __UNUSED__)
181 {
182 #if ENABLE_GNOME
183    GNOME_SetEwinArea(ewin);
184 #endif
185 }
186 
187 void
HintsSetWindowState(const EWin * ewin)188 HintsSetWindowState(const EWin * ewin)
189 {
190 #if ENABLE_GNOME
191    GNOME_SetHint(ewin);
192 #endif
193    EWMH_SetWindowState(ewin);
194    EWMH_SetWindowActions(ewin);
195 }
196 
197 void
HintsSetWindowOpacity(EWin * ewin)198 HintsSetWindowOpacity(EWin * ewin)
199 {
200    EWMH_SetWindowOpacity(ewin);
201 }
202 
203 void
HintsSetWindowBorder(const EWin * ewin)204 HintsSetWindowBorder(const EWin * ewin)
205 {
206    EWMH_SetWindowBorder(ewin);
207 }
208 
209 /*
210  * Functions that set E-internals from X11-properties
211  */
212 
213 void
HintsGetWindowHints(EWin * ewin)214 HintsGetWindowHints(EWin * ewin)
215 {
216 #if ENABLE_GNOME
217    GNOME_GetHints(ewin, 0);
218 #endif
219    EWMH_GetWindowHints(ewin);
220 }
221 
222 /*
223  * Functions that delete X11-properties
224  */
225 
226 void
HintsDelWindowHints(const EWin * ewin)227 HintsDelWindowHints(const EWin * ewin)
228 {
229 #if ENABLE_GNOME
230    GNOME_DelHints(ewin);
231 #endif
232    EWMH_DelWindowHints(ewin);
233 }
234 
235 /*
236  * Functions processing received X11 messages
237  */
238 
239 void
HintsProcessPropertyChange(EWin * ewin,XEvent * ev)240 HintsProcessPropertyChange(EWin * ewin, XEvent * ev)
241 {
242    if (ICCCM_ProcessPropertyChange(ewin, ev->xproperty.atom))
243       return;
244    if (EWMH_ProcessPropertyChange(ewin, ev->xproperty.atom))
245       return;
246 #if 0				/* No! - ENABLE_GNOME */
247    if (GNOME_GetHints(ewin, ev->xproperty.atom))
248       return;
249 #endif
250 #if 0
251    if (EDebug(1))
252      {
253 	Eprintf("%s:\n", __func__);
254 	EventShow(ev);
255      }
256 #endif
257 }
258 
259 void
HintsProcessClientClientMessage(EWin * ewin,XClientMessageEvent * event)260 HintsProcessClientClientMessage(EWin * ewin, XClientMessageEvent * event)
261 {
262    if (ICCCM_ProcessClientClientMessage(ewin, event))
263       return;
264    if (EWMH_ProcessClientClientMessage(ewin, event))
265       return;
266 #if ENABLE_GNOME
267    if (GNOME_ProcessClientClientMessage(ewin, event))
268       return;
269 #endif
270    if (EDebug(1))
271      {
272 	Eprintf("%s:\n", __func__);
273 	EventShow((XEvent *) event);
274      }
275 }
276 
277 void
HintsProcessRootClientMessage(XClientMessageEvent * event)278 HintsProcessRootClientMessage(XClientMessageEvent * event)
279 {
280    if (ICCCM_ProcessRootClientMessage(event))
281       return;
282    if (EWMH_ProcessRootClientMessage(event))
283       return;
284 #if ENABLE_GNOME
285    if (GNOME_ProcessRootClientMessage(event))
286       return;
287 #endif
288    if (EDebug(1))
289      {
290 	Eprintf("%s:\n", __func__);
291 	EventShow((XEvent *) event);
292      }
293 }
294 
295 EX_Pixmap
HintsGetRootPixmap(Win win)296 HintsGetRootPixmap(Win win)
297 {
298    EX_Pixmap           pm;
299 
300    pm = NoXID;
301    ex_window_prop_xid_get(WinGetXwin(win), ea_m._XROOTPMAP_ID, XA_PIXMAP, &pm,
302 			  1);
303 
304    return pm;
305 }
306 
307 void
HintsSetRootInfo(Win win,EX_Pixmap pmap,unsigned int color)308 HintsSetRootInfo(Win win, EX_Pixmap pmap, unsigned int color)
309 {
310    EX_Pixmap           pm;
311 
312    pm = pmap;
313    ex_window_prop_xid_set(WinGetXwin(win), ea_m._XROOTPMAP_ID, XA_PIXMAP, &pm,
314 			  1);
315 
316    ex_window_prop_card32_set(WinGetXwin(win), ea_m._XROOTCOLOR_PIXEL, &color,
317 			     1);
318 }
319 
320 typedef union {
321    struct {
322       unsigned            version:8;
323       unsigned            rsvd:22;
324       unsigned            docked:1;
325       unsigned            iconified:1;
326    } b;
327    unsigned            all:32;
328 } EWinInfoFlags;
329 
330 #define ENL_DATA_ITEMS      12
331 #define ENL_DATA_VERSION     0
332 
333 void
EHintsSetInfo(const EWin * ewin)334 EHintsSetInfo(const EWin * ewin)
335 {
336    int                 c[ENL_DATA_ITEMS];
337    unsigned int        flags[2];
338    EWinInfoFlags       f;
339 
340    if (EwinIsInternal(ewin))
341       return;
342 
343    f.all = 0;
344    f.b.version = ENL_DATA_VERSION;
345    f.b.docked = ewin->state.docked;
346    f.b.iconified = ewin->state.iconified;
347    c[0] = f.all;
348 
349    EwinFlagsEncode(ewin, flags);
350    c[1] = flags[0];
351    c[2] = flags[1];
352 
353    c[3] = ewin->save_max.x;
354    c[4] = ewin->save_max.y;
355    c[5] = ewin->save_max.w;
356    c[6] = ewin->save_max.h;
357    c[7] = ewin->save_fs.x;
358    c[8] = ewin->save_fs.y;
359    c[9] = ewin->save_fs.w;
360    c[10] = ewin->save_fs.h;
361    c[11] = ewin->save_fs.layer;
362 
363    ex_window_prop_card32_set(EwinGetClientXwin(ewin), ea_m.ENL_WIN_DATA,
364 			     (unsigned int *)c, ENL_DATA_ITEMS);
365 
366    ex_window_prop_string_set(EwinGetClientXwin(ewin), ea_m.ENL_WIN_BORDER,
367 			     BorderGetName(ewin->normal_border));
368 
369    if (EDebug(EDBUG_TYPE_SNAPS))
370       Eprintf("Snap set einf  %#x: %4d+%4d %4dx%4d: %s\n",
371 	      EwinGetClientXwin(ewin), ewin->client.x, ewin->client.y,
372 	      ewin->client.w, ewin->client.h, EwinGetTitle(ewin));
373 }
374 
375 void
EHintsGetInfo(EWin * ewin)376 EHintsGetInfo(EWin * ewin)
377 {
378    char               *str;
379    int                 num;
380    int                 c[ENL_DATA_ITEMS + 1];
381    unsigned int        flags[2];
382    EWinInfoFlags       f;
383 
384    if (EwinIsInternal(ewin))
385       return;
386 
387    /* Fix window position on hidden desks if restarting after a crash */
388    if (desk_info & (1U << EoGetDeskNum(ewin)))
389       ewin->client.x -= WinGetW(VROOT);
390 
391    num =
392       ex_window_prop_card32_get(EwinGetClientXwin(ewin), ea_m.ENL_WIN_DATA,
393 				(unsigned int *)c, ENL_DATA_ITEMS + 1);
394    if (num < 0)
395       return;
396 
397    ewin->state.identified = 1;
398    ewin->state.placed = 1;
399 
400    if (num < 2)
401       return;
402 
403    f.all = c[0];
404    if (f.b.version != ENL_DATA_VERSION)
405       return;
406    ewin->icccm.start_iconified = f.b.iconified;
407    ewin->state.docked = f.b.docked;
408 
409    flags[0] = c[1];
410    flags[1] = c[2];
411    EwinFlagsDecode(ewin, flags);
412 
413    if (num == ENL_DATA_ITEMS)
414      {
415 	ewin->save_max.x = c[3];
416 	ewin->save_max.y = c[4];
417 	ewin->save_max.w = c[5];
418 	ewin->save_max.h = c[6];
419 	ewin->save_fs.x = c[7];
420 	ewin->save_fs.y = c[8];
421 	ewin->save_fs.w = c[9];
422 	ewin->save_fs.h = c[10];
423 	ewin->save_fs.layer = c[11];
424      }
425 
426    str =
427       ex_window_prop_string_get(EwinGetClientXwin(ewin), ea_m.ENL_WIN_BORDER);
428    if (str)
429       EwinBorderSetInitially(ewin, str);
430    Efree(str);
431 
432    if (EDebug(EDBUG_TYPE_SNAPS))
433       Eprintf("Snap get einf  %#x: %4d+%4d %4dx%4d: %s\n",
434 	      EwinGetClientXwin(ewin), ewin->client.x, ewin->client.y,
435 	      ewin->client.w, ewin->client.h, EwinGetTitle(ewin));
436 }
437 
438 static void
EHintsSetDeskInfo(void)439 EHintsSetDeskInfo(void)
440 {
441    int                 i, ax, ay, n_desks;
442    unsigned int        c[2], desk_pos_info;
443 
444    if (!DesksGetCurrent())	/* Quit if current desk isn't assigned yet */
445       return;
446 
447    n_desks = DesksGetNumber();
448    if (n_desks <= 0)
449       return;
450 
451    desk_pos_info = 0;
452    for (i = 0; i < n_desks; i++)
453      {
454 	Desk               *dsk = DeskGet(i);
455 
456 	DeskGetArea(dsk, &ax, &ay);
457 	if (EoGetY(dsk) == 0 && EoGetX(dsk) == WinGetW(VROOT))
458 	   desk_pos_info |= 1U << i;	/* Desk is "hidden" */
459      }
460 
461    c[0] = DesksGetCurrentNum();
462    c[1] = Mode.wm.exiting ? 0 : desk_pos_info;
463    ex_window_prop_card32_set(WinGetXwin(VROOT),
464 			     ea_m.ENL_INTERNAL_DESK_DATA, c, 2);
465 
466    if (Mode.wm.exiting && Mode.root.ext_pmap_valid)
467      {
468 	HintsSetRootInfo(VROOT, Mode.root.ext_pmap, 0);
469 	ESetWindowBackgroundPixmap(VROOT, Mode.root.ext_pmap, 1);
470      }
471 }
472 
473 static void
EHintsSetAreaInfo(void)474 EHintsSetAreaInfo(void)
475 {
476    int                 i, ax, ay, n_desks;
477    unsigned int       *c;
478 
479    n_desks = DesksGetNumber();
480    if (n_desks <= 0)
481       return;
482 
483    c = EMALLOC(unsigned int, 2 * n_desks);
484    if (!c)
485       return;
486 
487    for (i = 0; i < n_desks; i++)
488      {
489 	Desk               *dsk = DeskGet(i);
490 
491 	DeskGetArea(dsk, &ax, &ay);
492 	c[(i * 2)] = ax;
493 	c[(i * 2) + 1] = ay;
494      }
495 
496    ex_window_prop_card32_set(WinGetXwin(VROOT),
497 			     ea_m.ENL_INTERNAL_AREA_DATA, c, 2 * n_desks);
498 
499    Efree(c);
500 }
501 
502 void
EHintsGetDeskInfo(void)503 EHintsGetDeskInfo(void)
504 {
505    unsigned int       *c;
506    int                 num, i, n_desks;
507 
508    n_desks = DesksGetNumber();
509    c = EMALLOC(unsigned int, 2 * n_desks);
510 
511    if (!c)
512       return;
513 
514    num = ex_window_prop_card32_get(WinGetXwin(VROOT),
515 				   ea_m.ENL_INTERNAL_AREA_DATA, c, 2 * n_desks);
516    if (num > 0)
517      {
518 	for (i = 0; i < (num / 2); i++)
519 	   DeskSetArea(DeskGet(i), c[(i * 2)], c[(i * 2) + 1]);
520      }
521 
522    num = ex_window_prop_card32_get(WinGetXwin(VROOT),
523 				   ea_m.ENL_INTERNAL_DESK_DATA, c, 2);
524    if (num > 0)
525      {
526 	DesksSetCurrent(DeskGet(c[0]));
527 	if (num > 1)
528 	   desk_info = c[1];
529      }
530    else
531      {
532 	/* Used to test if we should run cmd_init */
533 	Mode.wm.session_start = 1;
534      }
535 
536    Efree(c);
537 }
538 
539 void
EHintsSetInfoOnAll(void)540 EHintsSetInfoOnAll(void)
541 {
542    int                 i, num;
543    EWin               *const *lst;
544 
545    if (EDebug(EDBUG_TYPE_SESSION))
546       Eprintf("%s\n", __func__);
547 
548    lst = EwinListGetAll(&num);
549    for (i = 0; i < num; i++)
550       if (!EwinIsInternal(lst[i]))
551 	 EHintsSetInfo(lst[i]);
552 
553    EHintsSetDeskInfo();
554 }
555 
556 /*
557  * Selections.
558  */
559 
560 struct _selection {
561    EX_Atom             atom;
562    EX_Time             time;
563    Win                 win;
564    EventCallbackFunc  *func;
565    void               *data;
566 };
567 
568 ESelection         *
SelectionAcquire(const char * name,EventCallbackFunc * func,void * data)569 SelectionAcquire(const char *name, EventCallbackFunc * func, void *data)
570 {
571    ESelection         *sel;
572    char                buf[128];
573 
574    sel = ECALLOC(ESelection, 1);
575    if (!sel)
576       return sel;
577 
578    Esnprintf(buf, sizeof(buf), "%s%d", name, Dpy.screen);
579 
580    sel->atom = ex_atom_get(buf);
581    sel->time = EGetTimestamp();
582    sel->win = ECreateEventWindow(VROOT, -100, -100, 1, 1);
583 
584    sel->func = func;
585    sel->data = data;
586 
587    XSetSelectionOwner(disp, sel->atom, WinGetXwin(sel->win), sel->time);
588    if (XGetSelectionOwner(disp, sel->atom) != WinGetXwin(sel->win))
589      {
590 	DialogOK(_("Selection Error!"), _("Could not acquire selection: %s"),
591 		 buf);
592 	EDestroyWindow(sel->win);
593 	Efree(sel);
594 	return NULL;
595      }
596 
597    if (sel->func)
598      {
599 	ESelectInput(sel->win, SubstructureNotifyMask);
600 	EventCallbackRegister(sel->win, sel->func, sel->data);
601      }
602 
603    ex_client_message32_send(WinGetXwin(VROOT), ea_m.MANAGER,
604 			    StructureNotifyMask, CurrentTime, sel->atom,
605 			    WinGetXwin(sel->win), 0, 0);
606 
607    if (EDebug(EDBUG_TYPE_SELECTION))
608       Eprintf("Window %#x is now %s owner, time=%u\n",
609 	      WinGetXwin(sel->win), buf, sel->time);
610 
611    return sel;
612 }
613 
614 void
SelectionRelease(ESelection * sel)615 SelectionRelease(ESelection * sel)
616 {
617    if (!sel)
618       return;
619 
620    if (EDebug(EDBUG_TYPE_SELECTION))
621       Eprintf("Window %#x is no longer %s owner\n",
622 	      WinGetXwin(sel->win), XGetAtomName(disp, sel->atom));
623 
624    XSetSelectionOwner(disp, sel->atom, NoXID, sel->time);
625    if (sel->func)
626      {
627 	EventCallbackUnregister(sel->win, sel->func, sel->data);
628      }
629    EDestroyWindow(sel->win);
630    Efree(sel);
631 }
632