e16/src/x.c

1844 lines
35 KiB
C

/*
* Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors
* Copyright (C) 2004-2007 Kim Woelders
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies of the Software, its documentation and marketing & publicity
* materials, and acknowledgment shall be given in the documentation, materials
* and software packages that this Software was used.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#define DECLARE_WIN 1
#include "E.h"
#ifdef USE_ECORE_X
#include <Ecore_X.h>
#endif
#include "xwin.h"
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#include <X11/Xresource.h>
#if USE_COMPOSITE
#include <X11/extensions/Xrender.h>
#endif
#if USE_GLX
#include "eglx.h"
#endif
#define DEBUG_XWIN 0
#define DEBUG_PIXMAP 0
#if USE_COMPOSITE
static Visual *argb_visual = NULL;
static Colormap argb_cmap = None;
#endif
static XContext xid_context = 0;
static Win win_first = NULL;
static Win win_last = NULL;
#define WinBgInvalidate(win) if (win->bg_owned > 0) win->bg_owned = -1
#if !EXPOSE_WIN
Window
WinGetXwin(const Win win)
{
return win->xwin;
}
int
WinGetX(const Win win)
{
return win->x;
}
int
WinGetY(const Win win)
{
return win->y;
}
int
WinGetW(const Win win)
{
return win->w;
}
int
WinGetH(const Win win)
{
return win->h;
}
int
WinGetBorderWidth(const Win win)
{
return win->bw;
}
int
WinGetDepth(const Win win)
{
return win->depth;
}
Visual *
WinGetVisual(const Win win)
{
return win->visual;
}
Colormap
WinGetCmap(const Win win)
{
return win->cmap;
}
#endif
static Win
EXidCreate(void)
{
Win win;
win = ECALLOC(struct _xwin, 1);
win->bgcol = 0xffffffff;
return win;
}
static void
EXidDestroy(Win win)
{
#if DEBUG_XWIN
Eprintf("EXidDestroy: %p %#lx\n", win, win->xwin);
#endif
if (win->rects)
XFree(win->rects);
if (win->cbl.lst)
Efree(win->cbl.lst);
Efree(win);
}
static void
EXidAdd(Win win)
{
#if DEBUG_XWIN
Eprintf("EXidAdd: %p %#lx\n", win, win->xwin);
#endif
if (!xid_context)
xid_context = XUniqueContext();
XSaveContext(disp, win->xwin, xid_context, (XPointer) win);
if (!win_first)
{
win_first = win_last = win;
}
else
{
win->prev = win_last;
win_last->next = win;
win_last = win;
}
}
static void
EXidDel(Win win)
{
#if DEBUG_XWIN
Eprintf("EXidDel: %p %#lx\n", win, win->xwin);
#endif
if (win == win_first)
{
if (win == win_last)
{
win_first = win_last = NULL;
}
else
{
win_first = win->next;
win->next->prev = NULL;
}
}
else if (win == win_last)
{
win_last = win->prev;
win->prev->next = NULL;
}
else
{
win->prev->next = win->next;
win->next->prev = win->prev;
}
XDeleteContext(disp, win->xwin, xid_context);
if (win->in_use)
win->do_del = 1;
else
EXidDestroy(win);
}
#define EXidLookup ELookupXwin
Win
EXidLookup(Window xwin)
{
Win win;
XPointer xp;
if (!xid_context)
return NULL;
xp = NULL;
if (XFindContext(disp, xwin, xid_context, &xp) == XCNOENT)
xp = NULL;
win = (Win) xp;
return win;
}
static Win
EXidSet(Window xwin, Win parent, int x, int y, int w, int h, int depth,
Visual * visual, Colormap cmap)
{
Win win;
win = EXidCreate();
win->parent = parent;
win->xwin = xwin;
win->x = x;
win->y = y;
win->w = w;
win->h = h;
win->depth = depth;
win->visual = visual;
win->cmap = cmap;
#if DEBUG_XWIN
Eprintf("EXidSet: %#lx\n", win->xwin);
#endif
EXidAdd(win);
return win;
}
void
EventCallbackRegister(Win win, int type __UNUSED__, EventCallbackFunc * func,
void *prm)
{
EventCallbackItem *eci;
if (!win)
return;
#if 0
Eprintf("EventCallbackRegister: %p %#lx\n", win, win->xwin);
#endif
win->cbl.num++;
win->cbl.lst = EREALLOC(EventCallbackItem, win->cbl.lst, win->cbl.num);
eci = win->cbl.lst + win->cbl.num - 1;
eci->func = func;
eci->prm = prm;
}
void
EventCallbackUnregister(Win win, int type __UNUSED__,
EventCallbackFunc * func, void *prm)
{
EventCallbackList *ecl;
EventCallbackItem *eci;
int i;
if (!win)
return;
#if 0
Eprintf("EventCallbackUnregister: %p %#lx\n", win, win->xwin);
#endif
ecl = &win->cbl;
eci = ecl->lst;
for (i = 0; i < ecl->num; i++, eci++)
if (eci->func == func && eci->prm == prm)
{
ecl->num--;
if (ecl->num)
{
for (; i < ecl->num; i++, eci++)
*eci = *(eci + 1);
win->cbl.lst =
EREALLOC(EventCallbackItem, win->cbl.lst, ecl->num);
}
else
{
Efree(win->cbl.lst);
win->cbl.lst = NULL;
}
return;
}
}
void
EventCallbacksProcess(Win win, XEvent * ev)
{
EventCallbackList *ecl;
EventCallbackItem *eci;
int i;
if (!win)
return;
win->in_use = 1;
ecl = &win->cbl;
eci = ecl->lst;
for (i = 0; i < ecl->num; i++, eci++)
{
if (EDebug(EDBUG_TYPE_DISPATCH))
Eprintf("EventDispatch: type=%d win=%#lx func=%p prm=%p\n",
ev->type, ev->xany.window, eci->func, eci->prm);
eci->func(win, ev, eci->prm);
if (win->do_del)
{
EXidDestroy(win);
return;
}
}
win->in_use = 0;
}
Win
ECreateWindow(Win parent, int x, int y, int w, int h, int saveunder)
{
Win win;
Window xwin;
XSetWindowAttributes attr;
attr.backing_store = NotUseful;
attr.override_redirect = False;
attr.colormap = parent->cmap;
attr.border_pixel = 0;
/* attr.background_pixel = 0; */
attr.background_pixmap = None;
if ((saveunder == 1) && (Conf.save_under))
attr.save_under = True;
else if (saveunder == 2)
attr.save_under = True;
else
attr.save_under = False;
xwin = XCreateWindow(disp, parent->xwin, x, y, w, h, 0,
CopyFromParent, InputOutput, CopyFromParent,
CWOverrideRedirect | CWSaveUnder | CWBackingStore |
CWColormap | CWBackPixmap | CWBorderPixel, &attr);
win = EXidSet(xwin, parent, x, y, w, h, parent->depth, parent->visual,
parent->cmap);
return win;
}
#if USE_COMPOSITE
static Win
ECreateWindowVDC(Win parent, int x, int y, int w, int h,
Visual * vis, unsigned int depth, Colormap cmap)
{
Win win;
Window xwin;
XSetWindowAttributes attr;
attr.background_pixmap = None;
attr.border_pixel = 0;
attr.backing_store = NotUseful;
attr.save_under = False;
attr.override_redirect = False;
attr.colormap = cmap;
xwin = XCreateWindow(disp, parent->xwin, x, y, w, h, 0,
depth, InputOutput, vis,
CWOverrideRedirect | CWSaveUnder | CWBackingStore |
CWColormap | CWBackPixmap | CWBorderPixel, &attr);
win = EXidSet(xwin, parent, x, y, w, h, depth, vis, cmap);
return win;
}
Win
ECreateArgbWindow(Win parent, int x, int y, int w, int h, Win cwin)
{
int depth;
Visual *vis;
Colormap cmap;
if (cwin && Conf.testing.argb_clients_inherit_attr)
{
depth = cwin->depth;
vis = cwin->visual;
cmap = cwin->cmap;
}
else
{
if (!argb_visual)
{
argb_visual = EVisualFindARGB();
argb_cmap =
XCreateColormap(disp, VRoot.xwin, argb_visual, AllocNone);
}
depth = 32;
vis = argb_visual;
cmap = argb_cmap;
}
return ECreateWindowVDC(parent, x, y, w, h, vis, depth, cmap);
}
#if USE_GLX
Win
ECreateWindowVD(Win parent, int x, int y, int w, int h,
Visual * vis, unsigned int depth)
{
Colormap cmap;
if (!vis || depth == 0)
return 0;
cmap = XCreateColormap(disp, VRoot.xwin, vis, AllocNone);
return ECreateWindowVDC(parent, x, y, w, h, vis, depth, cmap);
}
#endif
#endif /* USE_COMPOSITE */
Win
ECreateObjectWindow(Win parent, int x, int y, int w, int h, int saveunder,
int type, Win cwin)
{
Win win;
#if USE_COMPOSITE
int argb = 0;
switch (type)
{
case 0: /* Client window */
if (Conf.testing.argb_clients || EVisualIsARGB(cwin->visual))
argb = 1;
break;
default:
case 1: /* Internal */
if (Conf.testing.argb_internal_objects)
argb = 1;
break;
#if USE_GLX
case 2: /* Internal GL */
argb = 1;
win =
ECreateWindowVD(parent, x, y, w, h, EGlGetVisual(), EGlGetDepth());
if (win)
win->argb = 1;
return win;
#endif
}
if (argb)
win = ECreateArgbWindow(parent, x, y, w, h, cwin);
else
win = ECreateWindow(parent, x, y, w, h, saveunder);
win->argb = argb;
#else
win = ECreateWindow(parent, x, y, w, h, saveunder);
type = 0;
cwin = NULL;
#endif
return win;
}
Win
ECreateClientWindow(Win parent, int x, int y, int w, int h)
{
#if USE_COMPOSITE
if (Conf.testing.argb_internal_clients)
return ECreateArgbWindow(parent, x, y, w, h, NULL);
#endif
return ECreateWindow(parent, x, y, w, h, 0);
}
Win
ECreateEventWindow(Win parent, int x, int y, int w, int h)
{
Win win;
Window xwin;
XSetWindowAttributes attr;
attr.override_redirect = False;
xwin = XCreateWindow(disp, parent->xwin, x, y, w, h, 0, 0, InputOnly,
CopyFromParent, CWOverrideRedirect, &attr);
win = EXidSet(xwin, parent, x, y, w, h, 0, NULL, None);
return win;
}
#if 0 /* Not used */
/*
* create a window which will accept the keyboard focus when no other
* windows have it
*/
Win
ECreateFocusWindow(Win parent, int x, int y, int w, int h)
{
Win win;
XSetWindowAttributes attr;
attr.backing_store = NotUseful;
attr.override_redirect = False;
attr.colormap = VRoot.cmap;
attr.border_pixel = 0;
attr.background_pixel = 0;
attr.save_under = False;
attr.event_mask = KeyPressMask | FocusChangeMask;
Window xwin, xpar;
win = XCreateWindow(disp, parent, x, y, w, h, 0, 0, InputOnly,
CopyFromParent,
CWOverrideRedirect | CWSaveUnder | CWBackingStore |
CWColormap | CWBackPixel | CWBorderPixel | CWEventMask,
&attr);
XSetWindowBackground(disp, win, 0);
XMapWindow(disp, win);
XSetInputFocus(disp, win, RevertToParent, CurrentTime);
return win;
}
#endif
void
EMoveWindow(Win win, int x, int y)
{
if (!win)
return;
#if 0
Eprintf("EMoveWindow: %p %#lx: %d,%d %dx%d -> %d,%d\n",
win, win->xwin, win->x, win->y, win->w, win->h, x, y);
#endif
if ((x == win->x) && (y == win->y))
return;
win->x = x;
win->y = y;
XMoveWindow(disp, win->xwin, x, y);
}
void
EResizeWindow(Win win, int w, int h)
{
if (!win)
return;
if ((w == win->w) && (h == win->h))
return;
WinBgInvalidate(win);
win->w = w;
win->h = h;
XResizeWindow(disp, win->xwin, w, h);
}
void
EMoveResizeWindow(Win win, int x, int y, int w, int h)
{
if (!win)
return;
#if 0
Eprintf("EMoveResizeWindow: %p %#lx: %d,%d %dx%d -> %d,%d %dx%d\n",
win, win->xwin, win->x, win->y, win->w, win->h, x, y, w, h);
#endif
if ((w == win->w) && (h == win->h) && (x == win->x) && (y == win->y))
return;
if (w != win->w || h != win->h)
WinBgInvalidate(win);
win->x = x;
win->y = y;
win->w = w;
win->h = h;
XMoveResizeWindow(disp, win->xwin, x, y, w, h);
}
static int
ExDelTree(Win win)
{
Win win2;
int nsub;
win->do_del = -1;
nsub = 0;
for (win2 = win_first; win2; win2 = win2->next)
{
if (win2->parent != win)
continue;
ExDelTree(win2);
nsub++;
}
return nsub;
}
void
EDestroyWindow(Win win)
{
Win next;
int nsub;
if (!win)
return;
#if DEBUG_XWIN
Eprintf("ExDestroyWindow: %p %#lx\n", win, win->xwin);
#endif
if (win->parent != None)
{
EFreeWindowBackgroundPixmap(win);
XDestroyWindow(disp, win->xwin);
}
/* Mark the ones to be deleted */
nsub = ExDelTree(win);
if (nsub == 0)
{
/* No children */
EXidDel(win);
return;
}
/* Delete entire tree */
for (win = win_first; win; win = next)
{
next = win->next;
if (win->do_del < 0)
EXidDel(win);
}
}
void
EWindowSync(Win win)
{
Window rr;
int x, y;
unsigned int w, h, bw, depth;
if (!win)
return;
XGetGeometry(disp, win->xwin, &rr, &x, &y, &w, &h, &bw, &depth);
#if 0
Eprintf("EWindowSync: %p %#lx: %d,%d %dx%d -> %d,%d %dx%d\n",
win, win->xwin, win->x, win->y, win->w, win->h, x, y, w, h);
#endif
win->x = x;
win->y = y;
win->w = w;
win->h = h;
win->depth = depth;
}
void
EWindowSetGeometry(Win win, int x, int y, int w, int h, int bw)
{
if (!win)
return;
win->x = x;
win->y = y;
win->w = w;
win->h = h;
win->bw = bw;
}
void
EWindowSetMapped(Win win, int mapped)
{
if (!win)
return;
win->mapped = mapped;
}
Window
EXWindowGetParent(Window xwin)
{
Window parent, rt;
Window *pch = NULL;
unsigned int nch = 0;
parent = None;
if (!XQueryTree(disp, xwin, &rt, &parent, &pch, &nch))
parent = None;
else if (pch)
XFree(pch);
#if 0 /* FIXME - Remove? */
win = EXidLookup(xwin);
if (win)
win->parent = parent;
#endif
return parent;
}
Win
ECreateWinFromXwin(Window xwin)
{
Win win;
Window rr;
int x, y;
unsigned int w, h, bw, depth;
if (!XGetGeometry(disp, xwin, &rr, &x, &y, &w, &h, &bw, &depth))
return NULL;
win = EXidCreate();
if (!win)
return NULL;
win->xwin = xwin;
win->x = x;
win->y = y;
win->w = w;
win->h = h;
win->depth = depth;
win->visual = VRoot.vis;
win->cmap = VRoot.cmap;
return win;
}
void
EDestroyWin(Win win)
{
EXidDestroy(win);
}
Win
ERegisterWindow(Window xwin, XWindowAttributes * pxwa)
{
Win win;
XWindowAttributes xwa;
win = EXidLookup(xwin);
if (win)
goto done;
if (!pxwa)
{
pxwa = &xwa;
if (!XGetWindowAttributes(disp, xwin, pxwa))
goto done;
}
#if 0
Eprintf("ERegisterWindow %#lx %d+%d %dx%d\n", win, x, y, w, h);
#endif
win = EXidSet(xwin, None, pxwa->x, pxwa->y, pxwa->width, pxwa->height,
pxwa->depth, pxwa->visual, pxwa->colormap);
win->mapped = pxwa->map_state != IsUnmapped;
win->attached = 1;
done:
return win;
}
void
EUnregisterXwin(Window xwin)
{
Win win;
win = EXidLookup(xwin);
if (!win)
return;
/* FIXME - We shouldn't go here */
EXidDel(win);
#if 1 /* Debug - Fix code if we get here */
Eprintf("*** FIXME - EUnregisterXwin %#lx\n", xwin);
#endif
}
void
EUnregisterWindow(Win win)
{
if (!win)
return;
if (win->cbl.lst)
{
if (EDebug(1))
Eprintf("EUnregisterWindow(%#lx) Ignored (%d callbacks remain)\n",
win->xwin, win->cbl.num);
return;
}
EXidDel(win);
}
void
EMapWindow(Win win)
{
if (!win)
return;
if (win->mapped)
return;
win->mapped = 1;
XMapWindow(disp, win->xwin);
}
void
EUnmapWindow(Win win)
{
if (!win)
return;
if (!win->mapped)
return;
win->mapped = 0;
XUnmapWindow(disp, win->xwin);
}
void
EReparentWindow(Win win, Win parent, int x, int y)
{
if (!win)
return;
#if 0
Eprintf
("EReparentWindow: %p %#lx: %d %#lx->%#lx %d,%d %dx%d -> %d,%d\n",
win, win->xwin, win->mapped, win->parent, parent->xwin,
win->x, win->y, win->w, win->h, x, y);
#endif
if (parent == win->parent)
{
if ((x != win->x) || (y != win->y))
{
win->x = x;
win->y = y;
XMoveWindow(disp, win->xwin, x, y);
}
return;
}
else
{
win->parent = parent;
win->x = x;
win->y = y;
}
XReparentWindow(disp, win->xwin, parent->xwin, x, y);
}
void
EMapRaised(Win win)
{
if (!win)
return;
if (win->mapped)
{
XRaiseWindow(disp, win->xwin);
return;
}
else
{
win->mapped = 1;
}
XMapRaised(disp, win->xwin);
}
int
EXGetGeometry(Drawable draw, Window * root_return, int *x, int *y,
int *w, int *h, int *bw, int *depth)
{
int ok;
Window rr;
int xx, yy;
unsigned int ww, hh, bb, dd;
ok = XGetGeometry(disp, draw, &rr, &xx, &yy, &ww, &hh, &bb, &dd);
if (!ok)
goto done;
if (root_return)
*root_return = rr;
if (x)
*x = xx;
if (y)
*y = yy;
if (w)
*w = ww;
if (h)
*h = hh;
if (bw)
*bw = bb;
if (depth)
*depth = dd;
done:
#if 0 /* Debug */
if (!ok)
Eprintf("EGetGeometry win=%#x, error %d\n", (unsigned)win, ok);
#endif
return ok;
}
int
EGetGeometry(Win win, Window * root_return, int *x, int *y,
int *w, int *h, int *bw, int *depth)
{
if (!win)
return 0;
if (x)
*x = win->x;
if (y)
*y = win->y;
if (w)
*w = win->w;
if (h)
*h = win->h;
if (bw)
*bw = 0;
if (depth)
*depth = win->depth;
if (root_return)
*root_return = VRoot.xwin;
return 1;
}
void
EGetWindowAttributes(Win win, XWindowAttributes * pxwa)
{
if (!win)
return;
pxwa->x = win->x;
pxwa->y = win->y;
pxwa->width = win->w;
pxwa->height = win->h;
pxwa->border_width = win->bw;
pxwa->depth = win->depth;
pxwa->visual = win->visual;
pxwa->colormap = win->cmap;
}
#if 0 /* Unused */
void
EConfigureWindow(Win win, unsigned int mask, XWindowChanges * wc)
{
char doit = 0;
if (!win)
return;
if ((mask & CWX) && (wc->x != win->x))
{
win->x = wc->x;
doit = 1;
}
if ((mask & CWY) && (wc->y != win->y))
{
win->y = wc->y;
doit = 1;
}
if ((mask & CWWidth) && (wc->width != win->w))
{
WinBgInvalidate(win);
win->w = wc->width;
doit = 1;
}
if ((mask & CWHeight) && (wc->height != win->h))
{
WinBgInvalidate(win);
win->h = wc->height;
doit = 1;
}
if ((doit) || (mask & (CWBorderWidth | CWSibling | CWStackMode)))
XConfigureWindow(disp, win->xwin, mask, wc);
}
#endif
void
ESetWindowBackgroundPixmap(Win win, Pixmap pmap)
{
if (!win)
return;
if (win->bgpmap && win->bg_owned)
EFreeWindowBackgroundPixmap(win);
win->bgpmap = pmap;
win->bg_owned = 0; /* Don't manage pixmap */
win->bgcol = 0xffffffff; /* Hmmm.. */
XSetWindowBackgroundPixmap(disp, win->xwin, pmap);
}
Pixmap
EGetWindowBackgroundPixmap(Win win)
{
Pixmap pmap;
if (!win)
return None;
if (win->bg_owned < 0) /* Free if invalidated */
EFreeWindowBackgroundPixmap(win);
else if (win->bgpmap)
return win->bgpmap;
/* Allocate/set new */
pmap = ECreatePixmap(win, win->w, win->h, 0);
ESetWindowBackgroundPixmap(win, pmap);
win->bg_owned = 1; /* Manage pixmap */
return pmap;
}
void
EFreeWindowBackgroundPixmap(Win win)
{
if (!win || !win->bgpmap)
return;
if (win->bg_owned)
EFreePixmap(win->bgpmap);
win->bgpmap = 0;
win->bg_owned = 0;
}
void
ESetWindowBackground(Win win, unsigned int col)
{
if (!win)
return;
if (win->bgpmap)
{
EFreeWindowBackgroundPixmap(win);
win->bgcol = col;
}
else if (win->bgcol != col)
{
win->bgcol = col;
}
else
return;
XSetWindowBackground(disp, win->xwin, col);
}
int
ETranslateCoordinates(Win src_w, Win dst_w,
int src_x, int src_y,
int *dest_x_return,
int *dest_y_return, Window * child_return)
{
Window child;
if (!child_return)
child_return = &child;
return XTranslateCoordinates(disp, src_w->xwin, dst_w->xwin, src_x, src_y,
dest_x_return, dest_y_return, child_return);
}
void
EXWarpPointer(Window xwin, int x, int y)
{
XWarpPointer(disp, None, xwin, 0, 0, 0, 0, x, y);
}
static Bool
EXQueryPointer(Window xwin, int *px, int *py, Window * pchild,
unsigned int *pmask)
{
Window root, child;
int root_x, root_y;
unsigned int mask;
if (xwin == None)
xwin = VRoot.xwin;
if (!px)
px = &root_x;
if (!py)
py = &root_y;
if (!pchild)
pchild = &child;
if (!pmask)
pmask = &mask;
return XQueryPointer(disp, xwin, &root, pchild, &root_x, &root_y, px, py,
pmask);
}
Bool
EQueryPointer(Win win, int *px, int *py, Window * pchild, unsigned int *pmask)
{
Window xwin;
xwin = (win) ? win->xwin : VRoot.xwin;
return EXQueryPointer(xwin, px, py, pchild, pmask);
}
void
ESelectInputChange(Win win, unsigned long set, unsigned long clear)
{
XWindowAttributes xwa;
XGetWindowAttributes(disp, win->xwin, &xwa);
xwa.your_event_mask |= set;
xwa.your_event_mask &= ~clear;
XSelectInput(disp, win->xwin, xwa.your_event_mask);
}
int
EDrawableCheck(Drawable draw, int grab)
{
int ok;
if (draw == None)
return 0;
if (grab)
EGrabServer();
ok = EXGetGeometry(draw, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
if (grab && !ok)
EUngrabServer();
return ok;
}
#define DEBUG_SHAPE_OPS 0
#define DEBUG_SHAPE_PROPAGATE 0
#if DEBUG_SHAPE_OPS || DEBUG_SHAPE_PROPAGATE
static void
EShapeShow(const char *txt, Window xwin, XRectangle * pr, int nr)
{
int i;
Eprintf("%s %#lx nr=%d\n", txt, xwin, nr);
for (i = 0; i < nr; i++)
Eprintf(" %d - %4d,%4d %4dx%4d\n", i,
pr[i].x, pr[i].y, pr[i].width, pr[i].height);
}
#endif
static void
EShapeUpdate(Win win)
{
if (win->rects)
{
XFree(win->rects);
win->num_rect = 0;
}
win->rects =
XShapeGetRectangles(disp, win->xwin, ShapeBounding, &(win->num_rect),
&(win->ord));
if (win->rects)
{
if (win->num_rect == 1)
{
if ((win->rects[0].x == 0) && (win->rects[0].y == 0)
&& (win->rects[0].width == win->w)
&& (win->rects[0].height == win->h))
{
win->num_rect = 0;
XFree(win->rects);
win->rects = NULL;
XShapeCombineMask(disp, win->xwin, ShapeBounding, 0, 0,
None, ShapeSet);
}
}
else if (win->num_rect > 4096)
{
Eprintf("*** EShapeUpdate: nrect=%d - Not likely, ignoring.\n",
win->num_rect);
XShapeCombineMask(disp, win->xwin, ShapeBounding, 0, 0, None,
ShapeSet);
win->num_rect = 0;
XFree(win->rects);
win->rects = NULL;
}
}
else
{
win->num_rect = -1;
}
#if DEBUG_SHAPE_OPS
EShapeShow("EShapeUpdate", win->xwin, win->rects, win->num_rect);
#endif
}
void
EShapeCombineMask(Win win, int dest, int x, int y, Pixmap pmap, int op)
{
char wasshaped = 0;
if (!win)
return;
if (win->rects || win->num_rect < 0)
{
win->num_rect = 0;
if (win->rects)
XFree(win->rects);
win->rects = NULL;
wasshaped = 1;
}
#if DEBUG_SHAPE_OPS
Eprintf("EShapeCombineMask %#lx %d,%d %dx%d mask=%#lx wassh=%d\n",
win->xwin, win->x, win->y, win->w, win->h, pmap, wasshaped);
#endif
if (pmap)
{
XShapeCombineMask(disp, win->xwin, dest, x, y, pmap, op);
EShapeUpdate(win);
}
else if (wasshaped)
XShapeCombineMask(disp, win->xwin, dest, x, y, pmap, op);
}
void
EShapeCombineMaskTiled(Win win, int dest, int x, int y,
Pixmap pmap, int op, int w, int h)
{
XGCValues gcv;
GC gc;
Window tm;
gcv.fill_style = FillTiled;
gcv.tile = pmap;
gcv.ts_x_origin = 0;
gcv.ts_y_origin = 0;
tm = ECreatePixmap(win, w, h, 1);
gc = EXCreateGC(tm, GCFillStyle | GCTile |
GCTileStipXOrigin | GCTileStipYOrigin, &gcv);
XFillRectangle(disp, tm, gc, 0, 0, w, h);
EXFreeGC(gc);
EShapeCombineMask(win, dest, x, y, tm, op);
EFreePixmap(tm);
}
void
EShapeCombineRectangles(Win win, int dest, int x, int y,
XRectangle * rect, int n_rects, int op, int ordering)
{
if (!win)
return;
#if DEBUG_SHAPE_OPS
Eprintf("EShapeCombineRectangles %#lx %d\n", win->xwin, n_rects);
#endif
if (n_rects == 1 && op == ShapeSet)
{
if ((rect[0].x == 0) && (rect[0].y == 0) &&
(rect[0].width == win->w) && (rect[0].height == win->h))
{
win->num_rect = 0;
XFree(win->rects);
win->rects = NULL;
XShapeCombineMask(disp, win->xwin, dest, x, y, None, op);
return;
}
}
XShapeCombineRectangles(disp, win->xwin, dest, x, y, rect, n_rects, op,
ordering);
if (n_rects > 1)
{
/* Limit shape to window extents */
XRectangle r;
r.x = r.y = 0;
r.width = win->w;
r.height = win->h;
XShapeCombineRectangles(disp, win->xwin, ShapeBounding, 0, 0, &r,
1, ShapeIntersect, Unsorted);
}
EShapeUpdate(win);
}
#if 0 /* Unused */
XRectangle *
EShapeGetRectangles(Win win, int dest, int *rn, int *ord)
{
if (!win)
return NULL;
if (!win->attached)
{
XRectangle *r;
#if DEBUG_SHAPE_OPS
Eprintf("EShapeGetRectangles-A %#lx nr=%d\n", win->xwin, win->num_rect);
#endif
*rn = win->num_rect;
*ord = win->ord;
if (win->num_rect > 0)
{
r = EMALLOC(XRectangle, win->num_rect);
if (!r)
return NULL;
memcpy(r, win->rects, sizeof(XRectangle) * win->num_rect);
return r;
}
}
else
{
XRectangle *r, *rr;
#if DEBUG_SHAPE_OPS
Eprintf("EShapeGetRectangles-B %#lx nr=%d\n", win->xwin, win->num_rect);
#endif
r = XShapeGetRectangles(disp, win->xwin, dest, rn, ord);
if (r)
{
rr = EMALLOC(XRectangle, *rn);
if (!rr)
return NULL;
memcpy(rr, r, sizeof(XRectangle) * *rn);
XFree(r);
return rr;
}
}
return NULL;
}
#endif
int
EShapeCopy(Win dst, Win src)
{
XRectangle *rl;
int rn;
if (!src || !dst)
return 0;
if (src->attached)
EShapeUpdate(src);
rn = src->num_rect;
rl = src->rects;
if (rn < 0)
{
/* Source has empty shape */
EShapeCombineShape(dst, ShapeBounding, 0, 0,
src, ShapeBounding, ShapeSet);
}
else if (rn == 0)
{
/* Source has default shape (no shape) */
EShapeCombineMask(dst, ShapeBounding, 0, 0, None, ShapeSet);
}
else if (rn == 1)
{
if ((rl[0].x <= 0) && (rl[0].y <= 0) && (rl[0].width >= src->w)
&& (rl[0].height >= src->h))
{
rn = 0;
EShapeCombineMask(dst, ShapeBounding, 0, 0, None, ShapeSet);
}
else
{
EShapeCombineShape(dst, ShapeBounding, 0, 0,
src, ShapeBounding, ShapeSet);
}
}
else
{
EShapeCombineShape(dst, ShapeBounding, 0, 0,
src, ShapeBounding, ShapeSet);
}
return rn != 0;
}
int
EShapePropagate(Win win)
{
Win xch;
unsigned int num_rects;
int k, rn;
int x, y, w, h;
XRectangle *rects, *rl;
if (!win || win->w <= 0 || win->h <= 0)
return 0;
#if DEBUG_SHAPE_PROPAGATE
Eprintf("EShapePropagate %#lx %d,%d %dx%d\n", win->xwin,
win->x, win->y, win->w, win->h);
#endif
num_rects = 0;
rects = NULL;
/* go through all child windows and create/inset spans */
for (xch = win_first; xch; xch = xch->next)
{
if (xch->parent != win)
continue;
#if DEBUG_SHAPE_PROPAGATE > 1
Eprintf("%#lx(%d): %4d,%4d %4dx%4d\n", xch->xwin, xch->mapped,
xch->x, xch->y, xch->w, xch->h);
#endif
if (!xch->mapped)
continue;
x = xch->x;
y = xch->y;
w = xch->w;
h = xch->h;
if (x >= win->w || y >= win->h || x + w < 0 || y + h < 0)
continue;
rn = xch->num_rect;
if (rn > 0)
{
rl = xch->rects;
rects = EREALLOC(XRectangle, rects, num_rects + rn);
/* go through all clip rects in thsi window's shape */
for (k = 0; k < rn; k++)
{
/* for each clip rect, add it to the rect list */
rects[num_rects + k].x = x + rl[k].x;
rects[num_rects + k].y = y + rl[k].y;
rects[num_rects + k].width = rl[k].width;
rects[num_rects + k].height = rl[k].height;
#if DEBUG_SHAPE_PROPAGATE > 1
Eprintf(" - %d: %4d,%4d %4dx%4d\n", k,
rects[num_rects + k].x,
rects[num_rects + k].y, rects[num_rects + k].width,
rects[num_rects + k].height);
#endif
}
num_rects += rn;
}
else if (rn == 0)
{
/* Unshaped */
rects = EREALLOC(XRectangle, rects, num_rects + 1);
rects[num_rects].x = x;
rects[num_rects].y = y;
rects[num_rects].width = w;
rects[num_rects].height = h;
num_rects++;
}
}
#if DEBUG_SHAPE_PROPAGATE
EShapeShow("EShapePropagate", win->xwin, rects, num_rects);
#endif
/* set the rects as the shape mask */
if (rects)
{
EShapeCombineRectangles(win, ShapeBounding, 0, 0, rects,
num_rects, ShapeSet, Unsorted);
Efree(rects);
}
else
{
/* Empty shape */
EShapeCombineRectangles(win, ShapeBounding, 0, 0, NULL, 0, ShapeSet,
Unsorted);
}
return win->num_rect;
}
void
EShapeCombineShape(Win win, int dest, int x, int y,
Win src_win, int src_kind, int op)
{
if (!win)
return;
XShapeCombineShape(disp, win->xwin, dest, x, y, src_win->xwin, src_kind, op);
EShapeUpdate(win);
}
int
EShapeCheck(Win win)
{
if (!win)
return 0;
return win->num_rect;
}
Pixmap
ECreatePixmap(Win win, unsigned int width, unsigned int height,
unsigned int depth)
{
Pixmap pmap;
if (depth == 0)
depth = win->depth;
pmap = XCreatePixmap(disp, win->xwin, width, height, depth);
#if DEBUG_PIXMAP
Eprintf("%s: %#lx\n", __func__, pmap);
#endif
return pmap;
}
void
EFreePixmap(Pixmap pmap)
{
#if DEBUG_PIXMAP
Eprintf("%s: %#lx\n", __func__, pmap);
#endif
XFreePixmap(disp, pmap);
}
Pixmap
EXCreatePixmapCopy(Pixmap src, unsigned int w, unsigned int h,
unsigned int depth)
{
Pixmap pmap;
GC gc;
pmap = XCreatePixmap(disp, src, w, h, depth);
gc = EXCreateGC(src, 0, NULL);
XCopyArea(disp, src, pmap, gc, 0, 0, w, h, 0, 0);
EXFreeGC(gc);
#if DEBUG_PIXMAP
Eprintf("%s: %#lx\n", __func__, pmap);
#endif
return pmap;
}
void
EXCopyArea(Drawable src, Drawable dst, int sx, int sy, unsigned int w,
unsigned int h, int dx, int dy)
{
GC gc;
gc = EXCreateGC(src, 0, NULL);
XCopyArea(disp, src, dst, gc, sx, sy, w, h, dx, dy);
EXFreeGC(gc);
}
GC
EXCreateGC(Drawable draw, unsigned long mask, XGCValues * val)
{
XGCValues xgcv;
if (val)
{
mask |= GCGraphicsExposures;
val->graphics_exposures = False;
}
else
{
mask = GCGraphicsExposures;
val = &xgcv;
val->graphics_exposures = False;
}
return XCreateGC(disp, draw, mask, val);
}
int
EXFreeGC(GC gc)
{
return XFreeGC(disp, gc);
}
void
EAllocColor(Colormap cmap, EColor * pec)
{
XColor xc;
EAllocXColor(cmap, &xc, pec);
pec->pixel = xc.pixel;
}
void
EAllocXColor(Colormap cmap, XColor * pxc, EColor * pec)
{
pxc->red = pec->red << 8;
pxc->green = pec->green << 8;
pxc->blue = pec->blue << 8;
XAllocColor(disp, cmap, pxc);
}
/* Build mask from window shape rects */
/* Snatched from imlib_create_scaled_image_from_drawable() */
Pixmap
EWindowGetShapePixmap(Win win)
{
Pixmap mask;
GC gc;
XRectangle *rect;
int i, w, h;
int rect_num, rect_ord;
EGetGeometry(win, NULL, NULL, NULL, &w, &h, NULL, NULL);
mask = ECreatePixmap(win, w, h, 1);
gc = EXCreateGC(mask, 0, NULL);
XSetForeground(disp, gc, 0);
rect =
XShapeGetRectangles(disp, win->xwin, ShapeBounding, &rect_num, &rect_ord);
XFillRectangle(disp, mask, gc, 0, 0, w, h);
if (rect)
{
XSetForeground(disp, gc, 1);
for (i = 0; i < rect_num; i++)
XFillRectangle(disp, mask, gc, rect[i].x, rect[i].y,
rect[i].width, rect[i].height);
XFree(rect);
}
EXFreeGC(gc);
return mask;
}
/*
* Display
*/
Display *
EDisplayOpen(const char *dstr, int scr)
{
char dbuf[256], *s;
Display *dpy;
if (scr >= 0)
{
/* Override screen */
Esnprintf(dbuf, sizeof(dbuf) - 10, dstr);
s = strchr(dbuf, ':');
if (s)
{
s = strchr(s, '.');
if (s)
*s = '\0';
}
Esnprintf(dbuf + strlen(dbuf), 10, ".%d", scr);
dstr = dbuf;
}
#ifdef USE_ECORE_X
ecore_x_init(dstr);
dpy = ecore_x_display_get();
#else
dpy = XOpenDisplay(dstr);
#endif
return dpy;
}
void
EDisplayClose(void)
{
if (!disp)
return;
#ifdef USE_ECORE_X
ecore_x_shutdown();
#else
XCloseDisplay(disp);
#endif
XSetErrorHandler(NULL);
XSetIOErrorHandler(NULL);
disp = NULL;
}
void
EDisplayDisconnect(void)
{
if (!disp)
return;
#ifdef USE_ECORE_X
ecore_x_disconnect();
#else
close(ConnectionNumber(disp));
#endif
XSetErrorHandler(NULL);
XSetIOErrorHandler(NULL);
disp = NULL;
}
/*
* Server
*/
void
EGrabServer(void)
{
if (Mode.grabs.server_grabbed <= 0)
{
if (EDebug(EDBUG_TYPE_GRABS))
Eprintf("EGrabServer\n");
XGrabServer(disp);
}
Mode.grabs.server_grabbed++;
}
void
EUngrabServer(void)
{
if (Mode.grabs.server_grabbed == 1)
{
XUngrabServer(disp);
XFlush(disp);
if (EDebug(EDBUG_TYPE_GRABS))
Eprintf("EUngrabServer\n");
}
Mode.grabs.server_grabbed--;
if (Mode.grabs.server_grabbed < 0)
Mode.grabs.server_grabbed = 0;
}
int
EServerIsGrabbed(void)
{
return Mode.grabs.server_grabbed;
}
void
EFlush(void)
{
XFlush(disp);
}
void
ESync(void)
{
XSync(disp, False);
}
/*
* Visuals
*/
#if USE_COMPOSITE
Visual *
EVisualFindARGB(void)
{
XVisualInfo *xvi, xvit;
int i, num;
Visual *vis;
xvit.screen = VRoot.scr;
xvit.depth = 32;
#if __cplusplus
xvit.c_class = TrueColor;
#else
xvit.class = TrueColor;
#endif
xvi = XGetVisualInfo(disp,
VisualScreenMask | VisualDepthMask | VisualClassMask,
&xvit, &num);
if (!xvi)
return NULL;
for (i = 0; i < num; i++)
{
if (EVisualIsARGB(xvi[i].visual))
break;
}
vis = (i < num) ? xvi[i].visual : NULL;
XFree(xvi);
return vis;
}
int
EVisualIsARGB(Visual * vis)
{
XRenderPictFormat *pictfmt;
pictfmt = XRenderFindVisualFormat(disp, vis);
if (!pictfmt)
return 0;
#if 0
Eprintf("Visual ID=%#lx Type=%d, alphamask=%d\n", vis->visualid,
pictfmt->type, pictfmt->direct.alphaMask);
#endif
return pictfmt->type == PictTypeDirect && pictfmt->direct.alphaMask;
}
#endif
/*
* Misc
*/
Time
EGetTimestamp(void)
{
static Window win_ts = None;
XSetWindowAttributes attr;
XEvent ev;
if (win_ts == None)
{
attr.override_redirect = False;
win_ts = XCreateWindow(disp, VRoot.xwin, -100, -100, 1, 1, 0,
CopyFromParent, InputOnly, CopyFromParent,
CWOverrideRedirect, &attr);
XSelectInput(disp, win_ts, PropertyChangeMask);
}
XChangeProperty(disp, win_ts, XA_WM_NAME, XA_STRING, 8,
PropModeAppend, (unsigned char *)"", 0);
XWindowEvent(disp, win_ts, PropertyChangeMask, &ev);
return ev.xproperty.time;
}