
/**************************************************************************
 *                                                                        *
 * 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 circle drawing routine
		makes a request thru property of DefaultRootWindow
	    interrupts are trapped to allow a graceful exit.
*/

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

static void sig_trap(int);

extern Display *display;
extern Atom atom_state, actual;
extern int data[PROP_NITEMS];
extern struct s_prop prop;

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



int
int_circle(pcr, pcc, prad)
int *pcr, *pcc, *prad;
{
	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, &actual,
				&(prop.format), &(prop.nitems), &(prop.bytes), 
				(char **) &(prop.data));
		if ((i != Success) || (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 circle, 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_CIRCLE_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, &actual,
				&(prop.format), &(prop.nitems), &(prop.bytes), 
				(char **) &(prop.data));
		/* 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;
	}	

	*pcr = prop.data[2];
	*pcc = prop.data[3];
	*prad = (int)(hypot((double)(prop.data[4]-prop.data[2]),
						(double)(prop.data[5]-prop.data[3])) +0.5);

	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_CIRCLE; all the routine does
	now is set the window state to SHOW_CIRCLE, 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_circle(cr, cc, rad)		/* displays circle on TV */
int cr, cc, rad;				/* on all windows in which it fits */
{
	XEvent event;
	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, &actual,
			&(prop.format), &(prop.nitems), &(prop.bytes), 
			(char **) &(prop.data));
	for (i = 0; i < PROP_NITEMS; i++)
		data[i] = prop.data[i];

	data[1] = STATE_CIRCLE_SHOW;
	data[2] = cr;
	data[3] = cc;
	data[4] = rad;

	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(x)
int x;
{
	int i;

	XGetWindowProperty(display, DefaultRootWindow(display), atom_state,
			(long) 0, (long) PROP_NITEMS, False, XA_INTEGER, &actual,
			&(prop.format), &(prop.nitems), &(prop.bytes), 
			(char **) &(prop.data));

	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);
	printf("\n");
	exit(0);
}
