/*

JAN-1993  J. Snyder	XTEK code modified into callable Motif-based interface.
			GIN (Graphics INput) mode support added.
			Foreground/Background color support added.

FEB-1993  J. Snyder	Added unsolicited input capability.

JUL-1993  R. Richmond	Modified to accept Tektronix 4105 commands
			Fixed "dot connecting" bug
MAY-2000  D. Ernst      modified to disable beep on every plot

*/

#define xtc_module 2


#include "xtek41.h"

static void callbackDrawingArea();
static void handlerFocus();
static void handlerWindow();
static void handlerKeyPress();
static void handlerButtonPress();
static void check_cursor();
static void set_got_gin();
void color_tek_window();
void dash_color(int color);
int set41_color(int color);
extern void return_gin_bytes();
extern void draw_adj_frame();


static int decode_int();
void xy_param();
void mov_down();
void mov_right();

#define POINT 1
#define LINE  2
#define LABEL 3
#define POLY  4

struct point  {
	short x,y;
	};

struct line  {
	short x1, y1, x2, y2;
	};

struct label  {
	short x,y;
	short len;
	char *value;
	};

/*
 * So we can re-display (eg. after an exposure event) we keep
 * all drawn objects on a linked list with head obp and tail lastobj
 */

struct object  {
	struct object *next;
	int type;
	int igc_line;
	int igc_text;
	int igc_panel;
	union  {
		struct point point;
		struct line line;
		struct label label;
		} obj;
	} *obp, *lastobj;

/*
 * syntactic shortcuts
 */

#define PTx obj.point.x
#define PTy obj.point.y
#define LNx1 obj.line.x1
#define LNx2 obj.line.x2
#define LNy1 obj.line.y1
#define LNy2 obj.line.y2
#define LBx obj.label.x
#define LBy obj.label.y
#define LBval obj.label.value
#define LBlen obj.label.len

char *wname = "XTEK";
int Wheight, Wwidth;
int Wxpos, Wypos;
Display *Wdpy;
int dpyht, dpywd;
long Wscr;
Visual *Wvis;
GC Wgc[8];
Colormap colormap;

XGCValues Wgcv =  {
	GXcopy,
	AllPlanes,
	1,
	0,
	1,
	LineSolid,
	CapButt,
	JoinMiter,
	FillSolid,
	EvenOddRule,
	ArcPieSlice,
	NULL,
	NULL,
	0,
	0,
	NULL,
	ClipByChildren,
	TRUE,
	0,
	0,
	NULL,
	0,
	'\0'
	};

unsigned long Wgcvmask =
	GCFunction|
	GCPlaneMask|
	GCForeground|
	GCBackground|
	GCLineWidth|
	GCLineStyle|
	GCFillStyle|
	GCFillRule|
	GCFont|
	GCSubwindowMode|
	GCGraphicsExposures;


XSetWindowAttributes Wxswa = 
	{
	None,				/* background pixmap +		*/
	0,				/* background pixel  +		*/
	None,				/* border pixmap +		*/
	0,				/* border pixel  +		*/
	ForgetGravity,			/* bit gravity			*/
	ForgetGravity,			/* window gravity		*/
	NotUseful,			/* backing store		*/
	0,				/* backing planes +		*/
	0,				/* backing pixel  +		*/
	FALSE,				/* save under			*/
	0,				/* event mask (to be saved)	*/
	0,				/* do not propagate mask	*/
	FALSE,				/* override redirect		*/
	NULL,				/* color map			*/
	NULL,				/* cursor			*/
	};

unsigned long Wxswamask = CWBackPixel|CWBorderPixel;

XWMHints Wxshints = 
	{
	InputHint,	/* specified-p mask */
	0	/* Nay, do not give us the input focus */
	};
			
int Wborder = 1;
int Wvmask;
int Wclass = InputOutput;
int Wfg, Wbg, Wdepth;
XID Wroot;

char *Wfontname = "fixed";
Font Wfont;
XFontStruct *Wfontp;
int Wchar_height, Wchar_width;
XID w;

int	oldmode, mode=ALPHA;
int	nesc;
char	escs[100];	/* escape sequence buffer */
int	cx=0, cy=YDIM-CHUGEY;
int	tsizex=CHUGEX, tsizey=CHUGEY;
int	leftmargin=0;
float	angle=0.;
int	HiX=0, LoX=0, BX=0;
int	HiY=0, LoY=0, BY=0;
int	ncx,ncy;
int	num_vector = (-1);
int	gotLoX=FALSE, gotLoY=FALSE;
int	beamon;
int	debug=FALSE;
int	panelclr=0;
int	rgb_all=(-1);	/* color override */

int got_focus = 0;
int got_window = 0;
int got_gin = 0;
int cursor_flag = 0;

int colortype;
int igc_line;
int igc_text;
int igc_panel;
int	font_num = (-1);
int	xsize[4] = {CHUGEX, CLARGEX, CMEDX, CSMALLX};
int	ysize[4] = {CHUGEY, CLARGEY, CMEDY, CSMALLY};
double  scale_factor=1.0;
int	linestyle = (-1);
unsigned long pixels[9];
int rocurrent[9];
struct point poly[12];
int npoly;
int c2 = 0;

/*===========================================================================*/

void create_tek_window(Display *display, Widget wdraw_in)  {

	Dimension get_width, get_height;
	int i;

	Wdpy = display;
	Wscr = DefaultScreen(Wdpy);
	dpyht = DisplayHeight(Wdpy,Wscr);
	dpywd = DisplayWidth(Wdpy,Wscr);
	colormap = DefaultColormap(Wdpy,Wscr);
	Wheight = dpyht/2;
	Wwidth = dpywd/2;
	Wxpos = dpywd/4;
	Wypos = dpyht/4;
	Wroot = RootWindow(Wdpy,Wscr);
	Wvis = DefaultVisual(Wdpy,Wscr);
	Wfg = BlackPixel(Wdpy,Wscr);
	Wbg = WhitePixel(Wdpy,Wscr);
	Wgcv.foreground = Wfg;
	Wgcv.background = Wbg;
	Wxswa.border_pixel = Wfg;
	Wxswa.background_pixel = Wbg;
	Wdepth = DefaultDepth(Wdpy,Wscr);
	Wfont = XLoadFont(Wdpy,Wfontname);
	Wgcv.font = Wfont;
	Wfontp = XQueryFont(Wdpy,Wfont);
	Wchar_height = Wfontp->max_bounds.width;
	Wchar_width = Wfontp->ascent+Wfontp->descent;
	Wxswa.border_pixel = Wfg;
	Wxswa.background_pixel = Wbg;

	wdraw = wdraw_in;

	XtAddCallback(wdraw, XmNexposeCallback, callbackDrawingArea, 10);
	XtAddCallback(wdraw, XmNresizeCallback, callbackDrawingArea, 20);

	w = XtWindow(wdraw);

	create_gcs();
	color_init();
	color_tek_window( 8, 255, 255, 255 );	/* white background */
	for (i = 0; i < 8; i++)
	    color_tek_window( i, 0, 0, 0 );	/* black + 7 colors foreground */
	igc_line = 0;
	igc_text = 0;
	igc_panel = 0;

	XChangeProperty(Wdpy,w,XA_WM_NAME,XA_STRING,8,PropModeReplace,
			 wname,strlen(wname));
	XSetWMHints(Wdpy,w,&Wxshints);

	cursor = XCreateFontCursor( Wdpy, XC_crosshair);

	nargs = 0;
	XtSetArg( args[nargs], XmNwidth,  &get_width); nargs++;
	XtSetArg( args[nargs], XmNheight, &get_height); nargs++;
	XtGetValues( wdraw, args, nargs );
	Wwidth = get_width;
	Wheight = get_height;

	XtAddEventHandler(wdraw, FocusChangeMask, FALSE, handlerFocus,    0);
	XtAddEventHandler(wdraw, EnterWindowMask, FALSE, handlerWindow,   0);
	XtAddEventHandler(wdraw, LeaveWindowMask, FALSE, handlerWindow,   0);
	XtAddEventHandler(wdraw, KeyPressMask,    FALSE, handlerKeyPress, 0);
	XtAddEventHandler(wdraw, ButtonPressMask, FALSE, handlerButtonPress,0);

	}

void xy_param(int c)  {

    if( (char) c < '@') {	/* High byte */
	if (gotLoY) {/* must be HiX */
	    HiX = ((char) c & 0x1f) << 7;
	} else {	/* must be HiY */
	    HiY = ((char) c & 0x1f) << 7;
	}
    } else if ( (char) c < '`') {/* Lo X: plot */
	gotLoY = FALSE;
	gotLoX = TRUE;
	LoX = (c & 0x1f) << 2;
	/* now actually do a plot */
	if (num_vector < 0) {
	    num_vector = 0;
	    cx = HiX + LoX + BX;
	    cy = HiY + LoY + BY;
	    xtek_moveto(cx,cy);
	    if (mode==CMD41) {
		poly[npoly].x=transl_x(cx);
		poly[npoly].y=transl_y(cy);
	    }
	} else {	/* draw the line */
	    cx = HiX + LoX + BX;
	    cy = HiY + LoY + BY;
	    if ((mode==GRAPH)||(mode==CMD41)) {
		xtek_lineto(cx,cy);
		if (mode==CMD41) {
		    npoly++;
		    poly[npoly].x=transl_x(cx);
		    poly[npoly].y=transl_y(cy);
		}
	    } else {/* mode == PTPLT */
		xtek_mtarc(cx,cy);
	    }
	}
    } else {/* Lo Y or extra byte */
	if (gotLoY) {	/* previous LoY => extra byte */
	    BX = (LoY & 0x0c) >> 2;
	    BY = (LoY & 0x30) >> 4;
	    LoY = (c & 0x1f) << 2;
	} else {	/* assume is LoY */
	    LoY = (c & 0x1f) << 2;
	    gotLoY = TRUE;
	}
    }

}/* ends xy_param */

/* Move text cursor to next line */
void mov_down()  {

    if((cy -= tsizey) < 0) {
	cy = YDIM - tsizey;
	leftmargin = leftmargin ? 0 : XDIM/2;
    }
    cx = leftmargin;
}

/* Move text cursor after outputting a character */
void mov_right()  {

    if (angle==0.) {		/* horizontal output */
	if ((cx += tsizex) > XDIM) mov_down();

    } else {		/* vertical output, angle = 90 */
	if ((cy -= tsizey) < 0) {
	/* new row */
	if ((cx += tsizex) > XDIM ) {
	    cx=leftmargin;
	    leftmargin = leftmargin ? 0: XDIM/2;
	}
	cy=tsizey;
	}
    }
}

int iscontrol(int c)  {
    int isctrl;

    isctrl = FALSE;
    switch (c) {	/* test for control character */
	case ( HT ):
	case ( SPACE ):
	    xtek_char(c,cx,cy);
	    mov_right();
	    isctrl = TRUE;
	    break;

	case ( CR ):
	case ( LF ):
	    mov_down();
	    isctrl = TRUE;
	    break;

	case ( BS ):
	    if ((cx -= tsizex) < 0) cx = XDIM;
	    isctrl = TRUE;
	    break;

	case ( VT ):
	    if ((cy += tsizey) > YDIM) cy = 0;
	    isctrl = TRUE;
	    break;

	case ( FF ):/* erase */
	    xtek_showpage();
	    plotx_clear();
	    cx = 0; cy = YDIM - tsizey;
	    igc_line = 0;
	    igc_text = 0;
	    igc_panel = 0;
	    plotx_clear();
	    break;

	case ( BEL ):
	    plotx_bell();
	    isctrl = TRUE;
	    break;

	case ( SYN ):/* padding character, ignore*/
	case ( NUL ):/* padding character, ignore*/
	    isctrl = TRUE;

	    break;

    }/* end of test for control char */
    return(isctrl);
}

int decode_int(char **bufp)  {

    int intval=0;

    while (**bufp & 0x40) {	/* if 0x40 then high order digit */
	intval <<= 6;		/* 0x40 */
	intval += **bufp & 0x3f;	/* add in new digit */
	(*bufp)++;
	}
    intval <<= 4;		/* low order digit */
    intval += **bufp & 0x0f;
    if ( (**bufp&0x10)==0 )	/* 0x10 set for positive numbers */
	intval *= (-1);
    (*bufp)++;
    return(intval);
}

/* Graphics mode */
void setfont (int newfont)  {

/* if (newfont != font_num) ... */
    tsizex = xsize[newfont];
    tsizey = ysize[newfont];
    font_num = newfont;
}


void write_tek_window(unsigned char buffer[], int nbytes)  {

int	i;
int	c,c2;
int	lenstr;
int	power;
int	visi,color;
int	height,width;
int	drawbound;
int	linewidth=0;
int	vectype;
char	*bufp;

for (i = 0; i < nbytes; i++) {
    c = (int) buffer[i];

    switch (mode) {
    case ALPHA:		/* start of ALPHA mode */
	if (isgraph((char) c)) {
			/* normal printing char */
	    xtek_char(c,cx,cy);
	    mov_right();
	    break;
	}
	if (iscontrol( c ))	/* print control char */
	    break;

	switch (c) {		/* tek control char */
	case ( GS ):
	    mode = GRAPH;
	    num_vector = -1;
	    break;

	case ( RS ):
	    mode = INCRE;
	    break;

	case ( FS ):
	    mode = PTPLT;
	    break;

	case ( US ):	/* put in ALPHA mode, already there */
	    break;

	case ( ESC ):
	    oldmode = ALPHA;
	    mode = LCEMD;
	    break;

	default :
	    if (debug)
		fprintf(stderr, "Unknown ALPHA mode character 0x%02x\n", c);
	}	/* end of tek control chars in ALPHA mode */
	break;	/* end of ALPHA mode */

    case PTPLT:
    case GRAPH:		/* start of GRAPH mode */
	if ( (char) c > US ) {	/* first, handle vector case */
	    xy_param(c);
	    break;
	}
				/* non-vector characters */
	switch ( c ) {
	case ( NUL ):	/* padding */
	case ( SYN ):	/* padding */
	    break;

	case ( BEL ):
	    plotx_bell();
	    break;

	case ( LF ):
	    cy -= tsizey;
	    xtek_moveto(cx,cy);
	    break;

	case ( CR ):
	    mode = ALPHA;
	    leftmargin = 0;
	    break;

	case ( RS ):
	    mode = INCRE;
	    break;

	case ( FS ):
	    if (debug)
		fprintf(stderr,"special point plot not implemented\n");
	    mode = PTPLT;
	    break;

	case ( GS ):
	    num_vector = -1;
	    break;

	case ( US ):
	    mode = ALPHA;
	    break;

	case ( ESC ):
	    mode = LCEMD;
	    break;

	default :
	    if (debug)
		fprintf(stderr, "Unknown GRAPH mode character 0x%02x\n", c);
	}/* end of switch on non-vector char in GRAPH mode */

	oldmode = GRAPH;
	break;	/* end of GRAPH mode */

    case INCRE:
	/* could do with bit masking and check for control, */
	/* but this is is simpler. (Let the compiler work). */
	switch ( c ) {
	case ( 32 ):
	    xtek_moveto(cx,cy);
	    beamon = FALSE;
	    break;

	case ( 80 ):
	    xtek_moveto(cx,cy);
	    beamon = TRUE;
	    break;

	case ( 68 ):	/* N */
	    if (++cy > YDIM) cy = YDIM;
	    if (beamon) xtek_lineto(cx,cy);
	    break;

	case ( 69 ):	/* NE */
	    if (++cy > YDIM) cy = YDIM;
	    if (++cx > XDIM) cx = XDIM;
	    if (beamon) xtek_lineto(cx,cy);
	    break;

	case ( 65 ):	/* E */
	    if (++cx > XDIM) cx = XDIM;
	    if (beamon) xtek_lineto(cx,cy);
	    break;

	case ( 73 ):	/* SE */
	    if (--cy < 0) cy = 0;
	    if (++cx > XDIM) cx = XDIM;
	    if (beamon) xtek_lineto(cx,cy);
	    break;

	case ( 72 ):	/* S */
	    if (--cy < 0) cy = 0;
	    if (beamon) xtek_lineto(cx,cy);
	    break;

	case ( 74 ):	/* SW */
	    if (--cy < 0) cy = 0;
	    if (--cx < 0) cx = 0;
	    if (beamon) xtek_lineto(cx,cy);
	    break;

	case ( 66 ):	/* W */
	    if (--cx < 0) cx = 0;
	    if (beamon) xtek_lineto(cx,cy);
	    break;

	case ( 70 ):	/* NW */
	    if (++cy > YDIM) cy = YDIM;
	    if (--cx < 0) cx = 0;
	    if (beamon) xtek_lineto(cx,cy);
	    break;

	case ( ESC ):
	    if (beamon) xtek_moveto(cx,cy);
	    oldmode = INCRE;
	    mode = LCEMD;
	    break;

	case ( FS ):
	    if (beamon) xtek_moveto(cx,cy);
	    mode = PTPLT;
	    break;

	case ( GS ):
	    if (beamon) xtek_moveto(cx,cy);
	    mode = GRAPH;
	    num_vector = -1;
	    break;

	case ( RS ):
	    break;

	case ( US ):
	    if (beamon) xtek_moveto(cx,cy);
	    mode = ALPHA;
	    break;

	default:
	    if (debug)
		fprintf(stderr,"Unknown incremental mode character 0x%02x\n", c);
	}	/* end of INCR switch */

	break;	/* end of INCREmental mode */

    case LCEMD:		/* start of LCEMD mode - 4014 escape mode */
	if ((c=='%') || ((c>='A') && (c<='Z'))) {
	    nesc=1;		/* 4105 command <ESC>aa */
	    escs[0]=c;
	    c2 = 0;
	    mode=CMD41;
	    break;
	}

	if (iscontrol( c )) {
	    mode = ALPHA;

	} else if ((c > 95) && (c < 117)) {
	    if ((char) c & 0x08)	/* set Z axis = linewidth */
		linewidth = 1;
	    else
		linewidth = 0;
	    /* setlinewidth(linewidth, widthscale) */

	    vectype = c & 0x07;		/* set vector type */
	    /* if (linestyle >= 0) vectype = linestyle; */
	    if (vectype > 7) vectype = 7;
	    dash_color(vectype);

	} else if ( (c>='8') && (c<=';') ) {	/* 8,9,:,; */
	    setfont ( c - (int)'8');

	} else {

	switch ( c ) {
	case ( GS ):
		mode = GRAPH;
		num_vector = -1;
		break;

	case ( LF ):
	case ( CR ):
	case ( DEL ):
		break;

	case ( ESC ):
	    i--;
		/* ungetc( (char) ESC, infile); */
		break;

	case ( ETB ):	/* make copy: print & start new page */
		xtek_showpage();
		plotx_clear();
		cx = 0; cy = YDIM - tsizey;
		break;

	case ( SO ):
	case ( SI ):
		if (debug)
		fprintf(stderr, "No alternate character set implemented\n");
		break;

	case ( CAN ):
	case ( SUB ):
		set_got_gin( TRUE );
		break;

	case ( ENQ ):
		if (debug)
		fprintf(stderr, "BYPASS  mode not implemented\n");
		break;

	case ( '?' ):
		/* ungetc( (char) DEL, infile); */
		break;

	default :
		if (debug)
		fprintf(stderr, "Unknown LCE mode character 0x%02x ignored\n", c);
	    }		/* end of LCE mode switch */
	}
	if (mode==LCEMD) mode = oldmode;
	break;		/* end of LCEMD case */

    case CMD41:
	if ( (escs[0]=='M') && (c>95) ) {	/* embedded ML command */
	    i--;
	    /* ungetc( (char) c, infile); */
	    num_vector = 0;
	    mode = GRAPH;
	    c = 0;
	}

	if (c >=' ' ){
	    if (nesc >= 100) {
		fprintf(stderr, "CMD41 buffer overflow\n");
		exit(1);
	    }
	    escs[nesc++]=c;
	    break;
	}

	c2= escs[0]<<8 | escs[1];

	bufp = &escs[2];
	switch (c2){
	case ('L'<<8 | 'T'):	/* Graphic-Text */
	    if (font_num < 0)
		setfont(0);	/* default size */
	    lenstr = decode_int(&bufp);
	    if (angle!=0.) {
		/* angle = 90 (written vertically) */
		/* no vertical fonts yet */
		cy += lenstr*tsizex;
		cx -= tsizey*3/2;
	    }
	    escs[nesc+1]=0;
	    while (bufp < &escs[nesc]) {
		xtek_char(*bufp++,cx,cy);
		mov_right();
	    }
	    break;

	case ('L'<<8 | 'P'):	/* Begin-Panel-Boundary */

	    if (c==GS) {	/* ignore GS within panel    */
	        c=0;
	        break;
	    }

	    num_vector = -1;
	    npoly=0;
	    do {
	        xy_param(*bufp++);
	    } while (gotLoX=FALSE);
	    drawbound = decode_int(&bufp);
	    while (bufp < &escs[nesc]) {
	        xy_param(*bufp++);
	    }
	    if ( (poly[npoly].x != poly[0].x) || (poly[npoly].y != poly[0].y) ) {
	        npoly++;		/* close the polygon */
	        poly[npoly].x=(poly[0].x);
	        poly[npoly].y=(poly[0].y);
	    }
	    break;

	case ('L'<<8 | 'E'):	/* End-Panel-Boundary  */
	    plotx_fill(npoly);
	    num_vector = -1;
	    break;

	case ('L'<<8 | 'V'):	/* set visibility */
	    visi = decode_int(&bufp);
	    break;

	case ('M'<<8 | 'R'):	/* Set-Graph-Rotation*/
	    angle = (float)decode_int(&bufp);
	    power = decode_int(&bufp);
	    while (power>0) {
		angle *= 10.;
		power--;
	    }
	    break;

	case ('M'<<8 | 'C'):	/* Set-Graphtext-Size */
	    width = decode_int(&bufp);
	    height = decode_int(&bufp);

	    if ((height>=55) && (height<65)) {	/* 8 case */
	        setfont(0);
	    } else if (height>=45) {	/* 9 case */
	        setfont(1);
	    } else if (height>=30) {	/* : case */
	        setfont(2);
	    } else if (height>=20) {	/* ; case */
	        setfont(3);
	    }
	    break;

	case ('M'<<8 | 'W'):	/* line width */
	    linewidth = decode_int(&bufp);
	    /* setlinewidth(linewidth,widthscale) */
	    break;

	case ('M'<<8 | 'L'):	/* line color */
	    igc_line = set41_color(decode_int(&bufp));
	    break;

	case ('M'<<8 | 'T'):	/* text color */
	    igc_text = set41_color(decode_int(&bufp));
	    break;

	case ('M'<<8 | 'P'):	/* panel color */
	    igc_panel = set41_color(decode_int(&bufp));
	    break;

	case ('%'<<8 |'!'):	/* select code */
	    visi = decode_int(&bufp);
	    if (visi==8) mode=ALPHA;	/* 4105 <-> 4014 */
	    break;

	}		/* end of c2 switch */

	switch(c) {		/* char after 4105 command */
	case ( GS ):
	    mode=GRAPH;
	    num_vector = -1;
	    break;
	case ( US ):
	    mode= ALPHA;
	    break;
	case ( ESC ):
	    mode= LCEMD;
	    break;
	case ( FS ):
	    mode = PTPLT;
	    break;
	}
 
	break;		/* end of CMD41 mode */

    default:
	 if (debug)
		fprintf(stderr, "Unknown major mode %d\n", mode);
    } /* end of mode switch */
    } /* end of main input loop */
    
}	/*end of function */


int tv_x,tv_y;	/* current screen location */
int tv_border = 10;

int transl_xy(int xa,int xb,int ya,int yb,int x)  {
    return((((xa-x)*yb)+((x-xb)*ya))/(xa-xb));
}

int transl_x (int x)  {
    return(transl_xy(0,XDIM,tv_border,tv_width()-tv_border,x));
}

int transl_y (int y)  {
    return(transl_xy(0,YDIM,tv_height()-tv_border,tv_border,y));
}

int untransl_xy(int xa, int xb, int ya, int yb, int x)  {
    return(((x*(xa-xb))-(xa*yb)+(xb*ya))/(ya-yb));
}

void x_to_tek(int xx, int xy, int *tekx, int *teky)  {
    *tekx = untransl_xy(0,XDIM,tv_border,tv_width()-tv_border,xx);
    *teky = untransl_xy(0,YDIM,tv_height()-tv_border,tv_border,xy);
    if (*tekx < 0) *tekx = 0;
    if (*tekx > XDIM) *tekx = XDIM;
    if (*teky < 0) *teky = 0;
    if (*teky > YDIM) *teky = YDIM;
    *tekx = *tekx / 4;
    *teky = *teky / 4;
}

xtek_char(int c, int cx, int cy)  {
    plotx_char(transl_x(cx), transl_y(cy), c);
}


xtek_moveto(int cx, int cy)  {
    tv_x = cx;
    tv_y = cy;
}

xtek_lineto(int cx, int cy)  {
    plotx_line(transl_x(tv_x), transl_y(tv_y),
	transl_x(cx), transl_y(cy));
    tv_x = cx;
    tv_y = cy;
}

xtek_mtarc(int cx, int cy)  {
    plotx_point(transl_x(cx), transl_y(cy) );
    tv_x =cx;
    tv_y =cy;
}

xtek_showpage()  {
    plotx_force_output();
}
 
tv_width()  {
    return(Wwidth);
}

tv_height()  {
    return(Wheight);
}

char *stralloc(char *s)  {
    char *p;
    p = (char *) malloc(strlen(s)+1);
    strcpy(p,s);
    return(p);
}

struct object *NewObj(int type)  {
    register struct object *p;

    p = (struct object *)malloc(sizeof(*p));
#ifdef VMS
    memset(p,0,sizeof(*p));
#else
    bzero(p,sizeof(*p));
#endif
    p->type = type;
    p->igc_line = igc_line;
    p->igc_text = igc_text;
    p->igc_panel = igc_panel;
    return(p);
}

FreeObj()  {
    register struct object *tp;

    while(obp != NULL)
	{
	tp = obp->next;
	if(obp->type == LABEL) free(obp->LBval);
	if(obp->type == POLY ) free(obp->LBval);
	free(obp);
	obp = tp;
	}
    lastobj = obp = NULL;
}

AddObj(struct object *p)  {
    if(obp == NULL)
	obp = p;
    else
	lastobj->next = p;
    lastobj = p;
}

plotx_point(int x, int y) {
    register struct object *p;

    p = NewObj(POINT);
    p->PTx = x;
    p->PTy = y;
    AddObj(p);
    XDrawPoint(Wdpy,w,Wgc[p->igc_line],p->PTx,p->PTy);
    return(1);
}

plotx_line(int x1, int y1, int x2, int y2) {
    register struct object *p;

    p = NewObj(LINE);
    p->LNx1 = x1;
    p->LNx2 = x2;
    p->LNy1 = y1;
    p->LNy2 = y2;
    AddObj(p);
    XDrawLine(Wdpy,w,Wgc[p->igc_line],p->LNx1,p->LNy1,p->LNx2,p->LNy2);
    return(1);
}

plotx_label(int x, int y, char *val)  {
    register struct object *p;

    p = NewObj(LABEL);
    p->LBx = x;
    p->LBy = y;
    p->LBval = stralloc(val);
    p->LBlen = strlen(val);
    AddObj(p);
    XDrawString(Wdpy,w,Wgc[p->igc_text], p->LBx,p->LBy,p->LBval,p->LBlen);
    return(1);
}

plotx_char(int x, int y, int val)  {
    char buffer[2];
    buffer[0] = val;
    buffer[1] = 0;
    plotx_label(x,y,buffer);
    return(1);
}

plotx_fill(int npoly)   {
    register struct point *pp;
    register int i;
    register struct object *p;

    p = NewObj(POLY);
    p->LBval = (char *)malloc(sizeof(poly));
    p->LBlen = npoly;
    pp = (struct point *)p->LBval;
    for (i=0; i<npoly; i++)
	{
	pp->x = poly[i].x;
	pp->y = poly[i].y;
	pp++;
	}
    XFillPolygon(Wdpy,w,Wgc[igc_panel],poly,npoly,Complex,CoordModeOrigin);
    return(1);
}

redraw_contents()  {
    register struct object *p;

    for(p=obp; p != NULL; p = p->next)
    switch(p->type) {
    case POINT:
	XDrawPoint(Wdpy,w,Wgc[p->igc_line],p->PTx,p->PTy);
	break;

    case LINE:
	XDrawLine(Wdpy,w,Wgc[p->igc_line],p->LNx1,p->LNy1,
	    p->LNx2,p->LNy2);
	break;

    case LABEL:
	XDrawString(Wdpy,w,Wgc[p->igc_text],p->LBx,p->LBy,
	    p->LBval,p->LBlen);
	break;

    case POLY:
	XFillPolygon(Wdpy,w,Wgc[p->igc_panel],p->LBval,p->LBlen,
	    Complex,CoordModeOrigin);
	break;

    default:
	break;
    }
}

plotx_clear()  {
    FreeObj();
    XClearWindow(Wdpy,w);
    return(1);
}

plotx_bell()  {
  /* XBell(Wdpy,50); DRE - disable beep on every plot*/ 
    XFlush(Wdpy);
    return(1);
}

plotx_refresh()  {
    XClearWindow(Wdpy,w);
    redraw_contents();
    return(1);
}

plotx_force_output()  {
    XFlush(Wdpy);
    return(1);
}

static void callbackDrawingArea( Widget widget, int tag,
    XmDrawingAreaCallbackStruct *callback_data)  {
    short wdt, hgt;

    if (tag == 10) {
/*	printf ("Callback: expose\n"); */
	redraw_contents();
    }

    else if (tag == 20) {
/*	printf ("Callback: resize\n"); */
	nargs = 0;
	XtSetArg( args[nargs], XmNwidth, &wdt); nargs++;
	XtSetArg( args[nargs], XmNheight, &hgt); nargs++;
	XtGetValues( wdraw, args, nargs );

	Wwidth = wdt;
	Wheight = hgt;
    }
}

static void handlerFocus( Widget widget, XtPointer client_data,
    XEvent *xevent, Boolean *condispatch)  {

    switch (xevent->type) {
	case FocusIn:
/*	    printf( "FocusIn\n"); */
	    got_focus = 1;
	    check_cursor();
	    break;
	case FocusOut:
/*	    printf( "FocusOut\n"); */
	    got_focus = 0;
	    check_cursor();
	    break;
	default:
	    break;
	}
}

static void handlerWindow( Widget widget, XtPointer client_data,
    XEvent *xevent, Boolean *condispatch)  {

    switch (xevent->type) {
	case EnterNotify:
/*	    printf( "EnterNotify\n"); */
	    got_window = 1;
	    check_cursor();
	    break;
	case LeaveNotify:
/*	    printf( "LeaveNotify\n"); */
	    got_window = 0;
	    check_cursor();
	    break;
	default:
	    break;
	}
    }

static void handlerKeyPress( widget, client_data, xevent, condispatch )
    Widget widget;
    XtPointer client_data;
    XEvent *xevent;
    Boolean *condispatch;
  {
    int x,y;
    int tekx,teky;
    unsigned char gin_bytes[6];
    char buffer[20];
    int nbuffer = 20;
    KeySym keysym;
    XComposeStatus compose;

    switch (xevent->type) {
	case KeyPress:
	    XLookupString( xevent, buffer, nbuffer,
		    &keysym, &compose );

	    if (keysym >= XK_Shift_L && keysym <= XK_Hyper_R)
		break;

	    if (keysym == XK_KP_Enter) keysym = XK_Return;

	    if (got_gin) {
		x = xevent->xkey.x;
		y = xevent->xkey.y;
		x_to_tek( x, y, &tekx, &teky);
		gin_bytes[0] = keysym & 0xFF;
		gin_bytes[1] = tekx >> 5;
		gin_bytes[2] = tekx & 0x1F;
		gin_bytes[3] = teky >> 5;
		gin_bytes[4] = teky & 0x1F;
		gin_bytes[5] = 0x0D;
		return_gin_bytes(gin_bytes, 6);
		set_got_gin( FALSE );
	    } else {
		gin_bytes[0] = keysym & 0xFF;
		return_gin_bytes(gin_bytes, 1);
		}

	    break;

	default:
	    break;
	}
    }

static void handlerButtonPress( widget, client_data, xevent, condispatch )
    Widget widget;
    XtPointer client_data;
    XEvent *xevent;
    Boolean *condispatch;
  {
    unsigned int button;
    int x,y;
    int tekx,teky;
    unsigned char gin_bytes[6];
    KeySym keysym;

    if (got_focus && got_window) {
	switch (xevent->type) {
	    case ButtonPress:
		if (xevent->xbutton.button == 1) {
		    keysym = XK_Return;
		    if (got_gin) {
			x = xevent->xbutton.x;
			y = xevent->xbutton.y;
			x_to_tek( x, y, &tekx, &teky);
			gin_bytes[0] = keysym & 0xFF;
			gin_bytes[1] = tekx >> 5;
			gin_bytes[2] = tekx & 0x1F;
			gin_bytes[3] = teky >> 5;
			gin_bytes[4] = teky & 0x1F;
			gin_bytes[5] = 0x0D;
			return_gin_bytes(gin_bytes, 6);
			set_got_gin( FALSE );
		    } else {
			gin_bytes[0] = keysym & 0xFF;
			return_gin_bytes(gin_bytes, 1);
			}
		    }

		else if (xevent->xbutton.button == 2)
		    draw_adj_frame(0);

		else if (xevent->xbutton.button == 3)
		    draw_adj_frame(1);

		break;

	    default:
		break;
	    }
	}
    }

static void check_cursor()  {
    if (got_focus && got_window && got_gin) {
	if (!cursor_flag) {
	    cursor_flag = 1;
	    XDefineCursor( Wdpy, XtWindow(wdraw), cursor);
	    }
    } else {
	if (cursor_flag) {
	    cursor_flag = 0;
	    XUndefineCursor( Wdpy, XtWindow(wdraw));
	    }
	}
    }

static void set_got_gin( int flag )  {
    if (flag && !got_gin) {
	got_gin = 1;
	check_cursor();

    } else if (!flag && got_gin) {
	got_gin = 0;
	check_cursor();
	}
    }

void get_tek_geometry( int *width, int *height )  {
    *width = Wwidth;
    *height = Wheight;
    }

void get_tek_pixel( int fb, unsigned long *pixel )  {
    *pixel = pixels[fb];
    }

create_gcs()  {
    int i;

    for (i = 0; i < 8; i++) {
	Wgc[i] = XCreateGC(Wdpy,w,Wgcvmask,&Wgcv);
	}

    }

color_init()  {
    XVisualInfo xvisualinfo;
    unsigned long plane_masks[1];
    unsigned int nplanes;
    unsigned int npixels;
    int i;

    if (Wdepth == 1)
	colortype = 3;

    else if (XMatchVisualInfo( Wdpy, Wscr, Wdepth,
		    PseudoColor, &xvisualinfo) ||
	 XMatchVisualInfo( Wdpy, Wscr, Wdepth,
		    DirectColor, &xvisualinfo) )
	{
	nplanes = 0;
	npixels = 9;

	if (XAllocColorCells( Wdpy, colormap, FALSE, plane_masks,
		    nplanes, pixels, npixels ) )
	  {
	    for (i = 0; i < 8; i++)
		XSetForeground( Wdpy, Wgc[i], pixels[i] );

	    nargs = 0;
	    XtSetArg( args[nargs], XmNbackground, pixels[8]);
	    nargs++;
	    XtSetValues( wdraw, args, nargs );

	    colortype = 1;
	} else {
	    colortype = 3;
	    }
	}

    else if (XMatchVisualInfo( Wdpy, Wscr, Wdepth,
		    StaticColor, &xvisualinfo) ||
	 XMatchVisualInfo( Wdpy, Wscr, Wdepth,
		    TrueColor, &xvisualinfo) )
	{
	colortype = 2;
	for (i = 0; i <= 8; i++) rocurrent[i] = 0;
	}

    else
	colortype = 3;

    }

void color_tek_window(int fb, int r, int g, int b)  {
    char rgb[8];
    unsigned long planes;
    unsigned long pixel_temp;
    XColor xcolor;

    if (colortype == 1) {
	sprintf (rgb, "#%02X%02X%02X\0", r, g, b);
	XParseColor(Wdpy, colormap, rgb, &xcolor);
	xcolor.pixel = pixels[fb];
	xcolor.flags = DoRed | DoGreen | DoBlue;
	XStoreColor( Wdpy, colormap, &xcolor );
    }

    else if (colortype == 2) {
    sprintf (rgb, "#%02X%02X%02X\0", r, g, b);
    XParseColor(Wdpy, colormap, rgb, &xcolor);

    if (XAllocColor( Wdpy, colormap, &xcolor ) ) {
	pixel_temp = pixels[fb];
	pixels[fb] = xcolor.pixel;
	if (fb < 8) {
	    XSetForeground( Wdpy, Wgc[fb], pixels[fb] );
	} else {
	    nargs = 0;
	    XtSetArg(args[nargs], XmNbackground, pixels[8]);
	    nargs++;
	    XtSetValues( wdraw, args, nargs );
	}

	if (rocurrent[fb] == 1) {
	    planes = 0;
	    XFreeColors( Wdpy, colormap, &pixel_temp,
	    1, planes );
	}

	rocurrent[fb] = 1;
	}
    }

    else {/* black&white */
	if (r == 0 && g == 0 && b == 0)
	    pixels[fb] = BlackPixel( Wdpy, Wscr );
    else
	pixels[fb] = WhitePixel( Wdpy, Wscr );

    if (fb < 8)
	XSetForeground( Wdpy, Wgc[fb], pixels[fb] );
    else {
	nargs = 0;
	XtSetArg( args[nargs], XmNbackground, pixels[8]);
	nargs++;
	XtSetValues( wdraw, args, nargs );
	}
    }

}

void dash_color(int icolor)  {
    if ((colortype!=3) && (mode==CMD41)) igc_line = icolor;
}

int set41_color(int color)  {

    if (color<0) color = -color;	/* panel solid colors are -7:0 */
    color--;			/* tek black is 1, xtc black is 0 */
    if (color==0) color = 8;	/* 8 is white = background */
    if (color>7) color = 0;
    if (colortype == 3) color=0;
    return(color);
}
