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