/* xwm.c 
 *   by Nathan Laredo (l a r e d o a t g n u d o t o r g)
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <X11/Xlib.h>

typedef struct {
	char *name;
	void *data;
} opt_t;

Display *mydisplay;
Window mywindow;
XWindowAttributes myattrib;

/* for sending changes */
XSetWindowAttributes xsa;
XWindowChanges xwc;

/* NOTE: everything is treated as an integer */
opt_t attribs[] = {
	{ "x", &myattrib.x },
	{ "y", &myattrib.y },
	{ "width", &myattrib.width },
	{ "height", &myattrib.height },
	{ "border-width", &myattrib.border_width },
	{ "depth", &myattrib.depth },
	{ "visual", &myattrib.visual },
	{ "root", &myattrib.root },
	{ "class", &myattrib.class },
	{ "bit-gravity", &myattrib.bit_gravity },
	{ "backing-store", &myattrib.backing_store },
	{ "backing-planes", &myattrib.backing_planes },
	{ "backing-pixel", &myattrib.backing_pixel },
	{ "save-under", &myattrib.save_under },
	{ "colormap", &myattrib.colormap },
	{ "map-installed", &myattrib.map_installed },
	{ "map-state", &myattrib.map_state },
	{ "all-event-masks", &myattrib.all_event_masks },
	{ "your-event-mask", &myattrib.your_event_mask },
	{ "do-not-propagate-mask", &myattrib.do_not_propagate_mask },
	{ "override-redirect", &myattrib.override_redirect },
	{ "screen", &myattrib.screen },
	{ NULL, NULL }
};

void usage_error(void)
{
	int i;

	fprintf(stderr, "usage: xwm windowid [--attrib-name=value] [...]\n");
	for (i = 0; attribs[i].name; i++)
		fprintf(stderr, "\t--%s=value\n", attribs[i].name);

	exit(1);
}

void handle_opt(char *opt)
{
	char *optval = strchr(opt, '=');
	int i;

	if (opt[0] != '-' || opt[1] != '-' || !optval)
		usage_error();

	*(optval++) = 0;	/* for strcmp */

	for (i = 0; attribs[i].name; i++) {
		if (strcmp(attribs[i].name, &opt[2]) == 0) {
			*(int *) attribs[i].data = strtol(optval, NULL, 0);
			return;
		}
	}
	usage_error();
}

int main(int argc, char **argv)
{
	int i;
	
	if (argc < 2)
		usage_error();

	mywindow = strtol(argv[1], NULL, 0);

	if (!getenv("DISPLAY")) {
		fprintf(stderr, "DISPLAY not set.\n");
		exit(1);
	}
	if (!(mydisplay = XOpenDisplay(getenv("DISPLAY")))) {
		fprintf(stderr, "Unable to open display.\n");
		exit(1);
	}

	/* An error in the following will terminate in libX11 */
	XGetWindowAttributes(mydisplay, mywindow, &myattrib);

	if (argc < 3) {
		fprintf(stderr, "Window 0x%08x current attributes\n",
			(int) mywindow);
		for (i = 0; attribs[i].name; i++)
			fprintf(stderr, "%22s=0x%08x\n", attribs[i].name,
				*(int *) attribs[i].data);
		exit(0);
	}

	for (i = 2; i < argc; i++)
		handle_opt(argv[i]);

	/* translate to set window attribs structure */
	xsa.bit_gravity = myattrib.bit_gravity;
	xsa.win_gravity = myattrib.win_gravity;
	xsa.backing_store = myattrib.backing_store;
	xsa.backing_planes = myattrib.backing_planes;
	xsa.backing_pixel = myattrib.backing_pixel;
	xsa.save_under = myattrib.save_under;
	xsa.do_not_propagate_mask = myattrib.do_not_propagate_mask;
	xsa.override_redirect = myattrib.override_redirect;
	xsa.colormap = myattrib.colormap;

	/* translate to window changes structure */
	xwc.x = myattrib.x;
	xwc.y = myattrib.y;
	xwc.width = myattrib.width;
	xwc.height = myattrib.height;

	/* An error in the following will terminate in libX11 */
	XChangeWindowAttributes(mydisplay, mywindow, CWBitGravity |
		CWWinGravity | CWBackingStore | CWBackingPlanes |
		CWBackingPixel | CWSaveUnder | CWDontPropagate |
		CWOverrideRedirect | CWColormap, &xsa);

	XConfigureWindow(mydisplay, mywindow, CWX | CWY | CWWidth |
		CWHeight | CWBorderWidth, &xwc);

	XSync(mydisplay, False);

	fprintf(stderr, "Window 0x%08x attributes changed\n", (int) mywindow);
	exit(0);
}
