chiark / gitweb /
Imported Upstream version 1.0.0
[e16] / src / x.c
1 /*
2  * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors
3  * Copyright (C) 2004-2008 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 #define DECLARE_WIN 1
25 #include "E.h"
26 #include "edebug.h"
27 #include "util.h"
28 #include "xwin.h"
29 #include <string.h>
30 #include <unistd.h>
31 #ifdef USE_ECORE_X
32 #include <Ecore_X.h>
33 #endif
34 #include <X11/Xatom.h>
35 #include <X11/Xutil.h>
36 #include <X11/Xresource.h>
37 #include <X11/extensions/shape.h>
38 #if USE_COMPOSITE
39 #include <X11/extensions/Xrender.h>
40 #endif
41 #if USE_GLX
42 #include "eglx.h"
43 #endif
44
45 #define DEBUG_XWIN   0
46 #define DEBUG_PIXMAP 0
47
48 EDisplay            Dpy;
49
50 #if USE_COMPOSITE
51 static Visual      *argb_visual = NULL;
52 static Colormap     argb_cmap = None;
53 #endif
54
55 static XContext     xid_context = 0;
56
57 static Win          win_first = NULL;
58 static Win          win_last = NULL;
59
60 #define WinBgInvalidate(win) if (win->bg_owned > 0) win->bg_owned = -1
61
62 #if !EXPOSE_WIN
63 Window
64 WinGetXwin(const Win win)
65 {
66    return win->xwin;
67 }
68
69 int
70 WinGetX(const Win win)
71 {
72    return win->x;
73 }
74
75 int
76 WinGetY(const Win win)
77 {
78    return win->y;
79 }
80
81 int
82 WinGetW(const Win win)
83 {
84    return win->w;
85 }
86
87 int
88 WinGetH(const Win win)
89 {
90    return win->h;
91 }
92
93 int
94 WinGetBorderWidth(const Win win)
95 {
96    return win->bw;
97 }
98
99 int
100 WinGetDepth(const Win win)
101 {
102    return win->depth;
103 }
104
105 Visual             *
106 WinGetVisual(const Win win)
107 {
108    return win->visual;
109 }
110
111 Colormap
112 WinGetCmap(const Win win)
113 {
114    return win->cmap;
115 }
116 #endif
117
118 void
119 EXInit(void)
120 {
121    memset(&Dpy, 0, sizeof(Dpy));
122 }
123
124 static              Win
125 EXidCreate(void)
126 {
127    Win                 win;
128
129    win = ECALLOC(struct _xwin, 1);
130
131    win->bgcol = 0xffffffff;
132
133    return win;
134 }
135
136 static void
137 EXidDestroy(Win win)
138 {
139 #if DEBUG_XWIN
140    Eprintf("EXidDestroy: %p %#lx\n", win, win->xwin);
141 #endif
142    if (win->rects)
143       XFree(win->rects);
144    Efree(win->cbl.lst);
145    Efree(win);
146 }
147
148 static void
149 EXidAdd(Win win)
150 {
151 #if DEBUG_XWIN
152    Eprintf("EXidAdd: %p %#lx\n", win, win->xwin);
153 #endif
154    if (!xid_context)
155       xid_context = XUniqueContext();
156
157    XSaveContext(disp, win->xwin, xid_context, (XPointer) win);
158
159    if (!win_first)
160      {
161         win_first = win_last = win;
162      }
163    else
164      {
165         win->prev = win_last;
166         win_last->next = win;
167         win_last = win;
168      }
169 }
170
171 static void
172 EXidDel(Win win)
173 {
174 #if DEBUG_XWIN
175    Eprintf("EXidDel: %p %#lx\n", win, win->xwin);
176 #endif
177    if (win == win_first)
178      {
179         if (win == win_last)
180           {
181              win_first = win_last = NULL;
182           }
183         else
184           {
185              win_first = win->next;
186              win->next->prev = NULL;
187           }
188      }
189    else if (win == win_last)
190      {
191         win_last = win->prev;
192         win->prev->next = NULL;
193      }
194    else
195      {
196         win->prev->next = win->next;
197         win->next->prev = win->prev;
198      }
199
200    XDeleteContext(disp, win->xwin, xid_context);
201    if (win->in_use)
202       win->do_del = 1;
203    else
204       EXidDestroy(win);
205 }
206
207 #define EXidLookup ELookupXwin
208
209 Win
210 EXidLookup(Window xwin)
211 {
212    Win                 win;
213    XPointer            xp;
214
215    if (!xid_context)
216       return NULL;
217
218    xp = NULL;
219    if (XFindContext(disp, xwin, xid_context, &xp) == XCNOENT)
220       xp = NULL;
221    win = (Win) xp;
222
223    return win;
224 }
225
226 static              Win
227 EXidSet(Window xwin, Win parent, int x, int y, int w, int h, int depth,
228         Visual * visual, Colormap cmap)
229 {
230    Win                 win;
231
232    win = EXidCreate();
233    win->parent = parent;
234    win->xwin = xwin;
235    win->x = x;
236    win->y = y;
237    win->w = w;
238    win->h = h;
239    win->depth = depth;
240    win->visual = visual;
241    win->cmap = cmap;
242 #if DEBUG_XWIN
243    Eprintf("EXidSet: %#lx\n", win->xwin);
244 #endif
245    EXidAdd(win);
246
247    return win;
248 }
249
250 void
251 EventCallbackRegister(Win win, int type __UNUSED__, EventCallbackFunc * func,
252                       void *prm)
253 {
254    EventCallbackItem  *eci;
255
256    if (!win)
257       return;
258 #if 0
259    Eprintf("EventCallbackRegister: %p %#lx: func=%p prm=%p\n", win, win->xwin,
260            func, prm);
261 #endif
262
263    win->cbl.num++;
264    win->cbl.lst = EREALLOC(EventCallbackItem, win->cbl.lst, win->cbl.num);
265    eci = win->cbl.lst + win->cbl.num - 1;
266    eci->func = func;
267    eci->prm = prm;
268 }
269
270 void
271 EventCallbackUnregister(Win win, int type __UNUSED__,
272                         EventCallbackFunc * func, void *prm)
273 {
274    EventCallbackList  *ecl;
275    EventCallbackItem  *eci;
276    int                 i;
277
278    if (!win)
279       return;
280 #if 0
281    Eprintf("EventCallbackUnregister: %p %#lx: func=%p prm=%p\n", win, win->xwin,
282            func, prm);
283 #endif
284
285    ecl = &win->cbl;
286    eci = ecl->lst;
287    for (i = 0; i < ecl->num; i++, eci++)
288       if (eci->func == func && eci->prm == prm)
289         {
290            ecl->num--;
291            if (ecl->num)
292              {
293                 for (; i < ecl->num; i++, eci++)
294                    *eci = *(eci + 1);
295                 win->cbl.lst =
296                    EREALLOC(EventCallbackItem, win->cbl.lst, ecl->num);
297              }
298            else
299              {
300                 Efree(win->cbl.lst);
301                 win->cbl.lst = NULL;
302              }
303            return;
304         }
305 }
306
307 void
308 EventCallbacksProcess(Win win, XEvent * ev)
309 {
310    EventCallbackList  *ecl;
311    EventCallbackItem  *eci;
312    int                 i;
313
314    if (!win)
315       return;
316
317    win->in_use = 1;
318    ecl = &win->cbl;
319    eci = ecl->lst;
320    for (i = 0; i < ecl->num; i++, eci++)
321      {
322         if (EDebug(EDBUG_TYPE_DISPATCH))
323            Eprintf("EventDispatch: type=%d win=%#lx func=%p prm=%p\n",
324                    ev->type, ev->xany.window, eci->func, eci->prm);
325         eci->func(win, ev, eci->prm);
326         if (win->do_del)
327           {
328              EXidDestroy(win);
329              return;
330           }
331      }
332    win->in_use = 0;
333 }
334
335 Win
336 ECreateWindow(Win parent, int x, int y, int w, int h, int saveunder)
337 {
338    Win                 win;
339    Window              xwin;
340    XSetWindowAttributes attr;
341
342    attr.backing_store = NotUseful;
343    attr.override_redirect = False;
344    attr.colormap = parent->cmap;
345    attr.border_pixel = 0;
346 /*   attr.background_pixel = 0; */
347    attr.background_pixmap = None;
348    if ((saveunder == 1) && (Conf.save_under))
349       attr.save_under = True;
350    else if (saveunder == 2)
351       attr.save_under = True;
352    else
353       attr.save_under = False;
354
355    xwin = XCreateWindow(disp, parent->xwin, x, y, w, h, 0,
356                         CopyFromParent, InputOutput, CopyFromParent,
357                         CWOverrideRedirect | CWSaveUnder | CWBackingStore |
358                         CWColormap | CWBackPixmap | CWBorderPixel, &attr);
359    win = EXidSet(xwin, parent, x, y, w, h, parent->depth, parent->visual,
360                  parent->cmap);
361
362    return win;
363 }
364
365 #if USE_COMPOSITE
366 static              Win
367 ECreateWindowVDC(Win parent, int x, int y, int w, int h,
368                  Visual * vis, unsigned int depth, Colormap cmap)
369 {
370    Win                 win;
371    Window              xwin;
372    XSetWindowAttributes attr;
373
374    attr.background_pixmap = None;
375    attr.border_pixel = 0;
376    attr.backing_store = NotUseful;
377    attr.save_under = False;
378    attr.override_redirect = False;
379    attr.colormap = cmap;
380
381    xwin = XCreateWindow(disp, parent->xwin, x, y, w, h, 0,
382                         depth, InputOutput, vis,
383                         CWOverrideRedirect | CWSaveUnder | CWBackingStore |
384                         CWColormap | CWBackPixmap | CWBorderPixel, &attr);
385    win = EXidSet(xwin, parent, x, y, w, h, depth, vis, cmap);
386
387    return win;
388 }
389
390 Win
391 ECreateArgbWindow(Win parent, int x, int y, int w, int h, Win cwin)
392 {
393    int                 depth;
394    Visual             *vis;
395    Colormap            cmap;
396
397    if (cwin && Conf.testing.argb_clients_inherit_attr)
398      {
399         depth = cwin->depth;
400         vis = cwin->visual;
401         cmap = cwin->cmap;
402      }
403    else
404      {
405         if (!argb_visual)
406           {
407              argb_visual = EVisualFindARGB();
408              argb_cmap =
409                 XCreateColormap(disp, WinGetXwin(VROOT), argb_visual,
410                                 AllocNone);
411           }
412         depth = 32;
413         vis = argb_visual;
414         cmap = argb_cmap;
415      }
416
417    return ECreateWindowVDC(parent, x, y, w, h, vis, depth, cmap);
418 }
419
420 #if USE_GLX
421 Win
422 ECreateWindowVD(Win parent, int x, int y, int w, int h,
423                 Visual * vis, unsigned int depth)
424 {
425    Colormap            cmap;
426
427    if (!vis || depth == 0)
428       return 0;
429
430    cmap = XCreateColormap(disp, WinGetXwin(VROOT), vis, AllocNone);
431
432    return ECreateWindowVDC(parent, x, y, w, h, vis, depth, cmap);
433 }
434 #endif
435
436 #endif /* USE_COMPOSITE */
437
438 Win
439 ECreateObjectWindow(Win parent, int x, int y, int w, int h, int saveunder,
440                     int type, Win cwin)
441 {
442    Win                 win;
443
444 #if USE_COMPOSITE
445    int                 argb = 0;
446
447    switch (type)
448      {
449      default:
450      case WIN_TYPE_NO_ARGB:
451         break;
452      case WIN_TYPE_CLIENT:
453         if (Conf.testing.argb_clients || EVisualIsARGB(cwin->visual))
454            argb = 1;
455         break;
456      case WIN_TYPE_INTERNAL:
457         if (Conf.testing.argb_internal_objects)
458            argb = 1;
459         break;
460 #if USE_GLX
461      case WIN_TYPE_GLX: /* Internal GL */
462         argb = 1;
463         win =
464            ECreateWindowVD(parent, x, y, w, h, EGlGetVisual(), EGlGetDepth());
465         if (win)
466            win->argb = 1;
467         return win;
468 #endif
469      }
470
471    if (argb)
472       win = ECreateArgbWindow(parent, x, y, w, h, cwin);
473    else
474       win = ECreateWindow(parent, x, y, w, h, saveunder);
475    win->argb = argb;
476 #else
477    win = ECreateWindow(parent, x, y, w, h, saveunder);
478    type = 0;
479    cwin = NULL;
480 #endif
481
482    return win;
483 }
484
485 Win
486 ECreateClientWindow(Win parent, int x, int y, int w, int h)
487 {
488 #if USE_COMPOSITE
489    if (Conf.testing.argb_internal_clients)
490       return ECreateArgbWindow(parent, x, y, w, h, NULL);
491 #endif
492
493    return ECreateWindow(parent, x, y, w, h, 0);
494 }
495
496 Win
497 ECreateEventWindow(Win parent, int x, int y, int w, int h)
498 {
499    Win                 win;
500    Window              xwin;
501    XSetWindowAttributes attr;
502
503    attr.override_redirect = False;
504
505    xwin = XCreateWindow(disp, parent->xwin, x, y, w, h, 0, 0, InputOnly,
506                         CopyFromParent, CWOverrideRedirect, &attr);
507    win = EXidSet(xwin, parent, x, y, w, h, 0, NULL, None);
508
509    return win;
510 }
511
512 #if 0                           /* Not used */
513 /*
514  * create a window which will accept the keyboard focus when no other 
515  * windows have it
516  */
517 Win
518 ECreateFocusWindow(Win parent, int x, int y, int w, int h)
519 {
520    Win                 win;
521    XSetWindowAttributes attr;
522
523    attr.backing_store = NotUseful;
524    attr.override_redirect = False;
525    attr.colormap = WinGetCmap(VROOT);
526    attr.border_pixel = 0;
527    attr.background_pixel = 0;
528    attr.save_under = False;
529    attr.event_mask = KeyPressMask | FocusChangeMask;
530
531    Window              xwin, xpar;
532
533    win = XCreateWindow(disp, parent, x, y, w, h, 0, 0, InputOnly,
534                        CopyFromParent,
535                        CWOverrideRedirect | CWSaveUnder | CWBackingStore |
536                        CWColormap | CWBackPixel | CWBorderPixel | CWEventMask,
537                        &attr);
538
539    XSetWindowBackground(disp, win, 0);
540    XMapWindow(disp, win);
541    XSetInputFocus(disp, win, RevertToParent, CurrentTime);
542
543    return win;
544 }
545 #endif
546
547 void
548 EMoveWindow(Win win, int x, int y)
549 {
550    if (!win)
551       return;
552
553 #if 0
554    Eprintf("EMoveWindow: %p %#lx: %d,%d %dx%d -> %d,%d\n",
555            win, win->xwin, win->x, win->y, win->w, win->h, x, y);
556 #endif
557    if ((x == win->x) && (y == win->y))
558       return;
559
560    win->x = x;
561    win->y = y;
562
563    XMoveWindow(disp, win->xwin, x, y);
564 }
565
566 void
567 EResizeWindow(Win win, int w, int h)
568 {
569    if (!win)
570       return;
571
572    if ((w == win->w) && (h == win->h))
573       return;
574
575    WinBgInvalidate(win);
576    win->w = w;
577    win->h = h;
578
579    XResizeWindow(disp, win->xwin, w, h);
580 }
581
582 void
583 EMoveResizeWindow(Win win, int x, int y, int w, int h)
584 {
585    if (!win)
586       return;
587
588 #if 0
589    Eprintf("EMoveResizeWindow: %p %#lx: %d,%d %dx%d -> %d,%d %dx%d\n",
590            win, win->xwin, win->x, win->y, win->w, win->h, x, y, w, h);
591 #endif
592    if ((w == win->w) && (h == win->h) && (x == win->x) && (y == win->y))
593       return;
594
595    if (w != win->w || h != win->h)
596       WinBgInvalidate(win);
597
598    win->x = x;
599    win->y = y;
600    win->w = w;
601    win->h = h;
602
603    XMoveResizeWindow(disp, win->xwin, x, y, w, h);
604 }
605
606 static int
607 ExDelTree(Win win)
608 {
609    Win                 win2;
610    int                 nsub;
611
612    win->do_del = -1;
613
614    nsub = 0;
615    for (win2 = win_first; win2; win2 = win2->next)
616      {
617         if (win2->parent != win)
618            continue;
619         ExDelTree(win2);
620         nsub++;
621      }
622
623    return nsub;
624 }
625
626 void
627 EDestroyWindow(Win win)
628 {
629    Win                 next;
630    int                 nsub;
631
632    if (!win)
633       return;
634
635 #if DEBUG_XWIN
636    Eprintf("ExDestroyWindow: %p %#lx\n", win, win->xwin);
637 #endif
638    if (win->parent != None)
639      {
640         EFreeWindowBackgroundPixmap(win);
641         XDestroyWindow(disp, win->xwin);
642      }
643
644    /* Mark the ones to be deleted */
645    nsub = ExDelTree(win);
646    if (nsub == 0)
647      {
648         /* No children */
649         EXidDel(win);
650         return;
651      }
652
653    /* Delete entire tree */
654    for (win = win_first; win; win = next)
655      {
656         next = win->next;
657         if (win->do_del < 0)
658            EXidDel(win);
659      }
660 }
661
662 void
663 EWindowSync(Win win)
664 {
665    Window              rr;
666    int                 x, y;
667    unsigned int        w, h, bw, depth;
668
669    if (!win)
670       return;
671
672    XGetGeometry(disp, win->xwin, &rr, &x, &y, &w, &h, &bw, &depth);
673 #if 0
674    Eprintf("EWindowSync: %p %#lx: %d,%d %dx%d -> %d,%d %dx%d\n",
675            win, win->xwin, win->x, win->y, win->w, win->h, x, y, w, h);
676 #endif
677    win->x = x;
678    win->y = y;
679    win->w = w;
680    win->h = h;
681    win->depth = depth;
682 }
683
684 void
685 EWindowSetGeometry(Win win, int x, int y, int w, int h, int bw)
686 {
687    if (!win)
688       return;
689
690    win->x = x;
691    win->y = y;
692    win->w = w;
693    win->h = h;
694    win->bw = bw;
695 }
696
697 void
698 EWindowSetMapped(Win win, int mapped)
699 {
700    if (!win)
701       return;
702
703    win->mapped = mapped;
704 }
705
706 Window
707 EXWindowGetParent(Window xwin)
708 {
709    Window              parent, rt;
710    Window             *pch = NULL;
711    unsigned int        nch = 0;
712
713    parent = None;
714    if (!XQueryTree(disp, xwin, &rt, &parent, &pch, &nch))
715       parent = None;
716    else if (pch)
717       XFree(pch);
718
719 #if 0                           /* FIXME - Remove? */
720    win = EXidLookup(xwin);
721    if (win)
722       win->parent = parent;
723 #endif
724
725    return parent;
726 }
727
728 Win
729 ECreateWinFromXwin(Window xwin)
730 {
731    Win                 win;
732    Window              rr;
733    int                 x, y;
734    unsigned int        w, h, bw, depth;
735
736    if (!XGetGeometry(disp, xwin, &rr, &x, &y, &w, &h, &bw, &depth))
737       return NULL;
738
739    win = EXidCreate();
740    if (!win)
741       return NULL;
742
743    win->xwin = xwin;
744    win->x = x;
745    win->y = y;
746    win->w = w;
747    win->h = h;
748    win->depth = depth;
749    win->visual = WinGetVisual(VROOT);
750    win->cmap = WinGetCmap(VROOT);
751
752    return win;
753 }
754
755 void
756 EDestroyWin(Win win)
757 {
758    EXidDestroy(win);
759 }
760
761 Win
762 ERegisterWindow(Window xwin, XWindowAttributes * pxwa)
763 {
764    Win                 win;
765    XWindowAttributes   xwa;
766
767    win = EXidLookup(xwin);
768    if (win)
769       goto done;
770
771    if (!pxwa)
772      {
773         pxwa = &xwa;
774         if (!XGetWindowAttributes(disp, xwin, pxwa))
775            goto done;
776      }
777
778 #if 0
779    Eprintf("ERegisterWindow %#lx %d+%d %dx%d\n", win, x, y, w, h);
780 #endif
781    win = EXidSet(xwin, None, pxwa->x, pxwa->y, pxwa->width, pxwa->height,
782                  pxwa->depth, pxwa->visual, pxwa->colormap);
783    win->mapped = pxwa->map_state != IsUnmapped;
784    win->attached = 1;
785
786  done:
787    return win;
788 }
789
790 void
791 EUnregisterXwin(Window xwin)
792 {
793    Win                 win;
794
795    win = EXidLookup(xwin);
796    if (!win)
797       return;
798
799    /* FIXME - We shouldn't go here */
800    EXidDel(win);
801 #if 1                           /* Debug - Fix code if we get here */
802    Eprintf("*** FIXME - EUnregisterXwin %#lx\n", xwin);
803 #endif
804 }
805
806 void
807 EUnregisterWindow(Win win)
808 {
809    if (!win)
810       return;
811
812    if (win->cbl.lst)
813      {
814         if (EDebug(1))
815            Eprintf("EUnregisterWindow(%#lx) Ignored (%d callbacks remain)\n",
816                    win->xwin, win->cbl.num);
817         return;
818      }
819
820    EXidDel(win);
821 }
822
823 void
824 EMapWindow(Win win)
825 {
826    if (!win)
827       return;
828
829    if (win->mapped)
830       return;
831    win->mapped = 1;
832
833    XMapWindow(disp, win->xwin);
834 }
835
836 void
837 EUnmapWindow(Win win)
838 {
839    if (!win)
840       return;
841
842    if (!win->mapped)
843       return;
844    win->mapped = 0;
845
846    XUnmapWindow(disp, win->xwin);
847 }
848
849 void
850 EReparentWindow(Win win, Win parent, int x, int y)
851 {
852    if (!win)
853       return;
854
855 #if 0
856    Eprintf
857       ("EReparentWindow: %p %#lx: %d %#lx->%#lx %d,%d %dx%d -> %d,%d\n",
858        win, win->xwin, win->mapped, win->parent, parent->xwin,
859        win->x, win->y, win->w, win->h, x, y);
860 #endif
861    if (parent == win->parent)
862      {
863         if ((x != win->x) || (y != win->y))
864           {
865              win->x = x;
866              win->y = y;
867              XMoveWindow(disp, win->xwin, x, y);
868           }
869         return;
870      }
871    else
872      {
873         win->parent = parent;
874         win->x = x;
875         win->y = y;
876      }
877
878    XReparentWindow(disp, win->xwin, parent->xwin, x, y);
879 }
880
881 void
882 EMapRaised(Win win)
883 {
884    if (!win)
885       return;
886
887    if (win->mapped)
888      {
889         XRaiseWindow(disp, win->xwin);
890         return;
891      }
892    else
893      {
894         win->mapped = 1;
895      }
896
897    XMapRaised(disp, win->xwin);
898 }
899
900 int
901 EXGetGeometry(Drawable draw, Window * root_return, int *x, int *y,
902               int *w, int *h, int *bw, int *depth)
903 {
904    int                 ok;
905    Window              rr;
906    int                 xx, yy;
907    unsigned int        ww, hh, bb, dd;
908
909    ok = XGetGeometry(disp, draw, &rr, &xx, &yy, &ww, &hh, &bb, &dd);
910    if (!ok)
911       goto done;
912
913    if (root_return)
914       *root_return = rr;
915    if (x)
916       *x = xx;
917    if (y)
918       *y = yy;
919    if (w)
920       *w = ww;
921    if (h)
922       *h = hh;
923    if (bw)
924       *bw = bb;
925    if (depth)
926       *depth = dd;
927
928  done:
929 #if 0                           /* Debug */
930    if (!ok)
931       Eprintf("EGetGeometry win=%#x, error %d\n", (unsigned)win, ok);
932 #endif
933    return ok;
934 }
935
936 int
937 EGetGeometry(Win win, Window * root_return, int *x, int *y,
938              int *w, int *h, int *bw, int *depth)
939 {
940    if (!win)
941       return 0;
942
943    if (x)
944       *x = win->x;
945    if (y)
946       *y = win->y;
947    if (w)
948       *w = win->w;
949    if (h)
950       *h = win->h;
951    if (bw)
952       *bw = 0;
953    if (depth)
954       *depth = win->depth;
955    if (root_return)
956       *root_return = WinGetXwin(VROOT);
957
958    return 1;
959 }
960
961 void
962 EGetWindowAttributes(Win win, XWindowAttributes * pxwa)
963 {
964    if (!win)
965       return;
966
967    pxwa->x = win->x;
968    pxwa->y = win->y;
969    pxwa->width = win->w;
970    pxwa->height = win->h;
971    pxwa->border_width = win->bw;
972    pxwa->depth = win->depth;
973    pxwa->visual = win->visual;
974    pxwa->colormap = win->cmap;
975 }
976
977 #if 0                           /* Unused */
978 void
979 EConfigureWindow(Win win, unsigned int mask, XWindowChanges * wc)
980 {
981    char                doit = 0;
982
983    if (!win)
984       return;
985
986    if ((mask & CWX) && (wc->x != win->x))
987      {
988         win->x = wc->x;
989         doit = 1;
990      }
991    if ((mask & CWY) && (wc->y != win->y))
992      {
993         win->y = wc->y;
994         doit = 1;
995      }
996    if ((mask & CWWidth) && (wc->width != win->w))
997      {
998         WinBgInvalidate(win);
999         win->w = wc->width;
1000         doit = 1;
1001      }
1002    if ((mask & CWHeight) && (wc->height != win->h))
1003      {
1004         WinBgInvalidate(win);
1005         win->h = wc->height;
1006         doit = 1;
1007      }
1008
1009    if ((doit) || (mask & (CWBorderWidth | CWSibling | CWStackMode)))
1010       XConfigureWindow(disp, win->xwin, mask, wc);
1011 }
1012 #endif
1013
1014 void
1015 ESetWindowBackgroundPixmap(Win win, Pixmap pmap)
1016 {
1017    if (!win)
1018       return;
1019
1020    if (win->bgpmap && win->bg_owned)
1021       EFreeWindowBackgroundPixmap(win);
1022    win->bgpmap = pmap;
1023    win->bg_owned = 0;           /* Don't manage pixmap */
1024    win->bgcol = 0xffffffff;     /* Hmmm.. */
1025
1026    XSetWindowBackgroundPixmap(disp, win->xwin, pmap);
1027 }
1028
1029 Pixmap
1030 EGetWindowBackgroundPixmap(Win win)
1031 {
1032    Pixmap              pmap;
1033
1034    if (!win)
1035       return None;
1036
1037    if (win->bg_owned < 0)       /* Free if invalidated */
1038       EFreeWindowBackgroundPixmap(win);
1039    else if (win->bgpmap)
1040       return win->bgpmap;
1041
1042    /* Allocate/set new */
1043    pmap = ECreatePixmap(win, win->w, win->h, 0);
1044    ESetWindowBackgroundPixmap(win, pmap);
1045    win->bg_owned = 1;           /* Manage pixmap */
1046
1047    return pmap;
1048 }
1049
1050 void
1051 EFreeWindowBackgroundPixmap(Win win)
1052 {
1053    if (!win || !win->bgpmap)
1054       return;
1055
1056    if (win->bg_owned)
1057       EFreePixmap(win->bgpmap);
1058    win->bgpmap = 0;
1059    win->bg_owned = 0;
1060 }
1061
1062 void
1063 ESetWindowBackground(Win win, unsigned int col)
1064 {
1065    if (!win)
1066       return;
1067
1068    if (win->bgpmap)
1069      {
1070         EFreeWindowBackgroundPixmap(win);
1071         win->bgcol = col;
1072      }
1073    else if (win->bgcol != col)
1074      {
1075         win->bgcol = col;
1076      }
1077    else
1078       return;
1079
1080    XSetWindowBackground(disp, win->xwin, col);
1081 }
1082
1083 void
1084 ESelectInput(Win win, unsigned int event_mask)
1085 {
1086    XSelectInput(disp, win->xwin, event_mask);
1087 }
1088
1089 void
1090 EChangeWindowAttributes(Win win, unsigned int mask, XSetWindowAttributes * attr)
1091 {
1092    XChangeWindowAttributes(disp, win->xwin, mask, attr);
1093 }
1094
1095 void
1096 ESetWindowBorderWidth(Win win, unsigned int bw)
1097 {
1098    XSetWindowBorderWidth(disp, win->xwin, bw);
1099 }
1100
1101 void
1102 ERaiseWindow(Win win)
1103 {
1104    XRaiseWindow(disp, win->xwin);
1105 }
1106
1107 void
1108 ELowerWindow(Win win)
1109 {
1110    XLowerWindow(disp, win->xwin);
1111 }
1112
1113 void
1114 EXRestackWindows(Window * windows, int nwindows)
1115 {
1116    XRestackWindows(disp, windows, nwindows);
1117 }
1118
1119 void
1120 EClearWindow(Win win)
1121 {
1122    XClearWindow(disp, win->xwin);
1123 }
1124
1125 void
1126 EClearArea(Win win, int x, int y, unsigned int w, unsigned int h)
1127 {
1128    XClearArea(disp, win->xwin, x, y, w, h, False);
1129 }
1130
1131 int
1132 ETranslateCoordinates(Win src_w, Win dst_w, int src_x, int src_y,
1133                       int *dest_x_return, int *dest_y_return,
1134                       Window * child_return)
1135 {
1136    Window              child;
1137
1138    if (!child_return)
1139       child_return = &child;
1140
1141    return XTranslateCoordinates(disp, src_w->xwin, dst_w->xwin, src_x, src_y,
1142                                 dest_x_return, dest_y_return, child_return);
1143 }
1144
1145 void
1146 EXWarpPointer(Window xwin, int x, int y)
1147 {
1148    XWarpPointer(disp, None, xwin, 0, 0, 0, 0, x, y);
1149 }
1150
1151 static              Bool
1152 EXQueryPointer(Window xwin, int *px, int *py, Window * pchild,
1153                unsigned int *pmask)
1154 {
1155    Window              root, child;
1156    int                 root_x, root_y;
1157    unsigned int        mask;
1158
1159    if (xwin == None)
1160       xwin = WinGetXwin(VROOT);
1161
1162    if (!px)
1163       px = &root_x;
1164    if (!py)
1165       py = &root_y;
1166    if (!pchild)
1167       pchild = &child;
1168    if (!pmask)
1169       pmask = &mask;
1170
1171    return XQueryPointer(disp, xwin, &root, pchild, &root_x, &root_y, px, py,
1172                         pmask);
1173 }
1174
1175 Bool
1176 EQueryPointer(Win win, int *px, int *py, Window * pchild, unsigned int *pmask)
1177 {
1178    Window              xwin;
1179
1180    xwin = (win) ? win->xwin : WinGetXwin(VROOT);
1181
1182    return EXQueryPointer(xwin, px, py, pchild, pmask);
1183 }
1184
1185 void
1186 ESelectInputChange(Win win, unsigned long set, unsigned long clear)
1187 {
1188    XWindowAttributes   xwa;
1189
1190    XGetWindowAttributes(disp, win->xwin, &xwa);
1191    xwa.your_event_mask |= set;
1192    xwa.your_event_mask &= ~clear;
1193    XSelectInput(disp, win->xwin, xwa.your_event_mask);
1194 }
1195
1196 int
1197 EDrawableCheck(Drawable draw, int grab)
1198 {
1199    int                 ok;
1200
1201    if (draw == None)
1202       return 0;
1203
1204    if (grab)
1205       EGrabServer();
1206
1207    ok = EXGetGeometry(draw, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1208
1209    if (grab && !ok)
1210       EUngrabServer();
1211
1212    return ok;
1213 }
1214
1215 KeyCode
1216 EKeysymToKeycode(KeySym keysym)
1217 {
1218    return XKeysymToKeycode(disp, keysym);
1219 }
1220
1221 KeyCode
1222 EKeynameToKeycode(const char *name)
1223 {
1224    return XKeysymToKeycode(disp, XStringToKeysym(name));
1225 }
1226
1227 const char         *
1228 EKeycodeToString(KeyCode keycode, int ix)
1229 {
1230    return XKeysymToString(XKeycodeToKeysym(disp, keycode, ix));
1231 }
1232
1233 Atom
1234 EInternAtom(const char *name)
1235 {
1236    return XInternAtom(disp, name, False);
1237 }
1238
1239 #define DEBUG_SHAPE_OPS 0
1240 #define DEBUG_SHAPE_PROPAGATE 0
1241
1242 #if DEBUG_SHAPE_OPS || DEBUG_SHAPE_PROPAGATE
1243 static void
1244 EShapeShow(const char *txt, Window xwin, XRectangle * pr, int nr)
1245 {
1246    int                 i;
1247
1248    Eprintf("%s %#lx nr=%d\n", txt, xwin, nr);
1249    for (i = 0; i < nr; i++)
1250       Eprintf(" %d - %4d,%4d %4dx%4d\n", i,
1251               pr[i].x, pr[i].y, pr[i].width, pr[i].height);
1252 }
1253 #endif
1254
1255 static void
1256 EShapeUpdate(Win win)
1257 {
1258    if (win->rects)
1259      {
1260         XFree(win->rects);
1261         win->num_rect = 0;
1262      }
1263
1264    win->rects =
1265       XShapeGetRectangles(disp, win->xwin, ShapeBounding, &(win->num_rect),
1266                           &(win->ord));
1267    if (win->rects)
1268      {
1269         if (win->num_rect == 1)
1270           {
1271              if ((win->rects[0].x == 0) && (win->rects[0].y == 0)
1272                  && (win->rects[0].width == win->w)
1273                  && (win->rects[0].height == win->h))
1274                {
1275                   win->num_rect = 0;
1276                   XFree(win->rects);
1277                   win->rects = NULL;
1278                   XShapeCombineMask(disp, win->xwin, ShapeBounding, 0, 0,
1279                                     None, ShapeSet);
1280                }
1281           }
1282         else if (win->num_rect > 4096)
1283           {
1284              Eprintf("*** EShapeUpdate: nrect=%d - Not likely, ignoring.\n",
1285                      win->num_rect);
1286              XShapeCombineMask(disp, win->xwin, ShapeBounding, 0, 0, None,
1287                                ShapeSet);
1288              win->num_rect = 0;
1289              XFree(win->rects);
1290              win->rects = NULL;
1291           }
1292      }
1293    else
1294      {
1295         win->num_rect = -1;
1296      }
1297 #if DEBUG_SHAPE_OPS
1298    EShapeShow("EShapeUpdate", win->xwin, win->rects, win->num_rect);
1299 #endif
1300 }
1301
1302 static void
1303 EShapeCombineMask(Win win, int dest, int x, int y, Pixmap pmap, int op)
1304 {
1305    char                wasshaped = 0;
1306
1307    if (!win)
1308       return;
1309
1310    if (win->rects || win->num_rect < 0)
1311      {
1312         win->num_rect = 0;
1313         if (win->rects)
1314            XFree(win->rects);
1315         win->rects = NULL;
1316         wasshaped = 1;
1317      }
1318 #if DEBUG_SHAPE_OPS
1319    Eprintf("EShapeCombineMask %#lx %d,%d %dx%d mask=%#lx wassh=%d\n",
1320            win->xwin, win->x, win->y, win->w, win->h, pmap, wasshaped);
1321 #endif
1322    if (pmap)
1323      {
1324         XShapeCombineMask(disp, win->xwin, dest, x, y, pmap, op);
1325         EShapeUpdate(win);
1326      }
1327    else if (wasshaped)
1328       XShapeCombineMask(disp, win->xwin, dest, x, y, pmap, op);
1329 }
1330
1331 static void
1332 EShapeCombineMaskTiled(Win win, int dest, int x, int y,
1333                        Pixmap pmap, int op, int w, int h)
1334 {
1335    XGCValues           gcv;
1336    GC                  gc;
1337    Window              tm;
1338
1339    gcv.fill_style = FillTiled;
1340    gcv.tile = pmap;
1341    gcv.ts_x_origin = 0;
1342    gcv.ts_y_origin = 0;
1343    tm = ECreatePixmap(win, w, h, 1);
1344    gc = EXCreateGC(tm, GCFillStyle | GCTile |
1345                    GCTileStipXOrigin | GCTileStipYOrigin, &gcv);
1346    XFillRectangle(disp, tm, gc, 0, 0, w, h);
1347    EXFreeGC(gc);
1348    EShapeCombineMask(win, dest, x, y, tm, op);
1349    EFreePixmap(tm);
1350 }
1351
1352 static void
1353 EShapeCombineRectangles(Win win, int dest, int x, int y,
1354                         XRectangle * rect, int n_rects, int op, int ordering)
1355 {
1356    if (!win)
1357       return;
1358 #if DEBUG_SHAPE_OPS
1359    Eprintf("EShapeCombineRectangles %#lx %d\n", win->xwin, n_rects);
1360 #endif
1361
1362    if (n_rects == 1 && op == ShapeSet)
1363      {
1364         if ((rect[0].x == 0) && (rect[0].y == 0) &&
1365             (rect[0].width == win->w) && (rect[0].height == win->h))
1366           {
1367              win->num_rect = 0;
1368              XFree(win->rects);
1369              win->rects = NULL;
1370              XShapeCombineMask(disp, win->xwin, dest, x, y, None, op);
1371              return;
1372           }
1373      }
1374    XShapeCombineRectangles(disp, win->xwin, dest, x, y, rect, n_rects, op,
1375                            ordering);
1376    if (n_rects > 1)
1377      {
1378         /* Limit shape to window extents */
1379         XRectangle          r;
1380
1381         r.x = r.y = 0;
1382         r.width = win->w;
1383         r.height = win->h;
1384         XShapeCombineRectangles(disp, win->xwin, ShapeBounding, 0, 0, &r,
1385                                 1, ShapeIntersect, Unsorted);
1386      }
1387    EShapeUpdate(win);
1388 }
1389
1390 static void
1391 EShapeCombineShape(Win win, int dest, int x, int y,
1392                    Win src_win, int src_kind, int op)
1393 {
1394    if (!win)
1395       return;
1396
1397    XShapeCombineShape(disp, win->xwin, dest, x, y, src_win->xwin, src_kind, op);
1398    EShapeUpdate(win);
1399 }
1400
1401 int
1402 EShapePropagate(Win win)
1403 {
1404    Win                 xch;
1405    unsigned int        num_rects;
1406    int                 k, rn;
1407    int                 x, y, w, h;
1408    XRectangle         *rects, *rectsn, *rl;
1409
1410    if (!win || win->w <= 0 || win->h <= 0)
1411       return 0;
1412
1413 #if DEBUG_SHAPE_PROPAGATE
1414    Eprintf("EShapePropagate %#lx %d,%d %dx%d\n", win->xwin,
1415            win->x, win->y, win->w, win->h);
1416 #endif
1417
1418    num_rects = 0;
1419    rects = NULL;
1420
1421    /* go through all child windows and create/inset spans */
1422    for (xch = win_first; xch; xch = xch->next)
1423      {
1424         if (xch->parent != win)
1425            continue;
1426
1427 #if DEBUG_SHAPE_PROPAGATE > 1
1428         Eprintf("%#lx(%d): %4d,%4d %4dx%4d\n", xch->xwin, xch->mapped,
1429                 xch->x, xch->y, xch->w, xch->h);
1430 #endif
1431         if (!xch->mapped)
1432            continue;
1433
1434         x = xch->x;
1435         y = xch->y;
1436         w = xch->w;
1437         h = xch->h;
1438         if (x >= win->w || y >= win->h || x + w < 0 || y + h < 0)
1439            continue;
1440
1441         rn = xch->num_rect;
1442
1443         if (rn > 0)
1444           {
1445              rl = xch->rects;
1446              rectsn = EREALLOC(XRectangle, rects, num_rects + rn);
1447              if (!rectsn)
1448                 goto bail_out;
1449              rects = rectsn;
1450
1451              /* go through all clip rects in thsi window's shape */
1452              for (k = 0; k < rn; k++)
1453                {
1454                   /* for each clip rect, add it to the rect list */
1455                   rects[num_rects + k].x = x + rl[k].x;
1456                   rects[num_rects + k].y = y + rl[k].y;
1457                   rects[num_rects + k].width = rl[k].width;
1458                   rects[num_rects + k].height = rl[k].height;
1459 #if DEBUG_SHAPE_PROPAGATE > 1
1460                   Eprintf(" - %d: %4d,%4d %4dx%4d\n", k,
1461                           rects[num_rects + k].x,
1462                           rects[num_rects + k].y, rects[num_rects + k].width,
1463                           rects[num_rects + k].height);
1464 #endif
1465                }
1466              num_rects += rn;
1467           }
1468         else if (rn == 0)
1469           {
1470              /* Unshaped */
1471              rectsn = EREALLOC(XRectangle, rects, num_rects + 1);
1472              if (!rectsn)
1473                 goto bail_out;
1474              rects = rectsn;
1475
1476              rects[num_rects].x = x;
1477              rects[num_rects].y = y;
1478              rects[num_rects].width = w;
1479              rects[num_rects].height = h;
1480              num_rects++;
1481           }
1482      }
1483
1484 #if DEBUG_SHAPE_PROPAGATE
1485    EShapeShow("EShapePropagate", win->xwin, rects, num_rects);
1486 #endif
1487
1488    /* set the rects as the shape mask */
1489    if (rects)
1490      {
1491         EShapeCombineRectangles(win, ShapeBounding, 0, 0, rects,
1492                                 num_rects, ShapeSet, Unsorted);
1493         Efree(rects);
1494      }
1495    else
1496      {
1497         /* Empty shape */
1498         EShapeCombineRectangles(win, ShapeBounding, 0, 0, NULL, 0, ShapeSet,
1499                                 Unsorted);
1500      }
1501
1502    return win->num_rect;
1503
1504  bail_out:
1505    Efree(rects);
1506    EShapeCombineMask(win, ShapeBounding, 0, 0, None, ShapeSet);
1507    return 0;
1508 }
1509
1510 int
1511 EShapeCheck(Win win)
1512 {
1513    if (!win)
1514       return 0;
1515
1516    return win->num_rect;
1517 }
1518
1519 void
1520 EShapeSetMask(Win win, int x, int y, Pixmap mask)
1521 {
1522    EShapeCombineMask(win, ShapeBounding, x, y, mask, ShapeSet);
1523 }
1524
1525 void
1526 EShapeUnionMask(Win win, int x, int y, Pixmap mask)
1527 {
1528    EShapeCombineMask(win, ShapeBounding, x, y, mask, ShapeUnion);
1529 }
1530
1531 void
1532 EShapeSetMaskTiled(Win win, int x, int y, Pixmap mask, int w, int h)
1533 {
1534    EShapeCombineMaskTiled(win, ShapeBounding, x, y, mask, ShapeSet, w, h);
1535 }
1536
1537 void
1538 EShapeSetRects(Win win, int x, int y, XRectangle * rect, int n_rects)
1539 {
1540    EShapeCombineRectangles(win, ShapeBounding, x, y, rect, n_rects,
1541                            ShapeSet, Unsorted);
1542 }
1543
1544 void
1545 EShapeUnionRects(Win win, int x, int y, XRectangle * rect, int n_rects)
1546 {
1547    EShapeCombineRectangles(win, ShapeBounding, x, y, rect, n_rects,
1548                            ShapeUnion, Unsorted);
1549 }
1550
1551 int
1552 EShapeSetShape(Win win, int x, int y, Win src_win)
1553 {
1554    EShapeCombineShape(win, ShapeBounding, x, y,
1555                       src_win, ShapeBounding, ShapeSet);
1556    return win->num_rect != 0;
1557 }
1558
1559 /* Build mask from window shape rects */
1560 Pixmap
1561 EWindowGetShapePixmap(Win win)
1562 {
1563    Pixmap              mask;
1564    GC                  gc;
1565    int                 i;
1566    const XRectangle   *rect;
1567
1568    if (win->num_rect == 0)      /* Not shaped */
1569       return None;
1570
1571    mask = ECreatePixmap(win, win->w, win->h, 1);
1572    gc = EXCreateGC(mask, 0, NULL);
1573
1574    XSetForeground(disp, gc, 0);
1575    XFillRectangle(disp, mask, gc, 0, 0, win->w, win->h);
1576
1577    XSetForeground(disp, gc, 1);
1578    rect = win->rects;
1579    for (i = 0; i < win->num_rect; i++)
1580       XFillRectangle(disp, mask, gc, rect[i].x, rect[i].y,
1581                      rect[i].width, rect[i].height);
1582
1583    EXFreeGC(gc);
1584
1585    return mask;
1586 }
1587
1588 Pixmap
1589 ECreatePixmap(Win win, unsigned int width, unsigned int height,
1590               unsigned int depth)
1591 {
1592    Pixmap              pmap;
1593
1594    if (depth == 0)
1595       depth = win->depth;
1596
1597    pmap = XCreatePixmap(disp, win->xwin, width, height, depth);
1598 #if DEBUG_PIXMAP
1599    Eprintf("%s: %#lx\n", __func__, pmap);
1600 #endif
1601    return pmap;
1602 }
1603
1604 void
1605 EFreePixmap(Pixmap pmap)
1606 {
1607 #if DEBUG_PIXMAP
1608    Eprintf("%s: %#lx\n", __func__, pmap);
1609 #endif
1610    XFreePixmap(disp, pmap);
1611 }
1612
1613 Pixmap
1614 EXCreatePixmapCopy(Pixmap src, unsigned int w, unsigned int h,
1615                    unsigned int depth)
1616 {
1617    Pixmap              pmap;
1618    GC                  gc;
1619
1620    pmap = XCreatePixmap(disp, src, w, h, depth);
1621    gc = EXCreateGC(src, 0, NULL);
1622    XCopyArea(disp, src, pmap, gc, 0, 0, w, h, 0, 0);
1623    EXFreeGC(gc);
1624 #if DEBUG_PIXMAP
1625    Eprintf("%s: %#lx\n", __func__, pmap);
1626 #endif
1627    return pmap;
1628 }
1629
1630 void
1631 EXCopyArea(Drawable src, Drawable dst, int sx, int sy, unsigned int w,
1632            unsigned int h, int dx, int dy)
1633 {
1634    GC                  gc;
1635
1636    gc = EXCreateGC(src, 0, NULL);
1637    XCopyArea(disp, src, dst, gc, sx, sy, w, h, dx, dy);
1638    EXFreeGC(gc);
1639 }
1640
1641 void
1642 EXCopyAreaTiled(Drawable src, Pixmap mask, Drawable dst, int sx, int sy,
1643                 unsigned int w, unsigned int h, int dx, int dy)
1644 {
1645    GC                  gc;
1646    XGCValues           gcv;
1647
1648    gcv.fill_style = FillTiled;
1649    gcv.tile = src;
1650    gcv.ts_x_origin = sx;
1651    gcv.ts_y_origin = sy;
1652    gcv.clip_mask = mask;
1653    gc = EXCreateGC(dst, GCFillStyle |
1654                    GCTile | GCTileStipXOrigin | GCTileStipYOrigin | GCClipMask,
1655                    &gcv);
1656    XFillRectangle(disp, dst, gc, dx, dy, w, h);
1657    EXFreeGC(gc);
1658 }
1659
1660 GC
1661 EXCreateGC(Drawable draw, unsigned long mask, XGCValues * val)
1662 {
1663    XGCValues           xgcv;
1664
1665    if (val)
1666      {
1667         mask |= GCGraphicsExposures;
1668         val->graphics_exposures = False;
1669      }
1670    else
1671      {
1672         mask = GCGraphicsExposures;
1673         val = &xgcv;
1674         val->graphics_exposures = False;
1675      }
1676    return XCreateGC(disp, draw, mask, val);
1677 }
1678
1679 int
1680 EXFreeGC(GC gc)
1681 {
1682    return XFreeGC(disp, gc);
1683 }
1684
1685 void
1686 EXSendEvent(Window xwin, long event_mask, XEvent * ev)
1687 {
1688    XSendEvent(disp, xwin, False, event_mask, ev);
1689 }
1690
1691 void
1692 EAllocColor(Colormap cmap, EColor * pec)
1693 {
1694    XColor              xc;
1695
1696    EAllocXColor(cmap, &xc, pec);
1697    pec->pixel = xc.pixel;
1698 }
1699
1700 void
1701 EAllocXColor(Colormap cmap, XColor * pxc, EColor * pec)
1702 {
1703    pxc->red = pec->red << 8;
1704    pxc->green = pec->green << 8;
1705    pxc->blue = pec->blue << 8;
1706    XAllocColor(disp, cmap, pxc);
1707 }
1708
1709 /*
1710  * Display
1711  */
1712
1713 int
1714 EDisplayOpen(const char *dstr, int scr)
1715 {
1716    char                dbuf[256], *s;
1717
1718    if (scr >= 0)
1719      {
1720         /* Override screen */
1721         Esnprintf(dbuf, sizeof(dbuf) - 10, "%s", dstr);
1722         s = strchr(dbuf, ':');
1723         if (s)
1724           {
1725              s = strchr(s, '.');
1726              if (s)
1727                 *s = '\0';
1728           }
1729         Esnprintf(dbuf + strlen(dbuf), 10, ".%d", scr);
1730         dstr = dbuf;
1731      }
1732
1733 #ifdef USE_ECORE_X
1734    ecore_x_init(dstr);
1735    disp = ecore_x_display_get();
1736 #else
1737    disp = XOpenDisplay(dstr);
1738 #endif
1739
1740    return (disp) ? 0 : -1;
1741 }
1742
1743 void
1744 EDisplayClose(void)
1745 {
1746    if (!disp)
1747       return;
1748 #ifdef USE_ECORE_X
1749    ecore_x_shutdown();
1750 #else
1751    XCloseDisplay(disp);
1752 #endif
1753    XSetErrorHandler(NULL);
1754    XSetIOErrorHandler(NULL);
1755    disp = NULL;
1756 }
1757
1758 void
1759 EDisplayDisconnect(void)
1760 {
1761    if (!disp)
1762       return;
1763 #ifdef USE_ECORE_X
1764    ecore_x_disconnect();
1765 #else
1766    close(ConnectionNumber(disp));
1767 #endif
1768    XSetErrorHandler(NULL);
1769    XSetIOErrorHandler(NULL);
1770
1771    disp = NULL;
1772 }
1773
1774 static int
1775 HandleXError(Display * dpy, XErrorEvent * ev)
1776 {
1777    char                buf[64];
1778
1779    if (EDebug(1))
1780      {
1781         XGetErrorText(dpy, ev->error_code, buf, 63);
1782         Eprintf("*** ERROR: xid=%#lx error=%i req=%i/%i: %s\n",
1783                 ev->resourceid, ev->error_code,
1784                 ev->request_code, ev->minor_code, buf);
1785      }
1786
1787    Dpy.last_error_code = ev->error_code;
1788
1789    return 0;
1790 }
1791
1792 static void         (*EXIOErrorFunc) (void) = NULL;
1793
1794 static int
1795 HandleXIOError(Display * dpy __UNUSED__)
1796 {
1797    disp = NULL;
1798
1799    if (EXIOErrorFunc)
1800       EXIOErrorFunc();
1801
1802    return 0;
1803 }
1804
1805 void
1806 EDisplaySetErrorHandlers(void (*fatal) (void))
1807 {
1808    /* set up an error handler for then E would normally have fatal X errors */
1809    XSetErrorHandler(HandleXError);
1810
1811    /* set up a handler for when the X Connection goes down */
1812    EXIOErrorFunc = fatal;
1813    XSetIOErrorHandler(HandleXIOError);
1814 }
1815
1816 /*
1817  * Server
1818  */
1819
1820 void
1821 EGrabServer(void)
1822 {
1823    if (Dpy.server_grabbed <= 0)
1824      {
1825         if (EDebug(EDBUG_TYPE_GRABS))
1826            Eprintf("EGrabServer\n");
1827         XGrabServer(disp);
1828      }
1829    Dpy.server_grabbed++;
1830 }
1831
1832 void
1833 EUngrabServer(void)
1834 {
1835    if (Dpy.server_grabbed == 1)
1836      {
1837         XUngrabServer(disp);
1838         XFlush(disp);
1839         if (EDebug(EDBUG_TYPE_GRABS))
1840            Eprintf("EUngrabServer\n");
1841      }
1842    Dpy.server_grabbed--;
1843    if (Dpy.server_grabbed < 0)
1844       Dpy.server_grabbed = 0;
1845 }
1846
1847 int
1848 EServerIsGrabbed(void)
1849 {
1850    return Dpy.server_grabbed;
1851 }
1852
1853 void
1854 EFlush(void)
1855 {
1856    XFlush(disp);
1857 }
1858
1859 void
1860 ESync(unsigned int mask)
1861 {
1862    if (mask & Conf.testing.no_sync_mask)
1863       return;
1864    XSync(disp, False);
1865 }
1866
1867 /*
1868  * Visuals
1869  */
1870
1871 #if USE_COMPOSITE
1872
1873 Visual             *
1874 EVisualFindARGB(void)
1875 {
1876    XVisualInfo        *xvi, xvit;
1877    int                 i, num;
1878    Visual             *vis;
1879
1880    xvit.screen = Dpy.screen;
1881    xvit.depth = 32;
1882 #if __cplusplus
1883    xvit.c_class = TrueColor;
1884 #else
1885    xvit.class = TrueColor;
1886 #endif
1887
1888    xvi = XGetVisualInfo(disp,
1889                         VisualScreenMask | VisualDepthMask | VisualClassMask,
1890                         &xvit, &num);
1891    if (!xvi)
1892       return NULL;
1893
1894    for (i = 0; i < num; i++)
1895      {
1896         if (EVisualIsARGB(xvi[i].visual))
1897            break;
1898      }
1899
1900    vis = (i < num) ? xvi[i].visual : NULL;
1901
1902    XFree(xvi);
1903
1904    return vis;
1905 }
1906
1907 int
1908 EVisualIsARGB(Visual * vis)
1909 {
1910    XRenderPictFormat  *pictfmt;
1911
1912    pictfmt = XRenderFindVisualFormat(disp, vis);
1913    if (!pictfmt)
1914       return 0;
1915
1916 #if 0
1917    Eprintf("Visual ID=%#lx Type=%d, alphamask=%d\n", vis->visualid,
1918            pictfmt->type, pictfmt->direct.alphaMask);
1919 #endif
1920    return pictfmt->type == PictTypeDirect && pictfmt->direct.alphaMask;
1921 }
1922
1923 #endif
1924
1925 /*
1926  * Misc
1927  */
1928
1929 Time
1930 EGetTimestamp(void)
1931 {
1932    static Window       win_ts = None;
1933    XSetWindowAttributes attr;
1934    XEvent              ev;
1935
1936    if (win_ts == None)
1937      {
1938         attr.override_redirect = False;
1939         win_ts = XCreateWindow(disp, WinGetXwin(VROOT), -100, -100, 1, 1, 0,
1940                                CopyFromParent, InputOnly, CopyFromParent,
1941                                CWOverrideRedirect, &attr);
1942         XSelectInput(disp, win_ts, PropertyChangeMask);
1943      }
1944
1945    XChangeProperty(disp, win_ts, XA_WM_NAME, XA_STRING, 8,
1946                    PropModeAppend, (unsigned char *)"", 0);
1947    XWindowEvent(disp, win_ts, PropertyChangeMask, &ev);
1948
1949    return ev.xproperty.time;
1950 }