/*                        COPYRIGHT (c) 1989 BY                             *
 *        PARADIGM ASSOCIATES INCORPORATED, CAMBRIDGE, MASSACHUSETTS.       *
 *			   ALL RIGHTS RESERVED                              *

Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the name of Paradigm Associates Inc
not be used in advertising or publicity pertaining to distribution of
the software without specific, written prior permission.

PARADIGM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
PARADIGM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.

*/

/* Under VMS these routines are called directly from VAXLISP.
   No event polling loop is required. Under Unix these routines
   are called from a subprocess which gets its input from a pipe.
*/


#include <stdio.h>
#ifdef VMS
#include <DECW$INCLUDE:Xlib.h>
#include <DECW$INCLUDE:Xatom.h>
#include <DECW$INCLUDE:Xutil.h>
#else
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#endif

#ifndef NULL
#define NULL 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b))
#endif

int errdbg = 0;
int syncmode = 0;


#ifdef VMS
void event_ast_handler();
#endif


/*
 * Basic screen object types
 */
#define POINT 1
#define LINE  2
#define LABEL 3

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;
  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;

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 plotx_setflags(syncmode_flag,errdbg_flag)
     int syncmode_flag,errdbg_flag;
{syncmode = syncmode_flag;
 errdbg = errdbg_flag;
 return(1);}

plotx_init()
{if ((Wdpy = XOpenDisplay(NULL)) == 0)
   {if (errdbg) perror("cannot open X display");
    return(0);}
 if (syncmode == 1) XSynchronize(Wdpy,1);
 Wscr = DefaultScreen(Wdpy);
 
 dpyht = DisplayHeight(Wdpy,Wscr);
 dpywd = DisplayWidth(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;

 w = XCreateWindow(Wdpy,Wroot,
		   Wxpos,Wypos,Wwidth,Wheight,Wborder,Wdepth,
		   Wclass,
		   Wvis,Wxswamask,&Wxswa);

 Wgc = XCreateGC(Wdpy,w,Wgcvmask,&Wgcv);
 XChangeProperty(Wdpy,w,XA_WM_NAME,XA_STRING,8,PropModeReplace,
		 wname,strlen(wname));
 XSetWMHints(Wdpy,w,&Wxshints);
 XMapWindow(Wdpy,w);

#ifdef VMS
 XSelectAsyncInput(Wdpy,w,ExposureMask|StructureNotifyMask,
		   event_ast_handler,0);
#endif

 XSelectInput(Wdpy,w,ExposureMask|StructureNotifyMask);

 XFlush(Wdpy);
 fprintf(stdout,
 "XTEK - Copyright (c) 1989 Paradigm Associates Inc. All Rights Reserved.\n");
 
 return(1);}


plotx_width()
{return(Wwidth);}

plotx_height()
{return(Wheight);}

plotx_char_width()
{return(Wchar_width);}

plotx_char_height()
{return(Wchar_height);}

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

struct object *NewObj(type) 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;
 return(p);}

FreeObj()
{register struct object *tp;

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


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

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

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

plotx_line(x1,y1,x2,y2)
     int x1, y1, x2, 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->LNx1,p->LNy1,p->LNx2,p->LNy2);
 return(1);}

plotx_label(x,y,val)
     int x,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->LBx,p->LBy,p->LBval,p->LBlen);
 return(1);}

plotx_char(x,y,val)
     int x,y,val;
{char buffer[2];
 buffer[0] = val;
 buffer[1] = 0;
 plotx_label(x,y,buffer);
 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->PTx,p->PTy);
	break;

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

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

      default:
	break;}}

onexpose(ep) XExposeEvent *ep;
{if (errdbg == 1) fprintf(stderr,"Expose Event\n");
 redraw_contents();}

onstructurenotify(ep)
     XAnyEvent *ep;
{XConfigureEvent *p;

 switch(ep->type)
   {case ConfigureNotify:
      if (errdbg == 1) fprintf(stderr,"ConfigureNotify Event\n");
      p = (XConfigureEvent *) ep;
      Wwidth = p->width;
      Wheight = p->height;
      Wxpos = p->x;
      Wypos = p->y;
      break;
    default:
      break;}}

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

char *decode_event_number();

#ifdef VMS

void event_ast_handler(astarg)
     int astarg;
{XEvent event;
 XAnyEvent *ep;
 ep = &event;
 while(XPending(Wdpy) > 0)
   {XNextEvent(Wdpy,ep);
    switch(ep->type)
      {case Expose:
	 onexpose(ep);
	 break;
       case ConfigureNotify:
	 onstructurenotify(ep);
	 break;
       default:
	 if (errdbg == 1)
	   fprintf(stderr,"Ignored Event %d %s\n",ep->type,
		   decode_event_number(ep->type));}}}
#endif

char *decode_event_number(x)
     int x;
{switch (x)
   {case KeyPress:
      return("KeyPress");
    case KeyRelease:
      return("KeyRelease");
    case ButtonPress:
      return("ButtonPress");
    case ButtonRelease:
      return("ButtonRelease");
    case MotionNotify:
      return("MotionNotify");
    case EnterNotify:
      return("EnterNotify");
    case LeaveNotify:
      return("LeaveNotify");
    case FocusIn:
      return("FocusIn");
    case FocusOut:
      return("FocusOut");
    case KeymapNotify:
      return("KeymapNotify");
    case Expose:
      return("Expose");
    case GraphicsExpose:
      return("GraphicsExpose");
    case NoExpose:
      return("NoExpose");
    case VisibilityNotify:
      return("VisibilityNotify");
    case CreateNotify:
      return("CreateNotify");
    case DestroyNotify:
      return("DestroyNotify");
    case UnmapNotify:
      return("UnmapNotify");
    case MapNotify:
      return("MapNotify");
    case MapRequest:
      return("MapRequest");
    case ReparentNotify:
      return("ReparentNotify");
    case ConfigureNotify:
      return("ConfigureNotify");
    case ConfigureRequest:
      return("ConfigureRequest");
    case GravityNotify:
      return("GravityNotify");
    case ResizeRequest:
      return("ResizeRequest");
    case CirculateNotify:
      return("CirculateNotify");
    case CirculateRequest:
      return("CirculateRequest");
    case PropertyNotify:
      return("PropertyNotify");
    case SelectionClear:
      return("SelectionClear");
    case SelectionRequest:
      return("SelectionRequest");
    case SelectionNotify:
      return("SelectionNotify");
    case ColormapNotify:
      return("ColormapNotify");
    case ClientMessage:
      return("ClientMessage");
    case MappingNotify:
      return("MappingNotify");
    default:
      return("*UNDEFINED?*");}}

plotx_bell()
{XBell(Wdpy,50);
 XFlush(Wdpy);
 return(1);}

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

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

