e16/src/x.c

872 lines
18 KiB
C

/*
* Copyright (C) 2000 Carsten Haitzler, Geoff Harrison and various contributors
*
* 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.
*/
#include "E.h"
#include <X11/Xutil.h>
#include <X11/Xresource.h>
Pixmap
ECreatePixmap(Display * display, Drawable d, unsigned int width,
unsigned int height, unsigned depth)
{
Pixmap pm;
pm = XCreatePixmap(display, d, width, height, depth);
return pm;
}
void
EFreePixmap(Display * display, Pixmap pixmap)
{
XFreePixmap(display, pixmap);
}
Window ECreateWindow(Window parent, int x, int y, int w, int h, int saveunder)
{
EXID *xid;
Window win;
XSetWindowAttributes attr;
EDBUG(6, "ECreateWindow");
attr.backing_store = NotUseful;
attr.override_redirect = True;
attr.colormap = root.cmap;
attr.border_pixel = 0;
/* attr.background_pixel = 0; */
attr.background_pixmap = None;
if ((saveunder == 1) && (mode.save_under))
attr.save_under = True;
else if (saveunder == 2)
attr.save_under = True;
else
attr.save_under = False;
win =
XCreateWindow(disp, parent, x, y, w, h, 0, root.depth, InputOutput,
root.vis,
CWOverrideRedirect | CWSaveUnder | CWBackingStore |
CWColormap | CWBackPixmap | CWBorderPixel, &attr);
xid = NewXID();
xid->parent = parent;
xid->win = win;
xid->x = x;
xid->y = y;
xid->w = w;
xid->h = h;
xid->depth = root.depth;
AddXID(xid);
EDBUG_RETURN(win);
}
void
EMoveWindow(Display * d, Window win, int x, int y)
{
EXID *xid;
xid = FindXID(win);
if (xid)
{
if ((x != xid->x) || (y != xid->y))
{
xid->x = x;
xid->y = y;
XMoveWindow(d, win, x, y);
}
}
else
XMoveWindow(d, win, x, y);
}
void
EResizeWindow(Display * d, Window win, int w, int h)
{
EXID *xid;
xid = FindXID(win);
if (xid)
{
if ((w != xid->w) || (h != xid->h))
{
xid->w = w;
xid->h = h;
XResizeWindow(d, win, w, h);
}
}
else
XResizeWindow(d, win, w, h);
}
void
EMoveResizeWindow(Display * d, Window win, int x, int y, int w, int h)
{
EXID *xid;
xid = FindXID(win);
if (xid)
{
if ((w != xid->w) || (h != xid->h) || (x != xid->x) || (y != xid->y))
{
xid->x = x;
xid->y = y;
xid->w = w;
xid->h = h;
XMoveResizeWindow(d, win, x, y, w, h);
}
}
else
XMoveResizeWindow(d, win, x, y, w, h);
}
void
EDestroyWindow(Display * d, Window win)
{
EXID *xid;
if ((mode.slideout) && (mode.slideout->from_win == win))
HideSlideout(mode.slideout, 0);
xid = FindXID(win);
if (xid)
{
EXID **lst;
int i, num;
DelXID(win);
XDestroyWindow(d, win);
lst = (EXID **) ListItemType(&num, LIST_TYPE_XID);
if (lst)
{
for (i = 0; i < num; i++)
{
if (lst[i]->parent == win)
EDestroyWindow(d, lst[i]->win);
}
Efree(lst);
}
}
else
XDestroyWindow(d, win);
}
void
EMapWindow(Display * d, Window win)
{
EXID *xid;
xid = FindXID(win);
if (xid)
{
if (!xid->mapped)
{
xid->mapped = 1;
XMapWindow(d, win);
}
}
else
XMapWindow(d, win);
}
void
EUnmapWindow(Display * d, Window win)
{
EXID *xid;
xid = FindXID(win);
if (xid)
{
if (xid->mapped)
{
xid->mapped = 0;
XUnmapWindow(d, win);
}
}
else
XUnmapWindow(d, win);
}
void
EShapeCombineMask(Display * d, Window win, int dest, int x, int y, Pixmap pmap,
int op)
{
EXID *xid;
xid = FindXID(win);
if (xid)
{
char wasshaped = 0;
if (xid->rects)
{
xid->num_rect = 0;
XFree(xid->rects);
xid->rects = NULL;
wasshaped = 1;
}
if (pmap)
{
XShapeCombineMask(d, win, dest, x, y, pmap, op);
xid->rects =
XShapeGetRectangles(d, win, dest, &(xid->num_rect),
&(xid->ord));
if (xid->rects)
{
if (xid->num_rect == 1)
{
if ((xid->rects[0].x == 0) && (xid->rects[0].y == 0)
&& (xid->rects[0].width == xid->w)
&& (xid->rects[0].height == xid->h))
{
xid->num_rect = 0;
XFree(xid->rects);
xid->rects = NULL;
}
}
}
}
else if ((!pmap) && (wasshaped))
XShapeCombineMask(d, win, dest, x, y, pmap, op);
}
else
XShapeCombineMask(d, win, dest, x, y, pmap, op);
}
void
EShapeCombineRectangles(Display * d, Window win, int dest, int x, int y,
XRectangle * rect, int n_rects, int op, int ordering)
{
EXID *xid;
xid = FindXID(win);
if (xid)
{
if (n_rects == 1)
{
if ((rect[0].x == 0) && (rect[0].y == 0)
&& (rect[0].width == xid->w) && (rect[0].height == xid->h))
{
xid->num_rect = 0;
XFree(xid->rects);
xid->rects = NULL;
XShapeCombineMask(d, win, dest, x, y, None, op);
return;
}
}
xid->num_rect = 0;
if (xid->rects)
XFree(xid->rects);
XShapeCombineRectangles(d, win, dest, x, y, rect, n_rects, op,
ordering);
xid->rects =
XShapeGetRectangles(d, win, dest, &(xid->num_rect), &(xid->ord));
if (xid->rects)
{
if (xid->num_rect == 1)
{
if ((xid->rects[0].x == 0) && (xid->rects[0].y == 0)
&& (xid->rects[0].width == xid->w)
&& (xid->rects[0].height == xid->h))
{
xid->num_rect = 0;
XFree(xid->rects);
xid->rects = NULL;
}
}
}
}
else
XShapeCombineRectangles(d, win, dest, x, y, rect, n_rects, op, ordering);
}
void
EShapeCombineShape(Display * d, Window win, int dest, int x, int y,
Window src_win, int src_kind, int op)
{
EXID *xid;
xid = FindXID(win);
if (xid)
{
xid->num_rect = 0;
if (xid->rects)
XFree(xid->rects);
XShapeCombineShape(d, win, dest, x, y, src_win, src_kind, op);
xid->rects =
XShapeGetRectangles(d, win, dest, &(xid->num_rect), &(xid->ord));
if (xid->rects)
{
if (xid->num_rect == 1)
{
if ((xid->rects[0].x == 0) && (xid->rects[0].y == 0)
&& (xid->rects[0].width == xid->w)
&& (xid->rects[0].height == xid->h))
{
xid->num_rect = 0;
XFree(xid->rects);
xid->rects = NULL;
}
}
}
}
else
XShapeCombineShape(d, win, dest, x, y, src_win, src_kind, op);
}
XRectangle *
EShapeGetRectangles(Display * d, Window win, int dest, int *rn, int *ord)
{
EXID *xid;
xid = FindXID(win);
if (xid)
{
XRectangle *r;
*rn = xid->num_rect;
*ord = xid->ord;
if (xid->num_rect > 0)
{
r = Emalloc(sizeof(XRectangle) * xid->num_rect);
memcpy(r, xid->rects, sizeof(XRectangle) * xid->num_rect);
return r;
}
else
return NULL;
}
else
{
XRectangle *r, *rr;
r = XShapeGetRectangles(d, win, dest, rn, ord);
if (r)
{
rr = Emalloc(sizeof(XRectangle) * *rn);
memcpy(rr, r, sizeof(XRectangle) * *rn);
XFree(r);
return rr;
}
}
return NULL;
}
void
EReparentWindow(Display * d, Window win, Window parent, int x, int y)
{
EXID *xid;
xid = FindXID(win);
if (xid)
{
if (parent == xid->parent)
{
if ((x != xid->x) || (y != xid->y))
{
xid->x = x;
xid->y = y;
XMoveWindow(d, win, x, y);
}
}
else
{
xid->parent = parent;
xid->x = x;
xid->y = y;
XReparentWindow(d, win, parent, x, y);
}
}
else
XReparentWindow(d, win, parent, x, y);
}
void
EMapRaised(Display * d, Window win)
{
EXID *xid;
xid = FindXID(win);
if (xid)
{
if (xid->mapped)
XRaiseWindow(d, win);
else
{
xid->mapped = 1;
XMapRaised(d, win);
}
}
else
XMapRaised(d, win);
}
int
EGetGeometry(Display * d, Window win, Window * root_return, int *x, int *y,
unsigned int *w, unsigned int *h, unsigned int *bw,
unsigned int *depth)
{
EXID *xid;
xid = FindXID(win);
if (xid)
{
if (x)
*x = xid->x;
if (y)
*y = xid->y;
if (w)
*w = xid->w;
if (h)
*h = xid->h;
if (bw)
*bw = 0;
if (depth)
*depth = xid->depth;
if (root_return)
*root_return = root.win;
return 1;
}
return XGetGeometry(d, win, root_return, x, y, w, h, bw, depth);
}
void
EConfigureWindow(Display * d, Window win, unsigned int mask,
XWindowChanges * wc)
{
EXID *xid;
xid = FindXID(win);
if (xid)
{
char doit = 0;
if ((mask & CWX) && (wc->x != xid->x))
{
xid->x = wc->x;
doit = 1;
}
if ((mask & CWY) && (wc->y != xid->y))
{
xid->y = wc->y;
doit = 1;
}
if ((mask & CWWidth) && (wc->width != xid->w))
{
xid->w = wc->width;
doit = 1;
}
if ((mask & CWHeight) && (wc->height != xid->h))
{
xid->h = wc->height;
doit = 1;
}
if ((doit) || (mask & (CWBorderWidth | CWSibling | CWStackMode)))
XConfigureWindow(d, win, mask, wc);
}
else
{
XConfigureWindow(d, win, mask, wc);
}
}
void
ESetWindowBackgroundPixmap(Display * d, Window win, Pixmap pmap)
{
EXID *xid;
xid = FindXID(win);
if (xid)
{
xid->bgpmap = pmap;
XSetWindowBackgroundPixmap(d, win, pmap);
}
else
XSetWindowBackgroundPixmap(d, win, pmap);
}
void
ESetWindowBackground(Display * d, Window win, int col)
{
EXID *xid;
xid = FindXID(win);
if (xid)
{
if (xid->bgpmap)
{
xid->bgpmap = 0;
xid->bgcol = col;
XSetWindowBackground(d, win, col);
}
else if (xid->bgcol != col)
{
xid->bgcol = col;
XSetWindowBackground(d, win, col);
}
}
else
XSetWindowBackground(d, win, col);
}
EXID *
NewXID(void)
{
EXID *xid;
xid = Emalloc(sizeof(EXID));
xid->parent = 0;
xid->win = 0;
xid->x = 0;
xid->y = 0;
xid->w = 0;
xid->h = 0;
xid->num_rect = 0;
xid->ord = 0;
xid->rects = NULL;
xid->depth = 0;
xid->mapped = 0;
xid->bgpmap = 0;
xid->bgcol = 0;
return xid;
}
static XContext xid_context = 0;
void
AddXID(EXID * xid)
{
if (!xid_context)
xid_context = XUniqueContext();
XSaveContext(disp, xid->win, xid_context, (XPointer) xid);
AddItem(xid, "", xid->win, LIST_TYPE_XID);
}
EXID *
FindXID(Window win)
{
EXID *xid = NULL;
if (xid_context == 0)
xid_context = XUniqueContext();
if (XFindContext(disp, win, xid_context, (XPointer *) & xid) == XCNOENT)
xid = NULL;
return xid;
}
void
DelXID(Window win)
{
EXID *xid;
if (xid_context == 0)
xid_context = XUniqueContext();
xid = RemoveItem("", win, LIST_FINDBY_ID, LIST_TYPE_XID);
if (xid)
{
XDeleteContext(disp, win, xid_context);
if (xid->rects)
XFree(xid->rects);
Efree(xid);
}
}
Window ECreateEventWindow(Window parent, int x, int y, int w, int h)
{
Window win;
XSetWindowAttributes attr;
EDBUG(6, "ECreateEventWindow");
attr.override_redirect = False;
win =
XCreateWindow(disp, parent, x, y, w, h, 0, 0, InputOnly, root.vis,
CWOverrideRedirect, &attr);
EDBUG_RETURN(win);
}
/*
* create a window which will accept the keyboard focus when no other
* windows have it
*/
Window ECreateFocusWindow(Window parent, int x, int y, int w, int h)
{
Window win;
XSetWindowAttributes attr;
EDBUG(6, "ECreateFocusWindow");
attr.backing_store = NotUseful;
attr.override_redirect = True;
attr.colormap = root.cmap;
attr.border_pixel = 0;
attr.background_pixel = 0;
attr.save_under = False;
attr.event_mask = KeyPressMask | FocusChangeMask;
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);
EDBUG_RETURN(win);
}
void
GrabX()
{
EDBUG(6, "GrabX");
if (mode.server_grabbed <= 0)
XGrabServer(disp);
mode.server_grabbed++;
EDBUG_RETURN_;
}
void
UngrabX()
{
EDBUG(6, "UngrabX");
if (mode.server_grabbed == 1)
{
XUngrabServer(disp);
XFlush(disp);
}
mode.server_grabbed--;
if (mode.server_grabbed < 0)
mode.server_grabbed = 0;
EDBUG_RETURN_;
}
void
SetBG(Window win, Pixmap pmap, int color)
{
static Atom a = 0, aa = 0, aaa = 0;
static Window alive_win = 0;
EDBUG(6, "SetBG");
if (!a)
{
a = XInternAtom(disp, "_XROOTPMAP_ID", False);
aa = XInternAtom(disp, "_XROOTCOLOR_PIXEL", False);
aaa = XInternAtom(disp, "_XROOTWINDOW", False);
}
if (!alive_win)
{
alive_win = ECreateWindow(root.win, -100, -100, 1, 1, 0);
XChangeProperty(disp, alive_win, aaa, XA_WINDOW, 32, PropModeReplace,
(unsigned char *)&alive_win, 1);
XChangeProperty(disp, root.win, aaa, XA_WINDOW, 32, PropModeReplace,
(unsigned char *)&alive_win, 1);
}
XChangeProperty(disp, win, a, XA_PIXMAP, 32, PropModeReplace,
(unsigned char *)&pmap, 1);
XChangeProperty(disp, win, aa, XA_CARDINAL, 32, PropModeReplace,
(unsigned char *)&color, 1);
if (pmap)
XSetWindowBackgroundPixmap(disp, win, pmap);
else
XSetWindowBackground(disp, win, color);
XClearWindow(disp, win);
EDBUG_RETURN_;
}
void
GetWinXY(Window win, int *x, int *y)
{
Window w1;
unsigned int w, h, b, d;
EDBUG(7, "GetWinXY");
EGetGeometry(disp, win, &w1, x, y, &w, &h, &b, &d);
EDBUG_RETURN_;
}
void
GetWinWH(Window win, unsigned int *w, unsigned int *h)
{
Window w1;
int x, y;
unsigned int b, d;
EDBUG(7, "GetWinWH");
EGetGeometry(disp, win, &w1, &x, &y, w, h, &b, &d);
EDBUG_RETURN_;
}
int
GetWinDepth(Window win)
{
Window w1;
unsigned int w, h, b, d;
int x, y;
EDBUG(7, "GetWinDepth");
EGetGeometry(disp, win, &w1, &x, &y, &w, &h, &b, &d);
EDBUG_RETURN(d);
}
int
WinExists(Window win)
{
Window w1;
int x, y;
unsigned int w, h;
unsigned int b, d;
EDBUG(7, "WinExists");
if (EGetGeometry(disp, win, &w1, &x, &y, &w, &h, &b, &d))
EDBUG_RETURN(1);
EDBUG_RETURN(0);
}
Window WindowAtXY_0(Window base, int bx, int by, int x, int y)
{
Window *list = NULL;
XWindowAttributes att;
Window child = 0, parent_win = 0, root_win = 0;
int i;
unsigned int ww, wh, num;
int wx, wy;
EDBUG(7, "WindowAtXY_0");
if (!XGetWindowAttributes(disp, base, &att))
EDBUG_RETURN(0);
if (att.class == InputOnly)
EDBUG_RETURN(0);
if (att.map_state != IsViewable)
EDBUG_RETURN(0);
wx = att.x;
wy = att.y;
ww = att.width;
wh = att.height;
wx += bx;
wy += by;
if (!((x >= wx) && (y >= wy) && (x < (int)(wx + ww))
&& (y < (int)(wy + wh))))
EDBUG_RETURN(0);
if (!XQueryTree(disp, base, &root_win, &parent_win, &list, &num))
EDBUG_RETURN(base);
if (list)
{
for (i = num - 1;; i--)
{
if ((child = WindowAtXY_0(list[i], wx, wy, x, y)) != 0)
{
XFree(list);
EDBUG_RETURN(child);
}
if (!i)
break;
}
XFree(list);
}
EDBUG_RETURN(base);
}
Window WindowAtXY(int x, int y)
{
Window *list = NULL;
Window child = 0, parent_win = 0, root_win = 0;
unsigned int num;
int i;
EDBUG(7, "WindowAtXY");
GrabX();
if (!XQueryTree(disp, root.win, &root_win, &parent_win, &list, &num))
{
UngrabX();
EDBUG_RETURN(root.win);
}
if (list)
{
i = num - 1;
do
{
XWindowAttributes xwa;
XGetWindowAttributes(disp, list[i], &xwa);
if (xwa.map_state != IsViewable)
continue;
if ((child = WindowAtXY_0(list[i], 0, 0, x, y)) == 0)
continue;
XFree(list);
UngrabX();
EDBUG_RETURN(child);
}
while (--i > 0);
XFree(list);
}
UngrabX();
EDBUG_RETURN(root.win);
}
void
PointerAt(int *x, int *y)
{
Window dw;
int dd;
unsigned int mm;
XQueryPointer(disp, root.win, &dw, &dw, &dd, &dd, x, y, &mm);
}
void
PastePixmap(Display * d, Drawable w, Pixmap p, Mask m, int x, int y)
{
static GC gc = 0;
XGCValues gcv;
int ww, hh;
if (!gc)
gc = XCreateGC(d, w, 0, &gcv);
GetWinWH(p, (unsigned int *)&ww, (unsigned int *)&hh);
XSetClipMask(disp, gc, m);
XSetClipOrigin(disp, gc, x, y);
XCopyArea(disp, p, w, gc, 0, 0, ww, hh, x, y);
}
void
PasteMask(Display * d, Drawable w, Pixmap p, int x, int y, int wd, int ht)
{
static GC gc = 0;
XGCValues gcv;
int ww, hh;
if (!gc)
gc = XCreateGC(d, w, 0, &gcv);
if (p)
{
GetWinWH(p, (unsigned int *)&ww, (unsigned int *)&hh);
XSetClipMask(disp, gc, p);
XSetClipOrigin(disp, gc, x, y);
XCopyArea(disp, p, w, gc, 0, 0, ww, hh, x, y);
}
else
{
XSetForeground(disp, gc, 1);
XFillRectangle(disp, w, gc, x, y, wd, ht);
}
}