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