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 <string.h>
27 #include <unistd.h>
28 #include <X11/Xatom.h>
29 #include <X11/Xlib.h>
30 #include <X11/Xutil.h>
31 #include <X11/Xresource.h>
32 #include <X11/extensions/shape.h>
33 #if USE_XRENDER
34 #include <X11/extensions/Xrender.h>
35 #define RENDER_VERSION VERS(RENDER_MAJOR, RENDER_MINOR)
36 #endif
37 #if USE_XI2
38 #include <X11/extensions/XInput2.h>
39 #endif
40 
41 #include "E.h"
42 #include "edebug.h"
43 #include "util.h"
44 #include "xwin.h"
45 #if USE_GLX
46 #include "eglx.h"
47 #endif
48 
49 #define DEBUG_XWIN   0
50 #define DEBUG_PIXMAP 0
51 
52 __EXPORT__ EDisplay Dpy;
53 __EXPORT__ Display *disp;
54 
55 #if USE_XRENDER
56 static Visual      *argb_visual = NULL;
57 static EX_Colormap  argb_cmap = NoXID;
58 #endif
59 
60 static XContext     xid_context = 0;
61 
62 static Win          win_first = NULL;
63 static Win          win_last = NULL;
64 
65 #define WinBgInvalidate(win) if (win->bg_owned > 0) win->bg_owned = -1
66 
67 void
EXInit(void)68 EXInit(void)
69 {
70    memset(&Dpy, 0, sizeof(Dpy));
71 }
72 
73 static              Win
_EXidCreate(void)74 _EXidCreate(void)
75 {
76    Win                 win;
77 
78    win = ECALLOC(struct _xwin, 1);
79 
80    win->bgcol = 0xffffffff;
81 
82    return win;
83 }
84 
85 static void
_EXidDestroy(Win win)86 _EXidDestroy(Win win)
87 {
88 #if DEBUG_XWIN
89    Eprintf("%s: %p %#x\n", __func__, win, win->xwin);
90 #endif
91    if (win->rects)
92       XFree(win->rects);
93    Efree(win->cbl.lst);
94    Efree(win);
95 }
96 
97 static void
_EXidAdd(Win win)98 _EXidAdd(Win win)
99 {
100 #if DEBUG_XWIN
101    Eprintf("%s: %p %#x\n", __func__, win, win->xwin);
102 #endif
103    if (!xid_context)
104       xid_context = XUniqueContext();
105 
106    XSaveContext(disp, win->xwin, xid_context, (XPointer) win);
107 
108    if (!win_first)
109      {
110 	win_first = win_last = win;
111      }
112    else
113      {
114 	win->prev = win_last;
115 	win_last->next = win;
116 	win_last = win;
117      }
118 }
119 
120 static void
_EXidDel(Win win)121 _EXidDel(Win win)
122 {
123 #if DEBUG_XWIN
124    Eprintf("%s: %p %#x\n", __func__, win, win->xwin);
125 #endif
126    if (win == win_first)
127      {
128 	if (win == win_last)
129 	  {
130 	     win_first = win_last = NULL;
131 	  }
132 	else
133 	  {
134 	     win_first = win->next;
135 	     win->next->prev = NULL;
136 	  }
137      }
138    else if (win == win_last)
139      {
140 	win_last = win->prev;
141 	win->prev->next = NULL;
142      }
143    else
144      {
145 	win->prev->next = win->next;
146 	win->next->prev = win->prev;
147      }
148 
149    XDeleteContext(disp, win->xwin, xid_context);
150    if (win->in_use)
151       win->do_del = 1;
152    else
153       _EXidDestroy(win);
154 }
155 
156 #define EXidLookup ELookupXwin
157 
158 Win
EXidLookup(EX_Window xwin)159 EXidLookup(EX_Window xwin)
160 {
161    Win                 win;
162    XPointer            xp;
163 
164    if (!xid_context)
165       return NULL;
166 
167    xp = NULL;
168    if (XFindContext(disp, xwin, xid_context, &xp) == XCNOENT)
169       xp = NULL;
170    win = (Win) xp;
171 
172    return win;
173 }
174 
175 static              Win
_EXidSet(EX_Window xwin,Win parent,int x,int y,int w,int h,int depth,Visual * visual,EX_Colormap cmap)176 _EXidSet(EX_Window xwin, Win parent, int x, int y, int w, int h, int depth,
177 	 Visual * visual, EX_Colormap cmap)
178 {
179    Win                 win;
180 
181    win = _EXidCreate();
182    win->parent = parent;
183    win->xwin = xwin;
184    win->x = x;
185    win->y = y;
186    win->w = w;
187    win->h = h;
188    win->depth = depth;
189    win->visual = visual;
190    win->cmap = cmap;
191    win->argb = depth == 32;
192 #if DEBUG_XWIN
193    Eprintf("%s: %#x\n", __func__, win->xwin);
194 #endif
195    _EXidAdd(win);
196 
197    return win;
198 }
199 
200 void
EventCallbackRegister(Win win,EventCallbackFunc * func,void * prm)201 EventCallbackRegister(Win win, EventCallbackFunc * func, void *prm)
202 {
203    EventCallbackItem  *eci;
204 
205    if (!win)
206       return;
207 #if 0
208    Eprintf("%s: %p %#x: func=%p prm=%p\n", __func__, win, win->xwin, func, prm);
209 #endif
210 
211    win->cbl.num++;
212    win->cbl.lst = EREALLOC(EventCallbackItem, win->cbl.lst, win->cbl.num);
213    eci = win->cbl.lst + win->cbl.num - 1;
214    eci->func = func;
215    eci->prm = prm;
216 }
217 
218 void
EventCallbackUnregister(Win win,EventCallbackFunc * func,void * prm)219 EventCallbackUnregister(Win win, EventCallbackFunc * func, void *prm)
220 {
221    EventCallbackList  *ecl;
222    EventCallbackItem  *eci;
223    int                 i;
224 
225    if (!win)
226       return;
227 #if 0
228    Eprintf("%s: %p %#x: func=%p prm=%p\n", __func__, win, win->xwin, func, prm);
229 #endif
230 
231    ecl = &win->cbl;
232    eci = ecl->lst;
233    for (i = 0; i < ecl->num; i++, eci++)
234       if (eci->func == func && eci->prm == prm)
235 	{
236 	   ecl->num--;
237 	   if (ecl->num)
238 	     {
239 		for (; i < ecl->num; i++, eci++)
240 		   *eci = *(eci + 1);
241 		win->cbl.lst =
242 		   EREALLOC(EventCallbackItem, win->cbl.lst, ecl->num);
243 	     }
244 	   else
245 	     {
246 		EFREE_NULL(win->cbl.lst);
247 	     }
248 	   return;
249 	}
250 }
251 
252 void
EventCallbacksProcess(Win win,XEvent * ev)253 EventCallbacksProcess(Win win, XEvent * ev)
254 {
255    EventCallbackList  *ecl;
256    EventCallbackItem  *eci;
257    int                 i;
258 
259    if (!win)
260       return;
261 
262    win->in_use = 1;
263    ecl = &win->cbl;
264    eci = ecl->lst;
265    for (i = 0; i < ecl->num; i++, eci++)
266      {
267 	if (EDebug(EDBUG_TYPE_DISPATCH))
268 	   Eprintf("%s: type=%d win=%#lx func=%p prm=%p\n", __func__,
269 		   ev->type, ev->xany.window, eci->func, eci->prm);
270 	eci->func(win, ev, eci->prm);
271 	if (win->do_del)
272 	  {
273 	     _EXidDestroy(win);
274 	     return;
275 	  }
276      }
277    win->in_use = 0;
278 }
279 
280 Win
ECreateWindow(Win parent,int x,int y,int w,int h,int saveunder)281 ECreateWindow(Win parent, int x, int y, int w, int h, int saveunder)
282 {
283    Win                 win;
284    EX_Window           xwin;
285    XSetWindowAttributes attr;
286 
287    attr.backing_store = NotUseful;
288    attr.override_redirect = False;
289    attr.colormap = parent->cmap;
290    attr.border_pixel = 0;
291 /*   attr.background_pixel = 0; */
292    attr.background_pixmap = NoXID;
293    if ((saveunder == 1) && (Conf.save_under))
294       attr.save_under = True;
295    else if (saveunder == 2)
296       attr.save_under = True;
297    else
298       attr.save_under = False;
299 
300    xwin = XCreateWindow(disp, parent->xwin, x, y, w, h, 0,
301 			CopyFromParent, InputOutput, CopyFromParent,
302 			CWOverrideRedirect | CWSaveUnder | CWBackingStore |
303 			CWColormap | CWBackPixmap | CWBorderPixel, &attr);
304    win = _EXidSet(xwin, parent, x, y, w, h, parent->depth, parent->visual,
305 		  parent->cmap);
306 
307    return win;
308 }
309 
310 #if USE_COMPOSITE
311 static              Win
_ECreateWindowVDC(Win parent,int x,int y,int w,int h,Visual * vis,unsigned int depth,EX_Colormap cmap)312 _ECreateWindowVDC(Win parent, int x, int y, int w, int h,
313 		  Visual * vis, unsigned int depth, EX_Colormap cmap)
314 {
315    Win                 win;
316    EX_Window           xwin;
317    XSetWindowAttributes attr;
318 
319    attr.background_pixmap = NoXID;
320    attr.border_pixel = 0;
321    attr.backing_store = NotUseful;
322    attr.save_under = False;
323    attr.override_redirect = False;
324    attr.colormap = cmap;
325 
326    xwin = XCreateWindow(disp, parent->xwin, x, y, w, h, 0,
327 			depth, InputOutput, vis,
328 			CWOverrideRedirect | CWSaveUnder | CWBackingStore |
329 			CWColormap | CWBackPixmap | CWBorderPixel, &attr);
330    win = _EXidSet(xwin, parent, x, y, w, h, depth, vis, cmap);
331 
332    return win;
333 }
334 
335 Win
ECreateArgbWindow(Win parent,int x,int y,int w,int h,Win cwin)336 ECreateArgbWindow(Win parent, int x, int y, int w, int h, Win cwin)
337 {
338    int                 depth;
339    Visual             *vis;
340    EX_Colormap         cmap;
341 
342    if (cwin && Conf.testing.argb_clients_inherit_attr)
343      {
344 	depth = cwin->depth;
345 	vis = cwin->visual;
346 	cmap = cwin->cmap;
347      }
348    else
349      {
350 	depth = 32;
351 	vis = EVisualFindARGB();
352 	cmap = argb_cmap;
353      }
354 
355    return _ECreateWindowVDC(parent, x, y, w, h, vis, depth, cmap);
356 }
357 
358 #if USE_GLX
359 static              Win
_ECreateWindowVD(Win parent,int x,int y,int w,int h,Visual * vis,unsigned int depth)360 _ECreateWindowVD(Win parent, int x, int y, int w, int h,
361 		 Visual * vis, unsigned int depth)
362 {
363    EX_Colormap         cmap;
364 
365    if (!vis || depth == 0)
366       return 0;
367 
368    cmap = XCreateColormap(disp, WinGetXwin(VROOT), vis, AllocNone);
369 
370    return _ECreateWindowVDC(parent, x, y, w, h, vis, depth, cmap);
371 }
372 #endif
373 
374 Win
ECreateObjectWindow(Win parent,int x,int y,int w,int h,int saveunder,int type,Win cwin)375 ECreateObjectWindow(Win parent, int x, int y, int w, int h, int saveunder,
376 		    int type, Win cwin)
377 {
378    Win                 win;
379    int                 argb = 0;
380 
381    switch (type)
382      {
383      default:
384      case WIN_TYPE_NO_ARGB:
385 	break;
386      case WIN_TYPE_CLIENT:
387 	if (Conf.testing.argb_clients || EVisualIsARGB(cwin->visual))
388 	   argb = 1;
389 	break;
390      case WIN_TYPE_INTERNAL:
391 	if (Conf.testing.argb_internal_objects)
392 	   argb = 1;
393 	break;
394 #if USE_GLX
395      case WIN_TYPE_GLX:	/* Internal GL */
396 	win =
397 	   _ECreateWindowVD(parent, x, y, w, h, EGlGetVisual(), EGlGetDepth());
398 	return win;
399 #endif
400      }
401 
402    if (argb)
403       win = ECreateArgbWindow(parent, x, y, w, h, cwin);
404    else
405       win = ECreateWindow(parent, x, y, w, h, saveunder);
406 
407    return win;
408 }
409 
410 #else
411 
412 Win
ECreateObjectWindow(Win parent,int x,int y,int w,int h,int saveunder,int type __UNUSED__,Win cwin __UNUSED__)413 ECreateObjectWindow(Win parent, int x, int y, int w, int h, int saveunder,
414 		    int type __UNUSED__, Win cwin __UNUSED__)
415 {
416    return ECreateWindow(parent, x, y, w, h, saveunder);
417 }
418 
419 #endif /* USE_COMPOSITE */
420 
421 Win
ECreateClientWindow(Win parent,int x,int y,int w,int h)422 ECreateClientWindow(Win parent, int x, int y, int w, int h)
423 {
424 #if USE_COMPOSITE
425    if (Conf.testing.argb_internal_clients)
426       return ECreateArgbWindow(parent, x, y, w, h, NULL);
427 #endif
428 
429    return ECreateWindow(parent, x, y, w, h, 0);
430 }
431 
432 Win
ECreateEventWindow(Win parent,int x,int y,int w,int h)433 ECreateEventWindow(Win parent, int x, int y, int w, int h)
434 {
435    Win                 win;
436    EX_Window           xwin;
437    XSetWindowAttributes attr;
438 
439    attr.override_redirect = False;
440 
441    xwin = XCreateWindow(disp, parent->xwin, x, y, w, h, 0, 0, InputOnly,
442 			CopyFromParent, CWOverrideRedirect, &attr);
443    win = _EXidSet(xwin, parent, x, y, w, h, 0, NULL, NoXID);
444 
445    return win;
446 }
447 
448 void
EMoveWindow(Win win,int x,int y)449 EMoveWindow(Win win, int x, int y)
450 {
451    if (!win)
452       return;
453 
454 #if 0
455    Eprintf("%s: %p %#x: %d,%d %dx%d -> %d,%d\n", __func__,
456 	   win, win->xwin, win->x, win->y, win->w, win->h, x, y);
457 #endif
458    if ((x == win->x) && (y == win->y))
459       return;
460 
461    win->x = x;
462    win->y = y;
463 
464    XMoveWindow(disp, win->xwin, x, y);
465 }
466 
467 void
EResizeWindow(Win win,int w,int h)468 EResizeWindow(Win win, int w, int h)
469 {
470    if (!win)
471       return;
472 
473    if ((w == win->w) && (h == win->h))
474       return;
475 
476    WinBgInvalidate(win);
477    win->w = w;
478    win->h = h;
479 
480    XResizeWindow(disp, win->xwin, w, h);
481 }
482 
483 void
EMoveResizeWindow(Win win,int x,int y,int w,int h)484 EMoveResizeWindow(Win win, int x, int y, int w, int h)
485 {
486    if (!win)
487       return;
488 
489 #if 0
490    Eprintf("%s: %p %#x: %d,%d %dx%d -> %d,%d %dx%d\n", __func__,
491 	   win, win->xwin, win->x, win->y, win->w, win->h, x, y, w, h);
492 #endif
493    if ((w == win->w) && (h == win->h) && (x == win->x) && (y == win->y))
494       return;
495 
496    if (w != win->w || h != win->h)
497       WinBgInvalidate(win);
498 
499    win->x = x;
500    win->y = y;
501    win->w = w;
502    win->h = h;
503 
504    XMoveResizeWindow(disp, win->xwin, x, y, w, h);
505 }
506 
507 static int
_ExDelTree(Win win)508 _ExDelTree(Win win)
509 {
510    Win                 win2;
511    int                 nsub;
512 
513    win->do_del = -1;
514 
515    nsub = 0;
516    for (win2 = win_first; win2; win2 = win2->next)
517      {
518 	if (win2->parent != win)
519 	   continue;
520 	_ExDelTree(win2);
521 	nsub++;
522      }
523 
524    return nsub;
525 }
526 
527 void
EDestroyWindow(Win win)528 EDestroyWindow(Win win)
529 {
530    Win                 next;
531    int                 nsub;
532 
533    if (!win)
534       return;
535 
536 #if DEBUG_XWIN
537    Eprintf("%s: %p %#x\n", __func__, win, win->xwin);
538 #endif
539    if (win->parent)
540      {
541 	EFreeWindowBackgroundPixmap(win);
542 	XDestroyWindow(disp, win->xwin);
543      }
544 
545    /* Mark the ones to be deleted */
546    nsub = _ExDelTree(win);
547    if (nsub == 0)
548      {
549 	/* No children */
550 	_EXidDel(win);
551 	return;
552      }
553 
554    /* Delete entire tree */
555    for (win = win_first; win; win = next)
556      {
557 	next = win->next;
558 	if (win->do_del < 0)
559 	   _EXidDel(win);
560      }
561 }
562 
563 void
EWindowSync(Win win)564 EWindowSync(Win win)
565 {
566    Window              rr;
567    int                 x, y;
568    unsigned int        w, h, bw, depth;
569 
570    if (!win)
571       return;
572 
573    XGetGeometry(disp, win->xwin, &rr, &x, &y, &w, &h, &bw, &depth);
574 #if 0
575    Eprintf("%s: %p %#x: %d,%d %dx%d -> %d,%d %dx%d\n", __func__,
576 	   win, win->xwin, win->x, win->y, win->w, win->h, x, y, w, h);
577 #endif
578    win->x = x;
579    win->y = y;
580    win->w = w;
581    win->h = h;
582    win->depth = depth;
583 }
584 
585 void
EWindowSetGeometry(Win win,int x,int y,int w,int h,int bw)586 EWindowSetGeometry(Win win, int x, int y, int w, int h, int bw)
587 {
588    if (!win)
589       return;
590 
591    win->x = x;
592    win->y = y;
593    win->w = w;
594    win->h = h;
595    win->bw = bw;
596 }
597 
598 void
EWindowSetMapped(Win win,int mapped)599 EWindowSetMapped(Win win, int mapped)
600 {
601    if (!win)
602       return;
603 
604    win->mapped = mapped;
605 }
606 
607 EX_Window
EXWindowGetParent(EX_Window xwin)608 EXWindowGetParent(EX_Window xwin)
609 {
610    Window              parent, rt;
611    Window             *pch = NULL;
612    unsigned int        nch = 0;
613 
614    parent = NoXID;
615    if (!XQueryTree(disp, xwin, &rt, &parent, &pch, &nch))
616       parent = NoXID;
617    else if (pch)
618       XFree(pch);
619 
620    return parent;
621 }
622 
623 Win
ECreateWinFromXwin(EX_Window xwin)624 ECreateWinFromXwin(EX_Window xwin)
625 {
626    Win                 win;
627    Window              rr;
628    int                 x, y;
629    unsigned int        w, h, bw, depth;
630 
631    if (!XGetGeometry(disp, xwin, &rr, &x, &y, &w, &h, &bw, &depth))
632       return NULL;
633 
634    win = _EXidCreate();
635    if (!win)
636       return NULL;
637 
638    win->xwin = xwin;
639    win->x = x;
640    win->y = y;
641    win->w = w;
642    win->h = h;
643    win->depth = depth;
644    win->visual = WinGetVisual(VROOT);
645    win->cmap = WinGetCmap(VROOT);
646 #if DEBUG_XWIN
647    Eprintf("%s: %p %#x\n", __func__, win, win->xwin);
648 #endif
649 
650    return win;
651 }
652 
653 void
EDestroyWin(Win win)654 EDestroyWin(Win win)
655 {
656    _EXidDestroy(win);
657 }
658 
659 Win
ERegisterWindow(EX_Window xwin,XWindowAttributes * pxwa)660 ERegisterWindow(EX_Window xwin, XWindowAttributes * pxwa)
661 {
662    Win                 win;
663    XWindowAttributes   xwa;
664 
665    win = EXidLookup(xwin);
666    if (win)
667       goto done;
668 
669    if (!pxwa)
670      {
671 	pxwa = &xwa;
672 	if (!EXGetWindowAttributes(xwin, pxwa))
673 	   goto done;
674      }
675 
676 #if 0
677    Eprintf("%s: %p #%x %d+%d %dx%d\n", __func__, win, xwin,
678 	   pxwa->x, pxwa->y, pxwa->width, pxwa->height);
679 #endif
680    win = _EXidSet(xwin, NoXID, pxwa->x, pxwa->y, pxwa->width, pxwa->height,
681 		  pxwa->depth, pxwa->visual, pxwa->colormap);
682    win->mapped = pxwa->map_state != IsUnmapped;
683    win->attached = 1;
684 
685  done:
686    return win;
687 }
688 
689 void
EUnregisterXwin(EX_Window xwin)690 EUnregisterXwin(EX_Window xwin)
691 {
692    Win                 win;
693 
694    win = EXidLookup(xwin);
695    if (!win)
696       return;
697 
698    /* FIXME - We shouldn't go here */
699    _EXidDel(win);
700 #if 1				/* Debug - Fix code if we get here */
701    Eprintf("*** FIXME - %s %#x\n", __func__, xwin);
702 #endif
703 }
704 
705 void
EUnregisterWindow(Win win)706 EUnregisterWindow(Win win)
707 {
708    if (!win)
709       return;
710 
711    if (win->cbl.lst)
712      {
713 	if (EDebug(1))
714 	   Eprintf("%s(%#x) Ignored (%d callbacks remain)\n",
715 		   __func__, win->xwin, win->cbl.num);
716 	return;
717      }
718 
719    _EXidDel(win);
720 }
721 
722 void
EMapWindow(Win win)723 EMapWindow(Win win)
724 {
725    if (!win)
726       return;
727 
728    if (win->mapped)
729       return;
730    win->mapped = 1;
731 
732    XMapWindow(disp, win->xwin);
733 }
734 
735 void
EUnmapWindow(Win win)736 EUnmapWindow(Win win)
737 {
738    if (!win)
739       return;
740 
741    if (!win->mapped)
742       return;
743    win->mapped = 0;
744 
745    XUnmapWindow(disp, win->xwin);
746 }
747 
748 void
EReparentWindow(Win win,Win parent,int x,int y)749 EReparentWindow(Win win, Win parent, int x, int y)
750 {
751    if (!win)
752       return;
753 
754 #if 0
755    Eprintf
756       ("%s: %p %#x: %d %#x->%#x %d,%d %dx%d -> %d,%d\n", __func__,
757        win, win->xwin, win->mapped, (win->parent) ? win->parent->xwin : NoXID,
758        parent->xwin, win->x, win->y, win->w, win->h, x, y);
759 #endif
760    if (parent == win->parent)
761      {
762 	if ((x != win->x) || (y != win->y))
763 	  {
764 	     win->x = x;
765 	     win->y = y;
766 	     XMoveWindow(disp, win->xwin, x, y);
767 	  }
768 	return;
769      }
770    else
771      {
772 	win->parent = parent;
773 	win->x = x;
774 	win->y = y;
775      }
776 
777    XReparentWindow(disp, win->xwin, parent->xwin, x, y);
778 }
779 
780 void
EMapRaised(Win win)781 EMapRaised(Win win)
782 {
783    if (!win)
784       return;
785 
786    if (win->mapped)
787      {
788 	XRaiseWindow(disp, win->xwin);
789 	return;
790      }
791    else
792      {
793 	win->mapped = 1;
794      }
795 
796    XMapRaised(disp, win->xwin);
797 }
798 
799 int
EXGetWindowAttributes(EX_Window xwin,XWindowAttributes * pxwa)800 EXGetWindowAttributes(EX_Window xwin, XWindowAttributes * pxwa)
801 {
802    return XGetWindowAttributes(disp, xwin, pxwa);
803 }
804 
805 int
EXGetSize(EX_Drawable draw,int * w,int * h)806 EXGetSize(EX_Drawable draw, int *w, int *h)
807 {
808    int                 ok;
809    Window              rr;
810    int                 xx, yy;
811    unsigned int        ww, hh, bb, dd;
812 
813    ok = XGetGeometry(disp, draw, &rr, &xx, &yy, &ww, &hh, &bb, &dd);
814    if (!ok)
815      {
816 #if 0				/* Debug */
817 	Eprintf("%s win=%#x, error %d\n", __func__, draw, ok);
818 #endif
819 	if (w)
820 	   *w = 0;
821 	if (h)
822 	   *h = 0;
823 	return 0;
824      }
825 
826    if (w)
827       *w = ww;
828    if (h)
829       *h = hh;
830 
831    return 1;
832 }
833 
834 void
EGetWindowAttributes(Win win,XWindowAttributes * pxwa)835 EGetWindowAttributes(Win win, XWindowAttributes * pxwa)
836 {
837    if (!win)
838       return;
839 
840    pxwa->x = win->x;
841    pxwa->y = win->y;
842    pxwa->width = win->w;
843    pxwa->height = win->h;
844    pxwa->border_width = win->bw;
845    pxwa->depth = win->depth;
846    pxwa->visual = win->visual;
847    pxwa->colormap = win->cmap;
848 }
849 
850 #if 0				/* Unused */
851 void
852 EConfigureWindow(Win win, unsigned int mask, XWindowChanges * wc)
853 {
854    char                doit = 0;
855 
856    if (!win)
857       return;
858 
859    if ((mask & CWX) && (wc->x != win->x))
860      {
861 	win->x = wc->x;
862 	doit = 1;
863      }
864    if ((mask & CWY) && (wc->y != win->y))
865      {
866 	win->y = wc->y;
867 	doit = 1;
868      }
869    if ((mask & CWWidth) && (wc->width != win->w))
870      {
871 	WinBgInvalidate(win);
872 	win->w = wc->width;
873 	doit = 1;
874      }
875    if ((mask & CWHeight) && (wc->height != win->h))
876      {
877 	WinBgInvalidate(win);
878 	win->h = wc->height;
879 	doit = 1;
880      }
881 
882    if ((doit) || (mask & (CWBorderWidth | CWSibling | CWStackMode)))
883       XConfigureWindow(disp, win->xwin, mask, wc);
884 }
885 #endif
886 
887 void
ESetWindowBackgroundPixmap(Win win,EX_Pixmap pmap,int kept)888 ESetWindowBackgroundPixmap(Win win, EX_Pixmap pmap, int kept)
889 {
890    if (!win)
891       return;
892 
893    if (win->bgpmap && win->bg_owned)
894       EFreeWindowBackgroundPixmap(win);
895    win->bgpmap = kept ? pmap : NoXID;
896    win->bg_owned = 0;		/* Don't manage pixmap */
897    win->bgcol = 0xffffffff;	/* Hmmm.. */
898 
899    XSetWindowBackgroundPixmap(disp, win->xwin, pmap);
900 }
901 
902 EX_Pixmap
EGetWindowBackgroundPixmap(Win win)903 EGetWindowBackgroundPixmap(Win win)
904 {
905    EX_Pixmap           pmap;
906 
907    if (!win)
908       return NoXID;
909 
910    if (win->bg_owned < 0)	/* Free if invalidated */
911       EFreeWindowBackgroundPixmap(win);
912    else if (win->bgpmap)
913       return win->bgpmap;
914 
915    /* Allocate/set new */
916    pmap = ECreatePixmap(win, win->w, win->h, 0);
917    ESetWindowBackgroundPixmap(win, pmap, 1);
918    win->bg_owned = 1;		/* Manage pixmap */
919 
920    return pmap;
921 }
922 
923 void
EFreeWindowBackgroundPixmap(Win win)924 EFreeWindowBackgroundPixmap(Win win)
925 {
926    if (!win || !win->bgpmap)
927       return;
928 
929    if (win->bg_owned)
930       EFreePixmap(win->bgpmap);
931    win->bgpmap = NoXID;
932    win->bg_owned = 0;
933 }
934 
935 void
ESetWindowBackground(Win win,unsigned int col)936 ESetWindowBackground(Win win, unsigned int col)
937 {
938    if (!win)
939       return;
940 
941    if (win->bgpmap)
942      {
943 	EFreeWindowBackgroundPixmap(win);
944 	win->bgcol = col;
945      }
946    else if (win->bgcol != col)
947      {
948 	win->bgcol = col;
949      }
950    else
951       return;
952 
953    XSetWindowBackground(disp, win->xwin, col);
954 }
955 
956 #if USE_XI2
957 void
EXIMaskSetup(EXIEventMask * em,int dev,unsigned int event_mask)958 EXIMaskSetup(EXIEventMask * em, int dev, unsigned int event_mask)
959 {
960    em->em.mask_len = sizeof(em->mb);
961    em->em.mask = em->mb;
962    memset(em->mb, 0, sizeof(em->mb));
963 
964    em->em.deviceid = dev;
965 
966    if (event_mask & KeyPressMask)
967       XISetMask(em->mb, XI_KeyPress);
968    if (event_mask & KeyReleaseMask)
969       XISetMask(em->mb, XI_KeyRelease);
970 
971    if (event_mask & ButtonPressMask)
972       XISetMask(em->mb, XI_ButtonPress);
973    if (event_mask & ButtonReleaseMask)
974       XISetMask(em->mb, XI_ButtonRelease);
975    if (event_mask & PointerMotionMask)
976       XISetMask(em->mb, XI_Motion);
977 
978    if (event_mask & EnterWindowMask)
979       XISetMask(em->mb, XI_Enter);
980    if (event_mask & LeaveWindowMask)
981       XISetMask(em->mb, XI_Leave);
982 
983    if (event_mask & FocusChangeMask)
984      {
985 	XISetMask(em->mb, XI_FocusIn);
986 	XISetMask(em->mb, XI_FocusOut);
987      }
988 }
989 #endif
990 
991 void
ESelectInput(Win win,unsigned int event_mask)992 ESelectInput(Win win, unsigned int event_mask)
993 {
994 #if USE_XI2
995    unsigned int        evold_mask;
996 
997 #define EVENTS_TO_XI_KBD (KeyPressMask | KeyReleaseMask)
998 #define EVENTS_TO_XI_PTR (ButtonPressMask | ButtonReleaseMask | PointerMotionMask)
999 #define EVENTS_TO_XI_WEL (EnterWindowMask | LeaveWindowMask)
1000 #define EVENTS_TO_XI_WFO (FocusChangeMask)
1001 #define EVENTS_TO_XI \
1002    (EVENTS_TO_XI_KBD | EVENTS_TO_XI_PTR | EVENTS_TO_XI_WEL | EVENTS_TO_XI_WFO)
1003 
1004    evold_mask = win->event_mask;
1005    win->event_mask = event_mask;
1006 
1007    if (((event_mask ^ evold_mask) & EVENTS_TO_XI) && XEXT_AVAILABLE(XEXT_XI))
1008      {
1009 	EXIEventMask        em;
1010 
1011 	EXIMaskSetup(&em, XIAllMasterDevices, event_mask & EVENTS_TO_XI);
1012 	XISelectEvents(disp, win->xwin, &em.em, 1);
1013 
1014 	event_mask &= ~EVENTS_TO_XI;
1015 	evold_mask &= ~EVENTS_TO_XI;
1016      }
1017 
1018    if (event_mask ^ evold_mask)
1019      {
1020 	XSelectInput(disp, win->xwin, event_mask);
1021      }
1022 #else
1023    XSelectInput(disp, win->xwin, event_mask);
1024 #endif
1025 }
1026 
1027 void
ESelectInputChange(Win win,unsigned int set,unsigned int clear)1028 ESelectInputChange(Win win, unsigned int set, unsigned int clear)
1029 {
1030 #if USE_XI2
1031    ESelectInput(win, (win->event_mask | set) & ~clear);
1032 #else
1033    XWindowAttributes   xwa;
1034 
1035    EXGetWindowAttributes(win->xwin, &xwa);
1036    xwa.your_event_mask |= set;
1037    xwa.your_event_mask &= ~clear;
1038    XSelectInput(disp, win->xwin, xwa.your_event_mask);
1039 #endif
1040 }
1041 
1042 void
EChangeWindowAttributes(Win win,unsigned int mask,XSetWindowAttributes * attr)1043 EChangeWindowAttributes(Win win, unsigned int mask, XSetWindowAttributes * attr)
1044 {
1045    XChangeWindowAttributes(disp, win->xwin, mask, attr);
1046 }
1047 
1048 void
ESetWindowBorderWidth(Win win,unsigned int bw)1049 ESetWindowBorderWidth(Win win, unsigned int bw)
1050 {
1051    XSetWindowBorderWidth(disp, win->xwin, bw);
1052 }
1053 
1054 void
ERaiseWindow(Win win)1055 ERaiseWindow(Win win)
1056 {
1057    XRaiseWindow(disp, win->xwin);
1058 }
1059 
1060 void
ELowerWindow(Win win)1061 ELowerWindow(Win win)
1062 {
1063    XLowerWindow(disp, win->xwin);
1064 }
1065 
1066 void
EXRestackWindows(EX_Window * windows,int nwindows)1067 EXRestackWindows(EX_Window * windows, int nwindows)
1068 {
1069 #if SIZEOF_INT == SIZEOF_LONG
1070    XRestackWindows(disp, (Window *) windows, nwindows);
1071 #else
1072    int                 i;
1073    Window             *_wins;
1074 
1075    _wins = EMALLOC(Window, nwindows);
1076    if (!_wins)
1077       return;
1078 
1079    for (i = 0; i < nwindows; i++)
1080       _wins[i] = windows[i];
1081    XRestackWindows(disp, _wins, nwindows);
1082 
1083    Efree(_wins);
1084 #endif
1085 }
1086 
1087 void
EClearWindow(Win win)1088 EClearWindow(Win win)
1089 {
1090    XClearWindow(disp, win->xwin);
1091 }
1092 
1093 void
EClearWindowExpose(Win win)1094 EClearWindowExpose(Win win)
1095 {
1096    XClearArea(disp, win->xwin, 0, 0, 0, 0, True);
1097 }
1098 
1099 void
EClearArea(Win win,int x,int y,unsigned int w,unsigned int h)1100 EClearArea(Win win, int x, int y, unsigned int w, unsigned int h)
1101 {
1102    XClearArea(disp, win->xwin, x, y, w, h, False);
1103 }
1104 
1105 int
ETranslateCoordinates(Win src_w,Win dst_w,int src_x,int src_y,int * dest_x_return,int * dest_y_return,EX_Window * child_return)1106 ETranslateCoordinates(Win src_w, Win dst_w, int src_x, int src_y,
1107 		      int *dest_x_return, int *dest_y_return,
1108 		      EX_Window * child_return)
1109 {
1110    Window              child;
1111    Bool                rc;
1112 
1113    rc = XTranslateCoordinates(disp, src_w->xwin, dst_w->xwin, src_x, src_y,
1114 			      dest_x_return, dest_y_return, &child);
1115 
1116    if (child_return)
1117       *child_return = child;
1118 
1119    return rc;
1120 }
1121 
1122 void
EXWarpPointer(EX_Window xwin,int x,int y)1123 EXWarpPointer(EX_Window xwin, int x, int y)
1124 {
1125    XWarpPointer(disp, NoXID, xwin, 0, 0, 0, 0, x, y);
1126 }
1127 
1128 void
EWarpPointer(Win win,int x,int y)1129 EWarpPointer(Win win, int x, int y)
1130 {
1131    EXWarpPointer(win ? win->xwin : NoXID, x, y);
1132 }
1133 
1134 int
EXQueryPointer(EX_Window xwin,int * px,int * py,EX_Window * pchild,unsigned int * pmask)1135 EXQueryPointer(EX_Window xwin, int *px, int *py, EX_Window * pchild,
1136 	       unsigned int *pmask)
1137 {
1138    Window              root, child;
1139    int                 root_x, root_y;
1140    unsigned int        mask;
1141    Bool                rc;
1142 
1143    if (xwin == NoXID)
1144       xwin = WinGetXwin(VROOT);
1145 
1146    if (!px)
1147       px = &root_x;
1148    if (!py)
1149       py = &root_y;
1150    if (!pmask)
1151       pmask = &mask;
1152 
1153    rc = XQueryPointer(disp, xwin, &root, &child, &root_x, &root_y, px, py,
1154 		      pmask);
1155 
1156    if (pchild)
1157       *pchild = child;
1158 
1159    return rc;
1160 }
1161 
1162 int
EQueryPointer(Win win,int * px,int * py,EX_Window * pchild,unsigned int * pmask)1163 EQueryPointer(Win win, int *px, int *py, EX_Window * pchild,
1164 	      unsigned int *pmask)
1165 {
1166    EX_Window           xwin;
1167 
1168    xwin = (win) ? win->xwin : WinGetXwin(VROOT);
1169 
1170    return EXQueryPointer(xwin, px, py, pchild, pmask);
1171 }
1172 
1173 int
EXDrawableOk(EX_Drawable draw)1174 EXDrawableOk(EX_Drawable draw)
1175 {
1176    if (draw == NoXID)
1177       return 0;
1178 
1179    return EXGetSize(draw, NULL, NULL);
1180 }
1181 
1182 int
EXWindowOk(EX_Window xwin)1183 EXWindowOk(EX_Window xwin)
1184 {
1185    XWindowAttributes   xwa;
1186 
1187    if (xwin == NoXID)
1188       return 0;
1189 
1190    return EXGetWindowAttributes(xwin, &xwa);
1191 }
1192 
1193 EX_KeyCode
EKeysymToKeycode(EX_KeySym keysym)1194 EKeysymToKeycode(EX_KeySym keysym)
1195 {
1196    return XKeysymToKeycode(disp, keysym);
1197 }
1198 
1199 EX_KeyCode
EKeynameToKeycode(const char * name)1200 EKeynameToKeycode(const char *name)
1201 {
1202    return XKeysymToKeycode(disp, XStringToKeysym(name));
1203 }
1204 
1205 #define DEBUG_SHAPE_OPS       0
1206 #define DEBUG_SHAPE_PROPAGATE 0
1207 
1208 #if DEBUG_SHAPE_OPS || DEBUG_SHAPE_PROPAGATE
1209 static void
_EShapeShow(const char * txt,EX_Window xwin,XRectangle * pr,int nr)1210 _EShapeShow(const char *txt, EX_Window xwin, XRectangle * pr, int nr)
1211 {
1212    int                 i;
1213 
1214    Eprintf("%s %#x nr=%d\n", txt, xwin, nr);
1215    for (i = 0; i < nr; i++)
1216       Eprintf(" %3d - %4d,%4d %4dx%4d\n", i,
1217 	      pr[i].x, pr[i].y, pr[i].width, pr[i].height);
1218 }
1219 #endif
1220 
1221 int
EShapeUpdate(Win win)1222 EShapeUpdate(Win win)
1223 {
1224    if (win->rects)
1225      {
1226 	XFree(win->rects);
1227 	win->num_rect = 0;
1228      }
1229 
1230    win->rects =
1231       XShapeGetRectangles(disp, win->xwin, ShapeBounding, &(win->num_rect),
1232 			  &(win->ord));
1233    if (win->rects)
1234      {
1235 	if (win->num_rect == 1)
1236 	  {
1237 	     if ((win->rects[0].x == 0) && (win->rects[0].y == 0)
1238 		 && (win->rects[0].width == win->w)
1239 		 && (win->rects[0].height == win->h))
1240 	       {
1241 		  win->num_rect = 0;
1242 		  XFree(win->rects);
1243 		  win->rects = NULL;
1244 		  XShapeCombineMask(disp, win->xwin, ShapeBounding, 0, 0,
1245 				    NoXID, ShapeSet);
1246 	       }
1247 	  }
1248 	else if (win->num_rect > 4096)
1249 	  {
1250 	     Eprintf("*** %s: nrect=%d - Not likely, ignoring.\n", __func__,
1251 		     win->num_rect);
1252 	     XShapeCombineMask(disp, win->xwin, ShapeBounding, 0, 0, NoXID,
1253 			       ShapeSet);
1254 	     win->num_rect = 0;
1255 	     XFree(win->rects);
1256 	     win->rects = NULL;
1257 	  }
1258      }
1259    else
1260      {
1261 	win->num_rect = -1;
1262      }
1263 #if DEBUG_SHAPE_OPS
1264    _EShapeShow(__func__, win->xwin, win->rects, win->num_rect);
1265 #endif
1266    return win->num_rect != 0;
1267 }
1268 
1269 static void
_EShapeCombineMask(Win win,int dest,int x,int y,EX_Pixmap pmap,int op)1270 _EShapeCombineMask(Win win, int dest, int x, int y, EX_Pixmap pmap, int op)
1271 {
1272    char                wasshaped = 0;
1273 
1274    if (!win)
1275       return;
1276 
1277    if (win->rects || win->num_rect < 0)
1278      {
1279 	win->num_rect = 0;
1280 	if (win->rects)
1281 	   XFree(win->rects);
1282 	win->rects = NULL;
1283 	wasshaped = 1;
1284      }
1285 #if DEBUG_SHAPE_OPS
1286    Eprintf("%s %#x %d,%d %dx%d mask=%#x wassh=%d\n", __func__,
1287 	   win->xwin, win->x, win->y, win->w, win->h, pmap, wasshaped);
1288 #endif
1289    if (pmap)
1290      {
1291 	XShapeCombineMask(disp, win->xwin, dest, x, y, pmap, op);
1292 	EShapeUpdate(win);
1293      }
1294    else if (wasshaped)
1295       XShapeCombineMask(disp, win->xwin, dest, x, y, pmap, op);
1296 }
1297 
1298 static void
_EShapeCombineMaskTiled(Win win,int dest,int x,int y,EX_Pixmap pmap,int op,int w,int h)1299 _EShapeCombineMaskTiled(Win win, int dest, int x, int y,
1300 			EX_Pixmap pmap, int op, int w, int h)
1301 {
1302    XGCValues           gcv;
1303    GC                  gc;
1304    EX_Window           tm;
1305 
1306    gcv.fill_style = FillTiled;
1307    gcv.tile = pmap;
1308    gcv.ts_x_origin = 0;
1309    gcv.ts_y_origin = 0;
1310    tm = ECreatePixmap(win, w, h, 1);
1311    gc = EXCreateGC(tm, GCFillStyle | GCTile |
1312 		   GCTileStipXOrigin | GCTileStipYOrigin, &gcv);
1313    XFillRectangle(disp, tm, gc, 0, 0, w, h);
1314    EXFreeGC(gc);
1315    _EShapeCombineMask(win, dest, x, y, tm, op);
1316    EFreePixmap(tm);
1317 }
1318 
1319 static void
_EShapeCombineRectangles(Win win,int dest,int x,int y,XRectangle * rect,int n_rects,int op,int ordering)1320 _EShapeCombineRectangles(Win win, int dest, int x, int y,
1321 			 XRectangle * rect, int n_rects, int op, int ordering)
1322 {
1323    if (!win)
1324       return;
1325 #if DEBUG_SHAPE_OPS
1326    Eprintf("%s %#x %d\n", __func__, win->xwin, n_rects);
1327 #endif
1328 
1329    if (n_rects == 1 && op == ShapeSet)
1330      {
1331 	if ((rect[0].x == 0) && (rect[0].y == 0) &&
1332 	    (rect[0].width == win->w) && (rect[0].height == win->h))
1333 	  {
1334 	     win->num_rect = 0;
1335 	     XFree(win->rects);
1336 	     win->rects = NULL;
1337 	     XShapeCombineMask(disp, win->xwin, dest, x, y, NoXID, op);
1338 	     return;
1339 	  }
1340      }
1341    XShapeCombineRectangles(disp, win->xwin, dest, x, y, rect, n_rects, op,
1342 			   ordering);
1343    if (n_rects > 1)
1344      {
1345 	/* Limit shape to window extents */
1346 	XRectangle          r;
1347 
1348 	r.x = r.y = 0;
1349 	r.width = win->w;
1350 	r.height = win->h;
1351 	XShapeCombineRectangles(disp, win->xwin, ShapeBounding, 0, 0, &r,
1352 				1, ShapeIntersect, Unsorted);
1353      }
1354    EShapeUpdate(win);
1355 }
1356 
1357 static void
_EShapeCombineShape(Win win,int dest,int x,int y,Win src_win,int src_kind,int op)1358 _EShapeCombineShape(Win win, int dest, int x, int y,
1359 		    Win src_win, int src_kind, int op)
1360 {
1361    XShapeCombineShape(disp, win->xwin, dest, x, y, src_win->xwin, src_kind, op);
1362    EShapeUpdate(win);
1363 }
1364 
1365 int
EShapePropagate(Win win)1366 EShapePropagate(Win win)
1367 {
1368    Win                 xch;
1369    unsigned int        num_rects;
1370    int                 k, rn;
1371    int                 x, y, w, h;
1372    XRectangle         *rects, *rectsn, *rl;
1373 
1374    if (!win || win->w <= 0 || win->h <= 0)
1375       return 0;
1376 
1377 #if DEBUG_SHAPE_PROPAGATE
1378    Eprintf("%s %#x %d,%d %dx%d\n", __func__, win->xwin,
1379 	   win->x, win->y, win->w, win->h);
1380 #endif
1381 
1382    num_rects = 0;
1383    rects = NULL;
1384 
1385    /* go through all child windows and create/inset spans */
1386    for (xch = win_first; xch; xch = xch->next)
1387      {
1388 	if (xch->parent != win)
1389 	   continue;
1390 
1391 #if DEBUG_SHAPE_PROPAGATE > 1
1392 	Eprintf("%#x(%d/%d): %4d,%4d %4dx%4d\n",
1393 		xch->xwin, xch->mapped, xch->num_rect,
1394 		xch->x, xch->y, xch->w, xch->h);
1395 #endif
1396 	if (!xch->mapped)
1397 	   continue;
1398 
1399 	x = xch->x;
1400 	y = xch->y;
1401 	w = xch->w;
1402 	h = xch->h;
1403 	if (x >= win->w || y >= win->h || x + w < 0 || y + h < 0)
1404 	   continue;
1405 
1406 	rn = xch->num_rect;
1407 
1408 	if (rn > 0)
1409 	  {
1410 	     rl = xch->rects;
1411 	     rectsn = EREALLOC(XRectangle, rects, num_rects + rn);
1412 	     if (!rectsn)
1413 		goto bail_out;
1414 	     rects = rectsn;
1415 
1416 	     /* go through all clip rects in this window's shape */
1417 	     for (k = 0; k < rn; k++)
1418 	       {
1419 		  /* for each clip rect, add it to the rect list */
1420 		  rects[num_rects].x = x + rl[k].x;
1421 		  rects[num_rects].y = y + rl[k].y;
1422 		  rects[num_rects].width = rl[k].width;
1423 		  rects[num_rects].height = rl[k].height;
1424 #if DEBUG_SHAPE_PROPAGATE > 1
1425 		  Eprintf(" - %x %d: %4d,%4d %4dx%4d\n", xch->xwin, k,
1426 			  rects[num_rects].x, rects[num_rects].y,
1427 			  rects[num_rects].width, rects[num_rects].height);
1428 #endif
1429 		  num_rects++;
1430 	       }
1431 	  }
1432 	else if (rn == 0)
1433 	  {
1434 	     /* Unshaped */
1435 	     rectsn = EREALLOC(XRectangle, rects, num_rects + 1);
1436 	     if (!rectsn)
1437 		goto bail_out;
1438 	     rects = rectsn;
1439 
1440 	     rects[num_rects].x = x;
1441 	     rects[num_rects].y = y;
1442 	     rects[num_rects].width = w;
1443 	     rects[num_rects].height = h;
1444 #if DEBUG_SHAPE_PROPAGATE > 1
1445 	     Eprintf(" - %x  : %4d,%4d %4dx%4d\n", xch->xwin,
1446 		     rects[num_rects].x, rects[num_rects].y,
1447 		     rects[num_rects].width, rects[num_rects].height);
1448 #endif
1449 	     num_rects++;
1450 	  }
1451      }
1452 
1453 #if DEBUG_SHAPE_PROPAGATE
1454    _EShapeShow(__func__, win->xwin, rects, num_rects);
1455 #endif
1456 
1457    /* set the rects as the shape mask */
1458    if (rects)
1459      {
1460 	_EShapeCombineRectangles(win, ShapeBounding, 0, 0, rects,
1461 				 num_rects, ShapeSet, Unsorted);
1462 	Efree(rects);
1463      }
1464    else
1465      {
1466 	/* Empty shape */
1467 	_EShapeCombineRectangles(win, ShapeBounding, 0, 0, NULL, 0, ShapeSet,
1468 				 Unsorted);
1469      }
1470 
1471    return win->num_rect;
1472 
1473  bail_out:
1474    Efree(rects);
1475    _EShapeCombineMask(win, ShapeBounding, 0, 0, NoXID, ShapeSet);
1476    return 0;
1477 }
1478 
1479 int
EShapeCheck(Win win)1480 EShapeCheck(Win win)
1481 {
1482    if (!win)
1483       return 0;
1484 
1485    return win->num_rect;
1486 }
1487 
1488 void
EShapeSetMask(Win win,int x,int y,EX_Pixmap mask)1489 EShapeSetMask(Win win, int x, int y, EX_Pixmap mask)
1490 {
1491    _EShapeCombineMask(win, ShapeBounding, x, y, mask, ShapeSet);
1492 }
1493 
1494 void
EShapeUnionMask(Win win,int x,int y,EX_Pixmap mask)1495 EShapeUnionMask(Win win, int x, int y, EX_Pixmap mask)
1496 {
1497    _EShapeCombineMask(win, ShapeBounding, x, y, mask, ShapeUnion);
1498 }
1499 
1500 void
EShapeSetMaskTiled(Win win,int x,int y,EX_Pixmap mask,int w,int h)1501 EShapeSetMaskTiled(Win win, int x, int y, EX_Pixmap mask, int w, int h)
1502 {
1503    _EShapeCombineMaskTiled(win, ShapeBounding, x, y, mask, ShapeSet, w, h);
1504 }
1505 
1506 void
EShapeSetRects(Win win,int x,int y,XRectangle * rect,int n_rects)1507 EShapeSetRects(Win win, int x, int y, XRectangle * rect, int n_rects)
1508 {
1509    _EShapeCombineRectangles(win, ShapeBounding, x, y, rect, n_rects,
1510 			    ShapeSet, Unsorted);
1511 }
1512 
1513 void
EShapeUnionRects(Win win,int x,int y,XRectangle * rect,int n_rects)1514 EShapeUnionRects(Win win, int x, int y, XRectangle * rect, int n_rects)
1515 {
1516    _EShapeCombineRectangles(win, ShapeBounding, x, y, rect, n_rects,
1517 			    ShapeUnion, Unsorted);
1518 }
1519 
1520 int
EShapeSetShape(Win win,int x,int y,Win src_win)1521 EShapeSetShape(Win win, int x, int y, Win src_win)
1522 {
1523    _EShapeCombineShape(win, ShapeBounding, x, y,
1524 		       src_win, ShapeBounding, ShapeSet);
1525    return win->num_rect != 0;
1526 }
1527 
1528 static              EX_Pixmap
_EWindowGetShapePixmap(Win win,unsigned int fg,unsigned int bg)1529 _EWindowGetShapePixmap(Win win, unsigned int fg, unsigned int bg)
1530 {
1531    EX_Pixmap           mask;
1532    GC                  gc;
1533    int                 i;
1534    const XRectangle   *rect;
1535 
1536    if (win->num_rect == 0)	/* Not shaped */
1537       return NoXID;
1538 
1539    mask = ECreatePixmap(win, win->w, win->h, 1);
1540    gc = EXCreateGC(mask, 0, NULL);
1541 
1542    XSetForeground(disp, gc, bg);
1543    XFillRectangle(disp, mask, gc, 0, 0, win->w, win->h);
1544 
1545    XSetForeground(disp, gc, fg);
1546    rect = win->rects;
1547    for (i = 0; i < win->num_rect; i++)
1548       XFillRectangle(disp, mask, gc, rect[i].x, rect[i].y,
1549 		     rect[i].width, rect[i].height);
1550 
1551    EXFreeGC(gc);
1552 
1553    return mask;
1554 }
1555 
1556 /* Build mask from window shape rects */
1557 EX_Pixmap
EWindowGetShapePixmap(Win win)1558 EWindowGetShapePixmap(Win win)
1559 {
1560    return _EWindowGetShapePixmap(win, 1, 0);
1561 }
1562 
1563 /* Build inverted mask from window shape rects */
1564 EX_Pixmap
EWindowGetShapePixmapInverted(Win win)1565 EWindowGetShapePixmapInverted(Win win)
1566 {
1567    return _EWindowGetShapePixmap(win, 0, 1);
1568 }
1569 
1570 EX_Pixmap
ECreatePixmap(Win win,unsigned int width,unsigned int height,unsigned int depth)1571 ECreatePixmap(Win win, unsigned int width, unsigned int height,
1572 	      unsigned int depth)
1573 {
1574    EX_Pixmap           pmap;
1575 
1576    if (depth == 0)
1577       depth = win->depth;
1578 
1579    pmap = XCreatePixmap(disp, win->xwin, width, height, depth);
1580 #if DEBUG_PIXMAP
1581    Eprintf("%s: %#x\n", __func__, pmap);
1582 #endif
1583    return pmap;
1584 }
1585 
1586 void
EFreePixmap(EX_Pixmap pmap)1587 EFreePixmap(EX_Pixmap pmap)
1588 {
1589 #if DEBUG_PIXMAP
1590    Eprintf("%s: %#x\n", __func__, pmap);
1591 #endif
1592    XFreePixmap(disp, pmap);
1593 }
1594 
1595 EX_Pixmap
EXCreatePixmapCopy(EX_Pixmap src,unsigned int w,unsigned int h,unsigned int depth)1596 EXCreatePixmapCopy(EX_Pixmap src, unsigned int w, unsigned int h,
1597 		   unsigned int depth)
1598 {
1599    EX_Pixmap           pmap;
1600    GC                  gc;
1601 
1602    pmap = XCreatePixmap(disp, src, w, h, depth);
1603    gc = EXCreateGC(src, 0, NULL);
1604    XCopyArea(disp, src, pmap, gc, 0, 0, w, h, 0, 0);
1605    EXFreeGC(gc);
1606 #if DEBUG_PIXMAP
1607    Eprintf("%s: %#x\n", __func__, pmap);
1608 #endif
1609    return pmap;
1610 }
1611 
1612 void
EXCopyAreaGC(EX_Drawable src,EX_Drawable dst,GC gc,int sx,int sy,unsigned int w,unsigned int h,int dx,int dy)1613 EXCopyAreaGC(EX_Drawable src, EX_Drawable dst, GC gc, int sx, int sy,
1614 	     unsigned int w, unsigned int h, int dx, int dy)
1615 {
1616    XCopyArea(disp, src, dst, gc, sx, sy, w, h, dx, dy);
1617 }
1618 
1619 void
EXCopyArea(EX_Drawable src,EX_Drawable dst,int sx,int sy,unsigned int w,unsigned int h,int dx,int dy)1620 EXCopyArea(EX_Drawable src, EX_Drawable dst, int sx, int sy,
1621 	   unsigned int w, unsigned int h, int dx, int dy)
1622 {
1623    GC                  gc = (GC) Dpy.root_gc;
1624 
1625    XCopyArea(disp, src, dst, gc, sx, sy, w, h, dx, dy);
1626 }
1627 
1628 void
EXCopyAreaTiled(EX_Drawable src,EX_Pixmap mask,EX_Drawable dst,int sx,int sy,unsigned int w,unsigned int h,int dx,int dy)1629 EXCopyAreaTiled(EX_Drawable src, EX_Pixmap mask, EX_Drawable dst,
1630 		int sx, int sy, unsigned int w, unsigned int h, int dx, int dy)
1631 {
1632    GC                  gc;
1633    XGCValues           gcv;
1634 
1635    gcv.fill_style = FillTiled;
1636    gcv.tile = src;
1637    gcv.ts_x_origin = sx;
1638    gcv.ts_y_origin = sy;
1639    gcv.clip_mask = mask;
1640    gc = EXCreateGC(dst, GCFillStyle |
1641 		   GCTile | GCTileStipXOrigin | GCTileStipYOrigin | GCClipMask,
1642 		   &gcv);
1643    XFillRectangle(disp, dst, gc, dx, dy, w, h);
1644    EXFreeGC(gc);
1645 }
1646 
1647 void
EXFillAreaSolid(EX_Drawable dst,int x,int y,unsigned int w,unsigned int h,unsigned int pixel)1648 EXFillAreaSolid(EX_Drawable dst, int x, int y, unsigned int w, unsigned int h,
1649 		unsigned int pixel)
1650 {
1651    GC                  gc;
1652    XGCValues           gcv;
1653 
1654    gcv.foreground = pixel;
1655    gc = EXCreateGC(dst, GCForeground, &gcv);
1656    XFillRectangle(disp, dst, gc, x, y, w, h);
1657    EXFreeGC(gc);
1658 }
1659 
1660 static void
_EXDrawRectangle(EX_Drawable dst,GC gc,int x,int y,unsigned int w,unsigned int h,unsigned int pixel)1661 _EXDrawRectangle(EX_Drawable dst, GC gc, int x, int y,
1662 		 unsigned int w, unsigned int h, unsigned int pixel)
1663 {
1664    XSetForeground(disp, gc, pixel);
1665    XDrawRectangle(disp, dst, gc, x, y, w, h);
1666 }
1667 
1668 static void
_EXFillRectangle(EX_Drawable dst,GC gc,int x,int y,unsigned int w,unsigned int h,unsigned int pixel)1669 _EXFillRectangle(EX_Drawable dst, GC gc, int x, int y,
1670 		 unsigned int w, unsigned int h, unsigned int pixel)
1671 {
1672    XSetForeground(disp, gc, pixel);
1673    XFillRectangle(disp, dst, gc, x, y, w, h);
1674 }
1675 
1676 void
EXPaintRectangle(EX_Drawable dst,int x,int y,unsigned int w,unsigned int h,unsigned int fg,unsigned int bg)1677 EXPaintRectangle(EX_Drawable dst, int x, int y,
1678 		 unsigned int w, unsigned int h,
1679 		 unsigned int fg, unsigned int bg)
1680 {
1681    GC                  gc;
1682 
1683    if (w == 0 || h == 0)
1684       return;
1685    gc = EXCreateGC(dst, 0, NULL);
1686    _EXDrawRectangle(dst, gc, x, y, w - 1, h - 1, fg);
1687    if (w > 2 && h > 2)
1688       _EXFillRectangle(dst, gc, x + 1, y + 1, w - 2, h - 2, bg);
1689    EXFreeGC(gc);
1690 }
1691 
1692 GC
EXCreateGC(EX_Drawable draw,unsigned int mask,XGCValues * val)1693 EXCreateGC(EX_Drawable draw, unsigned int mask, XGCValues * val)
1694 {
1695    XGCValues           xgcv;
1696 
1697    if (val)
1698      {
1699 	mask |= GCGraphicsExposures;
1700 	val->graphics_exposures = False;
1701      }
1702    else
1703      {
1704 	mask = GCSubwindowMode | GCGraphicsExposures;
1705 	val = &xgcv;
1706 	val->subwindow_mode = IncludeInferiors;
1707 	val->graphics_exposures = False;
1708      }
1709    return XCreateGC(disp, draw, mask, val);
1710 }
1711 
1712 void
EXFreeGC(GC gc)1713 EXFreeGC(GC gc)
1714 {
1715    if (gc)
1716       XFreeGC(disp, gc);
1717 }
1718 
1719 void
EXSendEvent(EX_Window xwin,unsigned int event_mask,XEvent * ev)1720 EXSendEvent(EX_Window xwin, unsigned int event_mask, XEvent * ev)
1721 {
1722    XSendEvent(disp, xwin, False, event_mask, ev);
1723 }
1724 
1725 unsigned int
EAllocColor(EX_Colormap cmap,unsigned int argb)1726 EAllocColor(EX_Colormap cmap, unsigned int argb)
1727 {
1728    XColor              xc;
1729 
1730    COLOR32_TO_RGB16(argb, xc.red, xc.green, xc.blue);
1731    XAllocColor(disp, cmap, &xc);
1732 
1733    return xc.pixel;
1734 }
1735 
1736 /*
1737  * Display
1738  */
1739 
1740 int
EDisplayOpen(const char * dstr,int scr)1741 EDisplayOpen(const char *dstr, int scr)
1742 {
1743    char                dbuf[256], *s;
1744    unsigned int        ddpy, dscr;
1745 
1746    if (!dstr)
1747       goto do_open;
1748 
1749    Esnprintf(dbuf, sizeof(dbuf), "%s", dstr);
1750    s = strchr(dbuf, ':');
1751    if (!s)
1752       return -1;
1753    s++;
1754 
1755    ddpy = dscr = 0;
1756    sscanf(s, "%u.%u", &ddpy, &dscr);
1757    if (scr >= 0)		/* Override screen */
1758       dscr = scr;
1759    Esnprintf(s, sizeof(dbuf) - (s - dbuf), "%u.%u", ddpy, dscr);
1760    dstr = dbuf;
1761 
1762  do_open:
1763    disp = XOpenDisplay(dstr);
1764 
1765    return (disp) ? 0 : -1;
1766 }
1767 
1768 void
EDisplayClose(void)1769 EDisplayClose(void)
1770 {
1771    if (!disp)
1772       return;
1773    XCloseDisplay(disp);
1774    XSetErrorHandler(NULL);
1775    XSetIOErrorHandler(NULL);
1776    disp = NULL;
1777 }
1778 
1779 void
EDisplayDisconnect(void)1780 EDisplayDisconnect(void)
1781 {
1782    if (!disp)
1783       return;
1784    close(ConnectionNumber(disp));
1785    XSetErrorHandler(NULL);
1786    XSetIOErrorHandler(NULL);
1787 
1788    disp = NULL;
1789 }
1790 
1791 static EXErrorHandler *EXErrorFunc = NULL;
1792 static EXIOErrorHandler *EXIOErrorFunc = NULL;
1793 
1794 static int
_HandleXError(Display * dpy __UNUSED__,XErrorEvent * ev)1795 _HandleXError(Display * dpy __UNUSED__, XErrorEvent * ev)
1796 {
1797    if (EDebug(1) && EXErrorFunc)
1798       EXErrorFunc((XEvent *) ev);
1799 
1800    Dpy.last_error_code = ev->error_code;
1801 
1802    return 0;
1803 }
1804 
1805 static int
_HandleXIOError(Display * dpy __UNUSED__)1806 _HandleXIOError(Display * dpy __UNUSED__)
1807 {
1808    disp = NULL;
1809 
1810    if (EXIOErrorFunc)
1811       EXIOErrorFunc();
1812 
1813    return 0;
1814 }
1815 
1816 void
EDisplaySetErrorHandlers(EXErrorHandler * error,EXIOErrorHandler * fatal)1817 EDisplaySetErrorHandlers(EXErrorHandler * error, EXIOErrorHandler * fatal)
1818 {
1819    /* set up an error handler for then E would normally have fatal X errors */
1820    EXErrorFunc = error;
1821    XSetErrorHandler(_HandleXError);
1822 
1823    /* set up a handler for when the X Connection goes down */
1824    EXIOErrorFunc = fatal;
1825    XSetIOErrorHandler(_HandleXIOError);
1826 }
1827 
1828 /*
1829  * Server
1830  */
1831 
1832 void
EGrabServer(void)1833 EGrabServer(void)
1834 {
1835    if (Dpy.server_grabbed <= 0)
1836      {
1837 	if (EDebug(EDBUG_TYPE_GRABS))
1838 	   Eprintf("%s\n", __func__);
1839 	XGrabServer(disp);
1840      }
1841    Dpy.server_grabbed++;
1842 }
1843 
1844 void
EUngrabServer(void)1845 EUngrabServer(void)
1846 {
1847    if (Dpy.server_grabbed == 1)
1848      {
1849 	XUngrabServer(disp);
1850 	XFlush(disp);
1851 	if (EDebug(EDBUG_TYPE_GRABS))
1852 	   Eprintf("%s\n", __func__);
1853      }
1854    Dpy.server_grabbed--;
1855    if (Dpy.server_grabbed < 0)
1856       Dpy.server_grabbed = 0;
1857 }
1858 
1859 int
EServerIsGrabbed(void)1860 EServerIsGrabbed(void)
1861 {
1862    return Dpy.server_grabbed;
1863 }
1864 
1865 void
EFlush(void)1866 EFlush(void)
1867 {
1868    XFlush(disp);
1869 }
1870 
1871 void
ESync(unsigned int mask)1872 ESync(unsigned int mask)
1873 {
1874    if (mask & Conf.testing.no_sync_mask)
1875       return;
1876    XSync(disp, False);
1877 }
1878 
1879 /*
1880  * Visuals
1881  */
1882 
1883 #if USE_XRENDER
1884 
1885 Visual             *
EVisualFindARGB(void)1886 EVisualFindARGB(void)
1887 {
1888    XVisualInfo        *xvi, xvit;
1889    int                 i, num;
1890    Visual             *vis;
1891 
1892    if (argb_visual)
1893       return argb_visual;
1894 
1895    xvit.screen = Dpy.screen;
1896    xvit.depth = 32;
1897 #if __cplusplus
1898    xvit.c_class = TrueColor;
1899 #else
1900    xvit.class = TrueColor;
1901 #endif
1902 
1903    xvi = XGetVisualInfo(disp,
1904 			VisualScreenMask | VisualDepthMask | VisualClassMask,
1905 			&xvit, &num);
1906    if (!xvi)
1907       return NULL;
1908 
1909    for (i = 0; i < num; i++)
1910      {
1911 	if (EVisualIsARGB(xvi[i].visual))
1912 	   break;
1913      }
1914 
1915    vis = (i < num) ? xvi[i].visual : NULL;
1916 
1917    XFree(xvi);
1918 
1919    argb_visual = vis;
1920    argb_cmap = XCreateColormap(disp, WinGetXwin(VROOT), vis, AllocNone);
1921 
1922    return vis;
1923 }
1924 
1925 int
EVisualIsARGB(Visual * vis)1926 EVisualIsARGB(Visual * vis)
1927 {
1928    XRenderPictFormat  *pictfmt;
1929 
1930    pictfmt = XRenderFindVisualFormat(disp, vis);
1931    if (!pictfmt)
1932       return 0;
1933 
1934 #if 0
1935    Eprintf("Visual ID=%#lx Type=%d, alphamask=%d\n", vis->visualid,
1936 	   pictfmt->type, pictfmt->direct.alphaMask);
1937 #endif
1938    return pictfmt->type == PictTypeDirect && pictfmt->direct.alphaMask;
1939 }
1940 
1941 #endif /* USE_XRENDER */
1942 
1943 /*
1944  * Misc
1945  */
1946 
1947 EX_Time
EGetTimestamp(void)1948 EGetTimestamp(void)
1949 {
1950    static EX_Window    win_ts = NoXID;
1951    XSetWindowAttributes attr;
1952    XEvent              ev;
1953 
1954    if (win_ts == NoXID)
1955      {
1956 	attr.override_redirect = False;
1957 	win_ts = XCreateWindow(disp, WinGetXwin(VROOT), -100, -100, 1, 1, 0,
1958 			       CopyFromParent, InputOnly, CopyFromParent,
1959 			       CWOverrideRedirect, &attr);
1960 	XSelectInput(disp, win_ts, PropertyChangeMask);
1961      }
1962 
1963    XChangeProperty(disp, win_ts, XA_WM_NAME, XA_STRING, 8,
1964 		   PropModeAppend, (unsigned char *)"", 0);
1965    XWindowEvent(disp, win_ts, PropertyChangeMask, &ev);
1966 
1967    return ev.xproperty.time;
1968 }
1969 
1970 #if USE_COMPOSITE
1971 
1972 #include <X11/extensions/Xcomposite.h>
1973 
1974 EX_Pixmap
EWindowGetPixmap(const Win win)1975 EWindowGetPixmap(const Win win)
1976 {
1977    XWindowAttributes   xwa;
1978 
1979    if (EXGetWindowAttributes(win->xwin, &xwa) == 0 ||
1980        xwa.map_state == IsUnmapped)
1981       return NoXID;
1982 
1983    return XCompositeNameWindowPixmap(disp, WinGetXwin(win));
1984 }
1985 
1986 #endif /* USE_COMPOSITE */
1987 
1988 #if USE_XRENDER
1989 
1990 /*
1991  * Pictures
1992  */
1993 #define _R(x) (((x) >> 16) & 0xff)
1994 #define _G(x) (((x) >>  8) & 0xff)
1995 #define _B(x) (((x)      ) & 0xff)
1996 
1997 EX_Picture
EPictureCreate(Win win,EX_Drawable draw)1998 EPictureCreate(Win win, EX_Drawable draw)
1999 {
2000    EX_Picture          pict;
2001    XRenderPictFormat  *pictfmt;
2002 
2003    if (!win)
2004       win = VROOT;
2005    pictfmt = XRenderFindVisualFormat(disp, WinGetVisual(win));
2006    pict = XRenderCreatePicture(disp, draw, pictfmt, 0, NULL);
2007 
2008    return pict;
2009 }
2010 
2011 EX_Picture
EPictureCreateII(Win win,EX_Drawable draw)2012 EPictureCreateII(Win win, EX_Drawable draw)
2013 {
2014    EX_Picture          pict;
2015    XRenderPictFormat  *pictfmt;
2016    XRenderPictureAttributes pa;
2017 
2018    pictfmt = XRenderFindVisualFormat(disp, WinGetVisual(win));
2019    pa.subwindow_mode = IncludeInferiors;
2020    pict = XRenderCreatePicture(disp, draw, pictfmt, CPSubwindowMode, &pa);
2021 
2022    return pict;
2023 }
2024 
2025 EX_Picture
EPictureCreateSolid(EX_Window xwin,int argb,unsigned int a,unsigned int rgb)2026 EPictureCreateSolid(EX_Window xwin, int argb, unsigned int a, unsigned int rgb)
2027 {
2028    Display            *dpy = disp;
2029    XRenderColor        c;
2030    EX_Picture          pict;
2031 
2032    c.alpha = (unsigned short)(a * 0x101);
2033    c.red = (unsigned short)(_R(rgb) * 0x101);
2034    c.green = (unsigned short)(_G(rgb) * 0x101);
2035    c.blue = (unsigned short)(_B(rgb) * 0x101);
2036 
2037 #if RENDER_VERSION >= VERS(0, 11)
2038    /* Version 0.10 should be good but apparently sometimes isn't
2039     * (or is it some broken driver?).
2040     * Anyway, let's require 0.11 and avoid some trouble. */
2041    if (ExtVersion(XEXT_RENDER) >= VERS(0, 11))
2042      {
2043 	pict = XRenderCreateSolidFill(dpy, &c);
2044      }
2045    else
2046 #endif
2047      {
2048 	EX_Pixmap           pmap;
2049 	XRenderPictFormat  *pictfmt;
2050 	XRenderPictureAttributes pa;
2051 
2052 	pmap = XCreatePixmap(dpy, xwin, 1, 1, argb ? 32 : 8);
2053 	pictfmt = XRenderFindStandardFormat(dpy,
2054 					    argb ? PictStandardARGB32 :
2055 					    PictStandardA8);
2056 	pa.repeat = True;
2057 	pict = XRenderCreatePicture(dpy, pmap, pictfmt, CPRepeat, &pa);
2058 	XRenderFillRectangle(dpy, PictOpSrc, pict, &c, 0, 0, 1, 1);
2059 	XFreePixmap(dpy, pmap);
2060      }
2061 
2062    return pict;
2063 }
2064 
2065 EX_Picture
EPictureCreateBuffer(Win win,int w,int h,int argb,EX_Pixmap * ppmap)2066 EPictureCreateBuffer(Win win, int w, int h, int argb, EX_Pixmap * ppmap)
2067 {
2068    EX_Picture          pict;
2069    EX_Pixmap           pmap;
2070    XRenderPictFormat  *pictfmt;
2071    int                 depth;
2072 
2073    depth = argb ? 32 : WinGetDepth(win);
2074    pictfmt = argb ?
2075       XRenderFindStandardFormat(disp, PictStandardARGB32) :
2076       XRenderFindVisualFormat(disp, WinGetVisual(win));
2077    pmap = XCreatePixmap(disp, WinGetXwin(win), w, h, depth);
2078    pict = XRenderCreatePicture(disp, pmap, pictfmt, 0, NULL);
2079    if (ppmap)
2080       *ppmap = pmap;
2081    else
2082       XFreePixmap(disp, pmap);
2083 
2084    return pict;
2085 }
2086 
2087 void
EPictureDestroy(EX_Picture pict)2088 EPictureDestroy(EX_Picture pict)
2089 {
2090    XRenderFreePicture(disp, pict);
2091 }
2092 
2093 void
EPictureFillRect(EX_Picture pict,int x,int y,int w,int h,unsigned int color)2094 EPictureFillRect(EX_Picture pict, int x, int y, int w, int h,
2095 		 unsigned int color)
2096 {
2097    XRenderColor        c;
2098 
2099    COLOR32_TO_ARGB16(color, c.alpha, c.red, c.green, c.blue);
2100    XRenderFillRectangle(disp, PictOpSrc, pict, &c, x, y, w, h);
2101 }
2102 
2103 #endif /* USE_XRENDER */
2104 
2105 #if USE_COMPOSITE
2106 
2107 void
EGCSetClip(GC gc,EX_SrvRegion clip)2108 EGCSetClip(GC gc, EX_SrvRegion clip)
2109 {
2110    XFixesSetGCClipRegion(disp, gc, 0, 0, clip);
2111 }
2112 
2113 void
EPictureSetClip(EX_Picture pict,EX_SrvRegion clip)2114 EPictureSetClip(EX_Picture pict, EX_SrvRegion clip)
2115 {
2116    XFixesSetPictureClipRegion(disp, pict, 0, 0, clip);
2117 }
2118 
2119 /*
2120  * Regions
2121  */
2122 #define DEBUG_REGIONS 0
2123 
2124 #if DEBUG_REGIONS
2125 static int          n_rgn_c = 0;
2126 static int          n_rgn_d = 0;
2127 #endif
2128 
2129 EX_SrvRegion
ERegionCreate(void)2130 ERegionCreate(void)
2131 {
2132    EX_SrvRegion        rgn;
2133 
2134    rgn = XFixesCreateRegion(disp, NULL, 0);
2135 
2136 #if DEBUG_REGIONS
2137    n_rgn_c++;
2138    Eprintf("%s: %#x %d %d %d\n", __func__, rgn,
2139 	   n_rgn_c - n_rgn_d, n_rgn_c, n_rgn_d);
2140 #endif
2141    return rgn;
2142 }
2143 
2144 EX_SrvRegion
ERegionCreateRect(int x,int y,int w,int h)2145 ERegionCreateRect(int x, int y, int w, int h)
2146 {
2147    EX_SrvRegion        rgn;
2148    XRectangle          rct;
2149 
2150    rct.x = x;
2151    rct.y = y;
2152    rct.width = w;
2153    rct.height = h;
2154    rgn = XFixesCreateRegion(disp, &rct, 1);
2155 
2156 #if DEBUG_REGIONS
2157    n_rgn_c++;
2158    Eprintf("%s: %#x %d %d %d\n", __func__, rgn,
2159 	   n_rgn_c - n_rgn_d, n_rgn_c, n_rgn_d);
2160 #endif
2161    return rgn;
2162 }
2163 
2164 #if USE_DESK_EXPOSE
2165 EX_SrvRegion
ERegionCreateFromRects(XRectangle * rectangles,int nrectangles)2166 ERegionCreateFromRects(XRectangle * rectangles, int nrectangles)
2167 {
2168    EX_SrvRegion        rgn;
2169 
2170    rgn = XFixesCreateRegion(disp, rectangles, nrectangles);
2171 
2172 #if DEBUG_REGIONS
2173    n_rgn_c++;
2174    Eprintf("%s: %#x %d %d %d\n", __func__, rgn,
2175 	   n_rgn_c - n_rgn_d, n_rgn_c, n_rgn_d);
2176 #endif
2177    return rgn;
2178 }
2179 #endif
2180 
2181 EX_SrvRegion
ERegionCreateFromWindow(Win win)2182 ERegionCreateFromWindow(Win win)
2183 {
2184    EX_SrvRegion        rgn;
2185 
2186    rgn =
2187       XFixesCreateRegionFromWindow(disp, WinGetXwin(win), WindowRegionBounding);
2188 
2189 #if DEBUG_REGIONS
2190    n_rgn_c++;
2191    Eprintf("%s: %#x %d %d %d\n", __func__, rgn,
2192 	   n_rgn_c - n_rgn_d, n_rgn_c, n_rgn_d);
2193 #endif
2194    return rgn;
2195 }
2196 
2197 EX_SrvRegion
ERegionCreateFromBitmap(EX_Pixmap mask)2198 ERegionCreateFromBitmap(EX_Pixmap mask)
2199 {
2200    return XFixesCreateRegionFromBitmap(disp, mask);
2201 }
2202 
2203 EX_SrvRegion
ERegionCopy(EX_SrvRegion rgn,EX_SrvRegion src)2204 ERegionCopy(EX_SrvRegion rgn, EX_SrvRegion src)
2205 {
2206    XFixesCopyRegion(disp, rgn, src);
2207    return rgn;
2208 }
2209 
2210 EX_SrvRegion
ERegionClone(EX_SrvRegion src)2211 ERegionClone(EX_SrvRegion src)
2212 {
2213    EX_SrvRegion        rgn;
2214 
2215    rgn = ERegionCreate();
2216    ERegionCopy(rgn, src);
2217 
2218    return rgn;
2219 }
2220 
2221 void
ERegionDestroy(EX_SrvRegion rgn)2222 ERegionDestroy(EX_SrvRegion rgn)
2223 {
2224 #if DEBUG_REGIONS
2225    n_rgn_d++;
2226    Eprintf("%s: %#x %d %d %d\n", __func__, rgn,
2227 	   n_rgn_c - n_rgn_d, n_rgn_c, n_rgn_d);
2228 #endif
2229    XFixesDestroyRegion(disp, rgn);
2230 }
2231 
2232 void
ERegionEmpty(EX_SrvRegion rgn)2233 ERegionEmpty(EX_SrvRegion rgn)
2234 {
2235    XFixesSetRegion(disp, rgn, NULL, 0);
2236 }
2237 
2238 void
ERegionSetRect(EX_SrvRegion rgn,int x,int y,int w,int h)2239 ERegionSetRect(EX_SrvRegion rgn, int x, int y, int w, int h)
2240 {
2241    XRectangle          rct;
2242 
2243    rct.x = x;
2244    rct.y = y;
2245    rct.width = w;
2246    rct.height = h;
2247    XFixesSetRegion(disp, rgn, &rct, 1);
2248 }
2249 
2250 void
ERegionTranslate(EX_SrvRegion rgn,int dx,int dy)2251 ERegionTranslate(EX_SrvRegion rgn, int dx, int dy)
2252 {
2253    if (dx == 0 && dy == 0)
2254       return;
2255    XFixesTranslateRegion(disp, rgn, dx, dy);
2256 }
2257 
2258 void
ERegionIntersect(EX_SrvRegion dst,EX_SrvRegion src)2259 ERegionIntersect(EX_SrvRegion dst, EX_SrvRegion src)
2260 {
2261    XFixesIntersectRegion(disp, dst, dst, src);
2262 }
2263 
2264 void
ERegionUnion(EX_SrvRegion dst,EX_SrvRegion src)2265 ERegionUnion(EX_SrvRegion dst, EX_SrvRegion src)
2266 {
2267    XFixesUnionRegion(disp, dst, dst, src);
2268 }
2269 
2270 void
ERegionSubtract(EX_SrvRegion dst,EX_SrvRegion src)2271 ERegionSubtract(EX_SrvRegion dst, EX_SrvRegion src)
2272 {
2273    XFixesSubtractRegion(disp, dst, dst, src);
2274 }
2275 
2276 void
ERegionIntersectOffset(EX_SrvRegion dst,int dx,int dy,EX_SrvRegion src,EX_SrvRegion tmp)2277 ERegionIntersectOffset(EX_SrvRegion dst, int dx, int dy, EX_SrvRegion src,
2278 		       EX_SrvRegion tmp)
2279 {
2280    Display            *dpy = disp;
2281    EX_SrvRegion        rgn;
2282 
2283    rgn = src;
2284    if (dx != 0 || dy != 0)
2285      {
2286 	rgn = ERegionCopy(tmp, src);
2287 	XFixesTranslateRegion(dpy, rgn, dx, dy);
2288      }
2289    XFixesIntersectRegion(dpy, dst, dst, rgn);
2290 }
2291 
2292 void
ERegionSubtractOffset(EX_SrvRegion dst,int dx,int dy,EX_SrvRegion src,EX_SrvRegion tmp)2293 ERegionSubtractOffset(EX_SrvRegion dst, int dx, int dy, EX_SrvRegion src,
2294 		      EX_SrvRegion tmp)
2295 {
2296    Display            *dpy = disp;
2297    EX_SrvRegion        rgn;
2298 
2299    rgn = src;
2300    if (dx != 0 || dy != 0)
2301      {
2302 	rgn = ERegionCopy(tmp, src);
2303 	XFixesTranslateRegion(dpy, rgn, dx, dy);
2304      }
2305    XFixesSubtractRegion(dpy, dst, dst, rgn);
2306 }
2307 
2308 #if 0				/* Unused */
2309 void
2310 ERegionUnionOffset(EX_SrvRegion dst, int dx, int dy, EX_SrvRegion src,
2311 		   EX_SrvRegion tmp)
2312 {
2313    Display            *dpy = disp;
2314    EX_SrvRegion        rgn;
2315 
2316    rgn = src;
2317    if (dx != 0 || dy != 0)
2318      {
2319 	rgn = ERegionCopy(tmp, src);
2320 	XFixesTranslateRegion(dpy, rgn, dx, dy);
2321      }
2322    XFixesUnionRegion(dpy, dst, dst, rgn);
2323 }
2324 #endif
2325 
2326 #if 0				/* Unused (for debug) */
2327 int
2328 ERegionIsEmpty(EX_SrvRegion rgn)
2329 {
2330    int                 nr;
2331    XRectangle         *pr;
2332 
2333    pr = XFixesFetchRegion(disp, rgn, &nr);
2334    if (pr)
2335       XFree(pr);
2336    return nr == 0;
2337 }
2338 #endif
2339 
2340 void
ERegionShow(const char * txt,EX_SrvRegion rgn,void (* prf)(const char * fmt,...))2341 ERegionShow(const char *txt, EX_SrvRegion rgn,
2342 	    void (*prf)(const char *fmt, ...))
2343 {
2344    int                 i, nr;
2345    XRectangle         *pr;
2346 
2347    prf = (prf) ? prf : Eprintf;
2348 
2349    if (rgn == NoXID)
2350      {
2351 	prf(" - region: %s %#x is None\n", txt, rgn);
2352 	return;
2353      }
2354 
2355    pr = XFixesFetchRegion(disp, rgn, &nr);
2356    if (!pr || nr <= 0)
2357      {
2358 	prf(" - region: %s %#x is empty\n", txt, rgn);
2359 	goto done;
2360      }
2361 
2362    prf(" - region: %s %#x:\n", txt, rgn);
2363    for (i = 0; i < nr; i++)
2364       prf("%4d: %4d+%4d %4dx%4d\n", i, pr[i].x, pr[i].y, pr[i].width,
2365 	  pr[i].height);
2366 
2367  done:
2368    if (pr)
2369       XFree(pr);
2370 }
2371 
2372 #endif /* USE_COMPOSITE */
2373