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