
/**************************************************************************
 *                                                                        *
 * Copyright (c) 1996 Michael Richmond and Richard Treffers               *
 *                                                                        *
 *                    This software may be copied and distributed for     *
 *                    educational, research and not for profit services   *
 *                    provided that this copyright and statement are      *
 *                    included in all such copies.                        *
 *                                                                        *
 **************************************************************************/


/*	
	interactive box drawing routine
		makes a request thru property of DefaultRootWindow
	    interrupts are trapped to allow a graceful exit.
	4/22/94 - read/set property moved to image1.c
*/

#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include "pcvista.h"
#include "pcvistax.h"

static void sig_trap();

static Display *display;
Atom atom_state, atom_actual;
static int data[PROP_NITEMS];
static struct s_prop prop;

#define MAX_TRIES 10		/* number of seconds to wait before giving up */
                     		/*   if no image windows are present at first */


	/* returns 0 if all goes well */

int
int_box(psr, psc, pnr, pnc)
int *psr, *psc, *pnr, *pnc;
{
	XEvent event;
	int i, tries;

	if ((display = XOpenDisplay("")) == NULL) {
		fprintf(stderr,"you must be running X-windows");
		exit(1);
	}
	atom_state = XInternAtom(display, ATOM_STATE, False);

	/* try to open communications with the RootWindow.  If there are
	   no windows open, then go into a loop where we wait a second,
	   then try again, up to MAX_TRIES times. */

	/* if the zero-th element of the property is less than 1, then
	   there isn't any window; or, if the property isn't in the NORMAL 
	   or FROZEN states, then we also shouldn't run.  In that case,
	   print an error message and exit; we don't want to conflict
	   with other 'box' or 'cursor' processes. */

	for (tries = 0; tries < MAX_TRIES; tries++) {
		i = XGetWindowProperty(display, DefaultRootWindow(display), atom_state,
				(long) 0, (long) PROP_NITEMS, False, XA_INTEGER, &atom_actual,
				&(prop.format), &(prop.nitems), &(prop.bytes), 
#if XGETUNSIGNED == 1
				(unsigned char **) &(prop.data));
#else
				(char **) &(prop.data));
#endif
		if ((i != Success) || (atom_actual == None)) {
			XCloseDisplay(display);
			error(1, "can't connect with any image window");
		}
		if (prop.data[0] < 1) {
			fprintf(stderr, "no image windows active yet - waiting %2d of %2d\r", tries, MAX_TRIES);
			sleep(1);
		}
		else
			break;
	}
	if (tries == MAX_TRIES) {
		XCloseDisplay(display);
		error(1, "couldn't find any image windows                            ");
	}
	else
		fprintf(stderr, "click and hold Left for center of box, then drag and release \n");
		
	if ((prop.data[1] != STATE_NORMAL) && (prop.data[1] != STATE_FROZEN)) {
		XCloseDisplay(display);
		error(1, "can't run 'box int' now; another process is busy");
	}

	signal(SIGINT, sig_trap);
	signal(SIGQUIT, sig_trap);
	signal(SIGTERM, sig_trap);

	for (i = 0; i < PROP_NITEMS; i++) 
		data[i] = prop.data[i];	
	data[1] = STATE_BOX_CENTER;
	XChangeProperty(display, DefaultRootWindow(display), atom_state,
			XA_INTEGER, PROP_FORMAT, PropModeReplace, 
			(unsigned char *) data, PROP_NITEMS);

	/* go into a loop in which we wait for the ATOM_STATE property of
	   the DefaultRootWindow to be changed by the image. ignore
	   all properties which do not have STATE_COMMUNICATE. 
	   use the values from the property to find the cr, cc, sr, sc of the 
	   selected box.  Then, change the property value [1] to NORMAL
	   to signal that we've read x, y, etc. correctly.  */

	XSelectInput(display, DefaultRootWindow(display), PropertyChangeMask);
	while (1) {
		XNextEvent(display, &event);
		if (event.type != PropertyNotify)
			error(1, "box process received wrong X event type");
		XGetWindowProperty(display, DefaultRootWindow(display), atom_state,
				(long) 0, (long) PROP_NITEMS, False, XA_INTEGER, &atom_actual,
				&(prop.format), &(prop.nitems), &(prop.bytes), 
#if XGETUNSIGNED == 1
			(unsigned char **) &(prop.data));
#else
			(char **) &(prop.data));
#endif
		/* the returned information is cr, cc, sr, sc (or er, ec) */
		if (prop.nitems != PROP_NITEMS)
			error(1, "box process receives wrong number of property items");
		if (prop.data[1] == STATE_COMMUNICATE)
			break;
	}	

	*pnr = 2*abs(prop.data[4] - prop.data[2]);
	*pnc = 2*abs(prop.data[5] - prop.data[3]);
	*psr = prop.data[2] - *pnr/2;
	*psc = prop.data[3] - *pnc/2;

	for (i = 0; i < PROP_NITEMS; i++)
		data[i] = prop.data[i];
	data[1] = STATE_NORMAL;
	XChangeProperty(display, DefaultRootWindow(display), atom_state, 
			XA_INTEGER, PROP_FORMAT, PropModeReplace, (unsigned char *) data,
			PROP_NITEMS);

	XCloseDisplay(display);

	return (0);
}

/*	causes the box to appear on the tv screen.  There is no good way to make
	sure that all windows receive the signal SHOW_BOX; all the routine does
	now is set the window state to SHOW_BOX, wait for a few seconds, and then
	re-set the window_state to NORMAL.  I hope it works out in practice..
	         - MWR 10/1/91
*/

#define NAPTIME     2

int
show_box(sr, sc, er, ec)		/* displays box on TV */
int sr, sc, er, ec;				/* on all windows in which it fits */
{
	int i;

	if ((display = XOpenDisplay("")) == NULL) {
		fprintf(stderr,"you must be running X-windows");
		exit(1);
	}
	atom_state = XInternAtom(display, ATOM_STATE, False);
	XGetWindowProperty(display, DefaultRootWindow(display), atom_state,
			(long) 0, (long) PROP_NITEMS, False, XA_INTEGER, &atom_actual,
			&(prop.format), &(prop.nitems), &(prop.bytes), 
#if XGETUNSIGNED == 1
			(unsigned char **) &(prop.data));
#else
			(char **) &(prop.data));
#endif
	for (i = 0; i < PROP_NITEMS; i++)
		data[i] = prop.data[i];

	data[1] = STATE_BOX_SHOW;
	data[2] = sr;
	data[3] = sc;
	data[4] = er;
	data[5] = ec;

	signal(SIGINT, sig_trap);
	signal(SIGQUIT, sig_trap);
	signal(SIGTERM, sig_trap);

	XChangeProperty(display, DefaultRootWindow(display), atom_state,
			XA_INTEGER, PROP_FORMAT, PropModeReplace, 
			(unsigned char *) data, PROP_NITEMS);
	XFlush(display);

	sleep(NAPTIME);

	data[1] = STATE_NORMAL;
	for (i = 2; i < PROP_NITEMS; i++)
		data[i] = 0;
	XChangeProperty(display, DefaultRootWindow(display), atom_state,
			XA_INTEGER, PROP_FORMAT, PropModeReplace, 
			(unsigned char *) data, PROP_NITEMS);

	XCloseDisplay(display);

	return(0);
}

	/* change the property back to NORMAL so that image windows don't 
	   wait forever for ackowledgment. */

static void
sig_trap()
{
	int i;

	XGetWindowProperty(display, DefaultRootWindow(display), atom_state,
			(long) 0, (long) PROP_NITEMS, False, XA_INTEGER, &atom_actual,
			&(prop.format), &(prop.nitems), &(prop.bytes), 
#if XGETUNSIGNED == 1
			(unsigned char **) &(prop.data));
#else
			(char **) &(prop.data));
#endif

	for (i = 0; i < PROP_NITEMS; i++)
		data[i] = prop.data[i];
	data[1] = STATE_NORMAL;

	XChangeProperty(display, DefaultRootWindow(display), atom_state,
			XA_INTEGER, PROP_FORMAT, PropModeReplace, 
			(unsigned char *) data, PROP_NITEMS);

	XCloseDisplay(display);
	exit(0);
}
