#include "xsimple.h"
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
XVARS xv;
static Atom wm_protocols, wm_delete_window;
static void cleanup(void)
{
XCloseDisplay(xv.d);
}
static void sighandler(int sig)
{
xv.sig++;
}
void xinit(char *appname, char *classname, char *winname,
int x, int y, int width, int height, int resizable,
char *bgcolor, char *fgcolor, long evtmask)
{
unsigned long bgc, fgc;
XClassHint *ch;
XSizeHints *sh;
if (! (xv.d = XOpenDisplay(NULL))) {
fprintf(stderr, "xinit(): Error opening display\n");
exit(1);
}
atexit(cleanup);
xv.s = DefaultScreen(xv.d);
xv.v = DefaultVisual(xv.d, xv.s);
xv.depth = DefaultDepth(xv.d, xv.s);
xv.cmap = DefaultColormap(xv.d, xv.s);
xv.x = x; xv.y = y;
xv.dwidth = DisplayWidth(xv.d, xv.s);
xv.dheight = DisplayHeight(xv.d, xv.s);
xv.width = (width == 0 ? xv.dwidth : width);
xv.height = (height == 0 ? xv.dheight : height);
xv.bwidth = xv.twidth = 0;
if ((xv.v->class != TrueColor) || (xv.depth != 16 && xv.depth != 24)) {
fprintf(stderr, "xinit(): Unsupported visual\n");
exit(1);
}
xv.sig = 0;
signal(SIGHUP, sighandler);
signal(SIGINT, sighandler);
signal(SIGTERM, sighandler);
initcolors();
bgc = getnamedcolor(bgcolor, NULL); fgc = getnamedcolor(fgcolor, NULL);
xv.w = XCreateSimpleWindow(xv.d, DefaultRootWindow(xv.d), xv.x, xv.y,
xv.width, xv.height, 0, fgc, bgc);
XSelectInput(xv.d, xv.w, StructureNotifyMask | ExposureMask |
KeyPressMask | KeyReleaseMask | evtmask);
xv.pmap = mkpixmap(resizable ? xv.dwidth : xv.width,
resizable ? xv.dheight : xv.height, xv.depth);
xv.gc = XCreateGC(xv.d, xv.pmap, 0, NULL);
ch = XAllocClassHint();
ch->res_name = appname;
ch->res_class = classname;
XSetClassHint(xv.d, xv.w, ch);
settitle(winname);
sh = XAllocSizeHints();
sh->flags = USPosition | USSize | PMaxSize | (resizable ? 0 : PMinSize);
sh->x = xv.x; sh->y = xv.y; sh->width = xv.width; sh->height = xv.height;
if (resizable) {
sh->max_width = xv.dwidth; sh->max_height = xv.dheight;
} else {
sh->min_width = sh->max_width = xv.width;
sh->min_height = sh->max_height = xv.height;
}
XSetWMNormalHints(xv.d, xv.w, sh);
wm_protocols = XInternAtom(xv.d, "WM_PROTOCOLS", False);
wm_delete_window = XInternAtom(xv.d, "WM_DELETE_WINDOW", False);
XSetWMProtocols(xv.d, xv.w, &wm_delete_window, 1);
XMapWindow(xv.d, xv.w);
}
int getevent(XEvent *event)
{
XEvent e;
if (xv.sig) exit(0);
if (! XPending(xv.d))
return 0;
XNextEvent(xv.d, &e);
switch (e.type) {
case ReparentNotify:
{
Window rootw, parentw = xv.w, currentw, child, *children;
int nchildren;
int x1, y1, x2, y2;
XTranslateCoordinates(xv.d, xv.w, DefaultRootWindow(xv.d),
0, 0, &x1, &y1, &child);
do {
currentw = parentw;
XQueryTree(xv.d, currentw, &rootw, &parentw, &children,
&nchildren);
XFree(children);
} while (parentw != rootw);
XTranslateCoordinates(xv.d, currentw, DefaultRootWindow(xv.d),
0, 0, &x2, &y2, &child);
xv.bwidth = x1 - x2; xv.twidth = y1 - y2;
}
break;
case ConfigureNotify:
{
XConfigureEvent *ce = (XConfigureEvent *)&e;
Window child;
XTranslateCoordinates(xv.d, xv.w, DefaultRootWindow(xv.d),
0, 0, &xv.x, &xv.y, &child);
xv.width = ce->width; xv.height = ce->height;
}
break;
case ClientMessage:
if (e.xclient.message_type == wm_protocols &&
e.xclient.data.l[0] == wm_delete_window)
exit(0);
break;
}
*event = e;
return 1;
}
void doexpose(XEvent *event)
{
for (;;) {
XExposeEvent *ee = (XExposeEvent *)event;
update(ee->x, ee->y, ee->width, ee->height);
if (! ee->count)
break;
XNextEvent(xv.d, event);
}
}
void update(int x, int y, int width, int height)
{
if (x == 0 && y == 0 && width == 0 && height == 0) {
width = xv.width;
height = xv.height;
}
XSync(xv.d, False);
XCopyArea(xv.d, xv.pmap, xv.w, xv.gc, x, y, width, height, x, y);
XSync(xv.d, False);
}