1 /*
2 * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors
3 * Copyright (C) 2004-2021 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 "config.h"
25
26 #include <X11/Xlib.h>
27 #include <X11/Xutil.h>
28 #include <X11/extensions/shape.h>
29 #define USE_EIWC_WINDOW 1
30 #if USE_XRENDER
31 #define USE_EIWC_RENDER 1
32 #include <X11/extensions/Xrender.h>
33 #endif
34
35 #include "E.h"
36 #include "eimage.h"
37 #include "events.h"
38 #include "xprop.h"
39 #include "xwin.h"
40
41 typedef struct {
42 EX_Cursor curs;
43 XSetWindowAttributes attr;
44 EX_Window cwin;
45 } EiwData;
46
47 typedef void (EiwLoopFunc) (EX_Window win, EImage * im, EiwData * d);
48
49 #if USE_EIWC_RENDER
50 static void _eiw_render_loop(EX_Window win, EImage * im, EiwData * d);
51
52 static EiwLoopFunc *
_eiw_render_init(EX_Window win __UNUSED__,EiwData * d)53 _eiw_render_init(EX_Window win __UNUSED__, EiwData * d)
54 {
55 Visual *vis;
56
57 /* Quit if no ARGB visual.
58 * If we have, assume(?) a colored XRenderCreateCursor is available. */
59 vis = EVisualFindARGB();
60 if (!vis)
61 return NULL;
62
63 d->curs = NoXID;
64
65 return _eiw_render_loop;
66 }
67
68 static void
_eiw_render_loop(EX_Window win,EImage * im,EiwData * d)69 _eiw_render_loop(EX_Window win, EImage * im, EiwData * d)
70 {
71 int w, h;
72
73 EImageGetSize(im, &w, &h);
74
75 if (d->curs != NoXID)
76 XFreeCursor(disp, d->curs);
77 d->curs = EImageDefineCursor(im, w / 2, h / 2);
78
79 XDefineCursor(disp, win, d->curs);
80 }
81
82 #endif /* USE_EIWC_RENDER */
83
84 #if USE_EIWC_WINDOW
85
86 static void _eiw_window_loop(EX_Window win, EImage * im, EiwData * d);
87
88 static EiwLoopFunc *
_eiw_window_init(EX_Window win,EiwData * d)89 _eiw_window_init(EX_Window win, EiwData * d)
90 {
91 EX_Pixmap pmap, mask;
92 XColor cl;
93
94 d->cwin = XCreateWindow(disp, win, 0, 0, 32, 32, 0,
95 CopyFromParent, InputOutput, CopyFromParent,
96 CWOverrideRedirect | CWBackingStore | CWBackPixel,
97 &d->attr);
98
99 pmap = XCreatePixmap(disp, d->cwin, 16, 16, 1);
100 EXFillAreaSolid(pmap, 0, 0, 16, 16, 0);
101
102 mask = XCreatePixmap(disp, d->cwin, 16, 16, 1);
103 EXFillAreaSolid(mask, 0, 0, 16, 16, 0);
104
105 d->curs = XCreatePixmapCursor(disp, pmap, mask, &cl, &cl, 0, 0);
106 XDefineCursor(disp, win, d->curs);
107 XDefineCursor(disp, d->cwin, d->curs);
108
109 return _eiw_window_loop;
110 }
111
112 static void
_eiw_window_loop(EX_Window win,EImage * im,EiwData * d)113 _eiw_window_loop(EX_Window win, EImage * im, EiwData * d)
114 {
115 EX_Pixmap pmap, mask;
116 Window ww;
117 int dd, x, y, w, h;
118 unsigned int mm;
119
120 EImageRenderPixmaps(im, NULL, 0, &pmap, &mask, 0, 0);
121 EImageGetSize(im, &w, &h);
122 XShapeCombineMask(disp, d->cwin, ShapeBounding, 0, 0, mask, ShapeSet);
123 XSetWindowBackgroundPixmap(disp, d->cwin, pmap);
124 EImagePixmapsFree(pmap, mask);
125 XClearWindow(disp, d->cwin);
126 XQueryPointer(disp, win, &ww, &ww, &dd, &dd, &x, &y, &mm);
127 XMoveResizeWindow(disp, d->cwin, x - w / 2, y - h / 2, w, h);
128 XMapWindow(disp, d->cwin);
129 }
130
131 #endif /* USE_EIWC_WINDOW */
132
133 static EX_Window
ExtInitWinMain(void)134 ExtInitWinMain(void)
135 {
136 int i, loop, err;
137 EX_Window win;
138 EX_Pixmap pmap;
139 EX_Atom a;
140 EiwData eiwd;
141 EiwLoopFunc *eiwc_loop_func;
142 unsigned int wclass, vmask;
143
144 if (EDebug(EDBUG_TYPE_SESSION))
145 Eprintf("%s: enter\n", __func__);
146
147 err = EDisplayOpen(NULL, -1);
148 if (err)
149 return NoXID;
150
151 EDisplaySetErrorHandlers(EventShowError, NULL);
152
153 EGrabServer();
154
155 EImageInit();
156
157 eiwd.attr.override_redirect = True;
158 eiwd.attr.background_pixmap = NoXID;
159 eiwd.attr.backing_store = NotUseful;
160 eiwd.attr.save_under = True;
161 eiwd.attr.background_pixel = 0; /* Not used */
162 wclass = InputOnly;
163 vmask = CWOverrideRedirect;
164 if (!Mode.wm.window)
165 {
166 pmap = ECreatePixmap(RROOT, WinGetW(RROOT), WinGetH(RROOT), 0);
167 EXCopyArea(WinGetXwin(RROOT), pmap, 0, 0,
168 WinGetW(RROOT), WinGetH(RROOT), 0, 0);
169 eiwd.attr.background_pixmap = pmap;
170 wclass = InputOutput;
171 vmask |= CWBackPixmap | CWBackingStore | CWSaveUnder;
172 }
173 win = XCreateWindow(disp, WinGetXwin(RROOT),
174 0, 0, WinGetW(RROOT), WinGetH(RROOT),
175 0, CopyFromParent, wclass, CopyFromParent,
176 vmask, &eiwd.attr);
177 if (!Mode.wm.window)
178 {
179 EFreePixmap(eiwd.attr.background_pixmap);
180 }
181
182 XMapRaised(disp, win);
183
184 a = ex_atom_get("ENLIGHTENMENT_RESTART_SCREEN");
185 ex_window_prop_window_set(WinGetXwin(RROOT), a, &win, 1);
186
187 XSelectInput(disp, win, StructureNotifyMask);
188
189 EUngrabServer();
190 ESync(0);
191
192 #if USE_EIWC_WINDOW && USE_EIWC_RENDER
193 eiwc_loop_func = _eiw_render_init(win, &eiwd);
194 if (!eiwc_loop_func)
195 eiwc_loop_func = _eiw_window_init(win, &eiwd);
196 #elif USE_EIWC_RENDER
197 eiwc_loop_func = _eiw_render_init(win, &eiwd);
198 #elif USE_EIWC_WINDOW
199 eiwc_loop_func = _eiw_window_init(win, &eiwd);
200 #endif
201 if (!eiwc_loop_func)
202 return NoXID;
203
204 {
205 XWindowAttributes xwa;
206 char s[1024];
207 EImage *im;
208
209 for (i = loop = 1;; i++, loop++)
210 {
211 if (i > 12)
212 i = 1;
213
214 /* If we get unmapped we are done */
215 if (!XGetWindowAttributes(disp, win, &xwa) ||
216 (xwa.map_state == IsUnmapped))
217 {
218 if (EDebug(EDBUG_TYPE_SESSION))
219 Eprintf("%s: child done\n", __func__);
220 break;
221 }
222
223 Esnprintf(s, sizeof(s), "pix/wait%i.png", i);
224 if (EDebug(EDBUG_TYPE_SESSION) > 1)
225 Eprintf("%s: child %s\n", __func__, s);
226
227 im = ThemeImageLoad(s);
228 if (im)
229 {
230 eiwc_loop_func(win, im, &eiwd);
231 EImageFree(im);
232 }
233 ESync(0);
234 SleepUs(50 * 1000);
235
236 /* If we still are here after 60 sec something is wrong. */
237 if (loop > 60000 / 50)
238 {
239 if (EDebug(EDBUG_TYPE_SESSION))
240 Eprintf("%s: child timeout\n", __func__);
241 break;
242 }
243 }
244 }
245
246 EDisplayClose();
247
248 exit(0);
249 }
250
251 EX_Window
ExtInitWinCreate(void)252 ExtInitWinCreate(void)
253 {
254 EX_Window win_ex; /* Hmmm.. */
255 EX_Window win;
256 EX_Atom a;
257
258 if (EDebug(EDBUG_TYPE_SESSION))
259 Eprintf("%s\n", __func__);
260
261 a = ex_atom_get("ENLIGHTENMENT_RESTART_SCREEN");
262 ex_window_prop_window_set(WinGetXwin(RROOT), a, NULL, 0);
263 ESync(0);
264
265 if (fork())
266 {
267 /* Parent */
268 EUngrabServer();
269
270 for (;;)
271 {
272 if (EDebug(EDBUG_TYPE_SESSION))
273 Eprintf("%s: parent\n", __func__);
274
275 /* Hack to give the child some space. Not foolproof. */
276 SleepUs(500000);
277
278 if (ex_window_prop_window_get
279 (WinGetXwin(RROOT), a, &win_ex, 1) > 0)
280 break;
281 }
282
283 win = win_ex;
284 if (EDebug(EDBUG_TYPE_SESSION))
285 Eprintf("%s: parent - %#x\n", __func__, win);
286
287 return win;
288 }
289
290 /* Child - Create the init window */
291
292 if (EDebug(EDBUG_TYPE_SESSION))
293 Eprintf("%s: child\n", __func__);
294
295 /* Clean up inherited stuff */
296
297 SignalsRestore();
298
299 EImageExit(0);
300 EDisplayDisconnect();
301
302 ExtInitWinMain();
303
304 /* We will never get here */
305 return NoXID;
306 }
307
308 static EX_Window init_win_ext = NoXID;
309
310 void
ExtInitWinSet(EX_Window win)311 ExtInitWinSet(EX_Window win)
312 {
313 init_win_ext = win;
314 }
315
316 EX_Window
ExtInitWinGet(void)317 ExtInitWinGet(void)
318 {
319 return init_win_ext;
320 }
321
322 void
ExtInitWinKill(void)323 ExtInitWinKill(void)
324 {
325 if (!disp || init_win_ext == NoXID)
326 return;
327
328 if (EDebug(EDBUG_TYPE_SESSION))
329 Eprintf("%s: %#x\n", __func__, init_win_ext);
330 XUnmapWindow(disp, init_win_ext);
331 init_win_ext = NoXID;
332 }
333