/* draw in a window, get x events, etc. -- example code.
 * brg Wed Jan 19 03:30:32 PST 2000
 * 
 * gcc -Wall -o foo foo.c -L/usr/X11R6/lib -lX11
 */

#include <stdio.h>
#include <stdlib.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>

#define PROGNAME "H0ZERwind"

Display *disp;
int screenNum;

GC createGC(Window wind)
{
	long valuemask;
	XGCValues gcvalues;

	valuemask = GCFunction | GCPlaneMask | GCForeground | GCBackground |
		GCLineWidth | GCLineStyle | GCCapStyle | GCJoinStyle | GCFillStyle |
		GCFillRule | GCArcMode;

	gcvalues.function = GXcopy;
	gcvalues.plane_mask = AllPlanes;
	gcvalues.foreground = BlackPixel(disp, screenNum);
	gcvalues.background = WhitePixel(disp, screenNum);
	gcvalues.line_width = 2;
	gcvalues.line_style = LineSolid;
	gcvalues.cap_style = CapButt; /* buttbutt? */
	gcvalues.join_style = JoinRound;
	gcvalues.fill_style = FillSolid;
	gcvalues.fill_rule = EvenOddRule;
	gcvalues.arc_mode = ArcChord;

	return XCreateGC(disp, wind, valuemask, &gcvalues);
}

Window createWindow(int width, int height)
{
	long valuemask;
	XSetWindowAttributes attrs;
	Window wind;

	attrs.background_pixmap = None;
	attrs.background_pixel = WhitePixel(disp, screenNum);
	attrs.border_pixmap = CopyFromParent;
	attrs.border_pixel = 0;
	attrs.bit_gravity = ForgetGravity;
	attrs.win_gravity = ForgetGravity;
	attrs.backing_store = Always;
	attrs.backing_planes = 0;
	attrs.backing_pixel = 0;
	attrs.save_under = False;
	attrs.event_mask = 0;
	attrs.do_not_propagate_mask = 0;
	attrs.override_redirect = False;
	attrs.colormap = None;
	attrs.cursor = None;
	valuemask = CWBackPixel | CWBorderPixel | CWBackingStore;
	wind = XCreateWindow(disp,       /* display */
			DefaultRootWindow(disp), /* parent */
			0,0,                     /* x, y */
			width,height,            /* width, height */
			CopyFromParent,          /* border_width */
			CopyFromParent,          /* depth */
			InputOutput,             /* class */
			CopyFromParent,          /* visual */
			valuemask,               /* valuemask */
			&attrs);                 /* attributes */
	return wind;
}

void setWindowProperties(Window wind, char *name, int argc, char **argv)
{
	char *window_name = name;
	char *icon_name = name;
    XTextProperty windowNameProperty, iconNameProperty;
	XWMHints wmhints;
	XClassHint classhints;

    XStringListToTextProperty(&window_name, 1, &windowNameProperty);
    XStringListToTextProperty(&icon_name, 1, &iconNameProperty);
	wmhints.flags = InputHint | StateHint;
	wmhints.input = True;
	wmhints.initial_state = NormalState;
	classhints.res_name = argv[0];
	classhints.res_class = name;

    XSetWMProperties(disp, wind, &windowNameProperty, &iconNameProperty,
    	argv, argc, NULL, &wmhints, &classhints);
}

void initXDisplay(void)
{
	disp = XOpenDisplay(NULL);
	if (!disp) {
		fprintf(stderr, "Error: can't open display: %s\n",
			getenv("DISPLAY") ? getenv("DISPLAY") : ""); 
		exit(1);
	}
	screenNum = DefaultScreen(disp);
}

int main(int argc, char **argv)
{
	Window wind;
	XEvent event;
	const long event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask |
		ButtonReleaseMask | EnterWindowMask | LeaveWindowMask;
	Bool done = False;
	GC gc;

	initXDisplay();
	wind = createWindow(640, 480);
	setWindowProperties(wind, PROGNAME, argc, argv);
	XMapWindow(disp, wind);
	gc = createGC(wind);

    XSelectInput(disp, wind, KeyPressMask | ButtonPressMask |
		ButtonReleaseMask);
    while (!done) {
		KeyCode c;
		int oldx=-1,newx,oldy=-1,newy;
		char ch;
		XWindowEvent(disp, wind, event_mask, &event);
		printf("type=%d serial=%lu send=%s\t[", event.type,event.xany.serial,
			event.xany.send_event ? "True" : "False");
		switch (event.xany.type) {
			case KeyPress: c = event.xkey.keycode;
				ch = ((int)XKeycodeToKeysym(disp,c,0) & 0xff);
				printf("KeyPress[%x:%c]",(int)XKeycodeToKeysym(disp,c,0),ch);
				if (ch=='q') done=True;
				break; 
			case ButtonPress: printf("ButtonPress");
				newx=event.xbutton.x;
				newy=event.xbutton.y;
				if (oldx!=-1) {
					XDrawLine(disp, wind, gc, oldx, oldy, newx, newy);
				}
				oldx=newx; oldy=newy;
				break; 
			case ButtonRelease: printf("ButtonRelease"); break;
			default: break;
		}
		printf("(%d)]\n", event.type);
	}

	XFreeGC(disp, gc);
	XUnmapWindow(disp, wind);
	XDestroyWindow(disp, wind);
	XCloseDisplay(disp);
	return 0;
}
