/*
 * win.c
 *
 * do operations on windows
 *
 */

#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/file.h>
#include <X11/Xlib.h>
#include <X11/X10.h>
#include "../defs.h"
#include "win.h"

Display	*display;
int	screen;
XAssocTable	*win_table;
int	border;
XFontStruct *font;
int	no_X;

int
win_init(dp)
	char	*dp;
{
	extern	char *getenv();

	if (dp == 0)
		dp = getenv("DISPLAY");
	if ((display = XOpenDisplay(dp)) == 0) {
		no_X++;
		fprintf(stderr, "cannot open display at %s\n", dp);
		return 0;
	}
	win_table = XCreateAssocTable(8);
	setdefaults();
	printf("opened display\n");
	return 1;
}

/*
 * create the window and add to associated table
 */
struct win *
win_create()
{
	extern	char *index();
	extern	int forePixel;
	extern	int backPixel;
	Window	win;
	char	*p;
	struct	win *wp;
	XGCValues gc_vals;
	u_int	mask;

	if (display == 0 && win_init(0) == 0)
		return 0;
	if ((win = XCreateSimpleWindow(display, DefaultRootWindow(display),
		200, 200, 250, 250, border/2, forePixel, backPixel)) == 0)
		return 0;
	XMapWindow(display, win);
	XSelectInput(display, win, ExposureMask|ButtonPressMask);
	wp = (struct win *) calloc(sizeof(*wp), 1);
	wp->w_win = win;
	XMakeAssoc(display, win_table, win, wp);
	gc_vals.foreground = forePixel;
	gc_vals.background = backPixel;
	gc_vals.function = GXcopy;
	mask = GCForeground | GCBackground | GCFunction;
	wp->w_gc = XCreateGC(display, wp->w_win, mask, &gc_vals);
	gc_vals.foreground = backPixel;
	gc_vals.background = forePixel;
	gc_vals.function = GXcopy;
	wp->w_rev = XCreateGC(display, wp->w_win, mask, &gc_vals);
	return wp;
}

/*
 * destroy window & associated data
 */
win_destroy(wp)
	struct	win *wp;
{
	if (wp == 0)
		return 0;
	printf("Deleting window %d\n", wp->w_win);
	XDeleteAssoc(display, win_table, wp->w_win);
	XUnmapWindow(display, wp->w_win);
	XDestroyWindow(display, wp->w_win);
	if (wp->w_data != 0)
		free(wp->w_data);
	free(wp);
	return 1;
}


/*
 * returns "yes" if the window changed size.
 * if so, the current values are set in the
 * passed window structure.
 */
int
win_resize(wp)
	struct	win *wp;
{
	XWindowAttributes info;

	XGetWindowAttributes(display, wp->w_win, &info);
	if (info.width == wp->w_width && info.height == wp->w_height)
		return 0;
	wp->w_width = info.width;
	wp->w_height = info.height;
	return 1;
}

/*
 * returns a window struct based on a left-mouse input
 * event in a window on our display.  If we get an event,
 * but not in a window we know about, its the same as
 * not getting an event at all.
 */
struct win *
win_leftmouse(prompt)
	char	*prompt;
{
	XButtonEvent event;
	struct	win *wp;

	printf(prompt);
	XMaskEvent(display, ButtonPressMask, &event);
	if (event.button == Button1) {
		wp = (struct win *) XLookUpAssoc(display, win_table,
			event.window);
		if (wp == 0) {
			printf("That window doesn't belong to us!\n");
			return 0;
		}
		return wp;
	}
	printf("aborted\n");
	return 0;
}

/*
 * this routine processes all X events that have been
 * waiting in the soft queue or at the socket level.
 * It returns immediately if no events are waiting.
 */
win_events()
{
	extern	XAssocTable *win_table;
	int	nevents;
	int	nbytes;
	XEvent	event;
	struct	win *wp;

	if (display == 0)
		return;
	nevents = XPending(display);
	if (nevents <= 0) {
		if (ioctl(display->fd, FIONREAD, &nbytes) < 0) {
			perror("X display socket ioctl FIONREAD");
			return;
		}
		if (nbytes <= 0)
			return;
		XNextEvent(display, &event);
		nevents = XPending(display);
	} else {
		XNextEvent(display, &event);
		nevents--;
	}
	while (1) {
		wp = (struct win *) XLookUpAssoc(display, win_table,
			event.xany.window);
		if (wp == 0)
			printf("Orphaned Event for win %d\n",
				event.xany.window);
		else if (wp->w_event == 0)
			printf("No event handler for window %d\n",
				event.xany.window);
		else {
			wp->w_event(&event, wp);
		}
		if (nevents == 0)
			break;
		nevents--;
		XNextEvent(display, &event);
	}
}
