#ifdef X11_GRAPHICS

/* Check ~mouse/X/Xlib.doc */

#include <stdio.h>
#include <errno.h>
#include <ctype.h>	
#include <sys/types.h>
#include <sys/time.h>

#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/Xresource.h>

#include "../h/cdefs.h"
#include "../h/timeval.h"
#include "grf4.h"
#include "grf4Internal.h"

extern int errno;

extern void *malloc();
char *getenv();

static XrmDatabase db;
static char *defaults = "\
*Foreground: white\n\
*Background: black\n\
*BorderColor: white\n\
*BorderWidth: 1\n\
*BorderMargin: 0\n\
*Font: fixed\n\
*Name: robotsim\n\
*IconName: robotsim\n\
";

static char *displayname;
static char *geometryspec;
static char *foreground;
static char *background;
static char *bordercstr;
static char *borderwstr;
static char *bordermstr;
static char *margincstr;
static char *name;
static char *iconname;
static char *fontname;

static int argc;
static char **argv;

static Display *disp;
static Screen *scr;
static int width;
static int height;
static int depth;
static Window rootwin;
static Colormap defcmap;
static Visual *visual;

static XColor fgcolor;
static XColor bgcolor;
static XColor bdcolor;
static XColor mgcolor;

static int reverse = 0;

static GC wingc;
static GC revgc;
static Window topwin;
static Window win;
static Colormap wincmap;
static int winw;
static int winh;
static int panw;
static int panh;
static int margin;
static int borderwidth;
static XFontStruct *font;

static Pixmap pixmap = None;

static saveargv();
static handleargs();
static maybeset();
static setup_db();
static char *get_default_value();
static char *defaultValue();
static setup_color();
static setup_font();
static setup_colors();
static setup_numbers();
static setup_windows();
static setup_pixmap();
static x11GetCursorState ();
static x11GetButtonState ();
static eachcycle();
static handle_event();
static resize();
static redisplay();

static saveargv(ac,av)
int ac;
char **av;
{
 int i;
 int nc;
 char *abuf;

 argc = ac;
 argv = (char **)malloc((ac+1)*sizeof(char *));
 nc = 1;
 for (i=0;i<ac;i++)
  { nc += strlen(av[i]) + 1;
  }
 abuf = (char *) malloc(nc*sizeof(char));
 for (i=0;i<ac;i++)
  { argv[i] = abuf;
    strcpy(abuf,av[i]);
    while (*abuf) abuf ++;
    abuf ++;
  }
 *abuf = '\0';
 argv[ac] = 0;
}

static handleargs(ac,av)
int ac;
char **av;
{
 int skip;
 int errs;

 skip = 0;
 errs = 0;
 for (ac--,av++;ac;ac--,av++)
  { if (skip > 0)
     { skip --;
       continue;
     }
    if (**av != '-')
     { fprintf(stderr,"unrecognized argument `%s'\n",*av);
       errs ++;
       continue;
     }
    if (0)
     {
needarg:;
       fprintf(stderr,"%s needs a following argument\n",*av);
       errs ++;
       continue;
     }
#define WANTARG() do { if (++skip >= ac) goto needarg; } while (0)
    if (!strcmp(*av,"-display"))
     { WANTARG();
       displayname = av[skip];
       continue;
     }
    if (!strcmp(*av,"-geometry"))
     { WANTARG();
       geometryspec = av[skip];
       continue;
     }
    if (!strcmp(*av,"-foreground") || !strcmp(*av,"-fg"))
     { WANTARG();
       foreground = av[skip];
       continue;
     }
    if (!strcmp(*av,"-background") || !strcmp(*av,"-bg"))
     { WANTARG();
       background = av[skip];
       continue;
     }
    if (!strcmp(*av,"-bordercolor") || !strcmp(*av,"-bd"))
     { WANTARG();
       bordercstr = av[skip];
       continue;
     }
    if (!strcmp(*av,"-borderwidth") || !strcmp(*av,"-bw"))
     { WANTARG();
       borderwstr = av[skip];
       continue;
     }
    if (!strcmp(*av,"-bordermargin") || !strcmp(*av,"-bm"))
     { WANTARG();
       bordermstr = av[skip];
       continue;
     }
    if (!strcmp(*av,"-margincolor") || !strcmp(*av,"-mc"))
     { WANTARG();
       margincstr = av[skip];
       continue;
     }
    if (!strcmp(*av,"-name"))
     { WANTARG();
       name = av[skip];
       continue;
     }
    if (!strcmp(*av,"-iconname"))
     { WANTARG();
       iconname = av[skip];
       continue;
     }
    if (!strcmp(*av,"-font") || !strcmp(*av,"-fn"))
     { WANTARG();
       fontname = av[skip];
       continue;
     }
    if (!strcmp(*av,"-reverse"))
     { reverse = 1;
       continue;
     }
#undef WANTARG
    fprintf(stderr,"unrecognized option `%s'\n",*av);
    errs ++;
  }
 if (errs)
  { exit(1);
  }
}

static maybeset(strp,str)
char **strp;
char *str;
{
 if (str && !*strp) *strp = str;
}

static setup_db()
{
 char *str;
 char *home;
 XrmDatabase db2;

 db = XrmGetStringDatabase(defaults);
 str = XResourceManagerString(disp);
 if (str)
  { db2 = XrmGetStringDatabase(str);
    XrmMergeDatabases(db2,&db);
  }
 else
  { home = getenv("HOME");
    if (home)
     { str = (char*)malloc(strlen(home)+1+10+1);
       sprintf(str,"%s/.Xdefaults",home);
       db2 = XrmGetFileDatabase(str);
       if (db2)
	{ XrmMergeDatabases(db2,&db);
	}
       free(str);
     }
  }
}

static char *get_default_value(name,class)
char *name;
char *class;
{
 char *type;
 XrmValue value;

 if (XrmGetResource(db,name,class,&type,&value) == False) return(0);
 return(value.addr);
}

static char *defaultValue(name,prop,Name,class)
char *name;
char *prop;
{
	char nbuf[256];
	char cbuf[256];

	sprintf (nbuf, "%s.%s", name, prop);
	sprintf (cbuf, "%s.%s", Name, class);
	return (get_default_value(nbuf,cbuf));
}

static setup_color(str,col)
char *str;
XColor *col;
{
 if (XParseColor(disp,wincmap,str,col) == 0)
  { fprintf(stderr,"bad color `%s'\n",str);
    exit(1);
  }
 while (1)
  { if (XAllocColor(disp,wincmap,col) == 0)
     { if (wincmap != defcmap)
	{ fprintf(stderr,"can't allocate colormap cell for color `%s'\n",str);
	  exit(1);
	}
       wincmap = XCopyColormapAndFree(disp,wincmap);
       continue;
     }
    break;
  }
}

static setup_font()
{
 font = fontname ? XLoadQueryFont(disp,fontname) : 0;
 if (fontname && !font)
  { fprintf(stderr,"can't load font %s, using server default\n",fontname);
  }
}

static setup_colors()
{
 wincmap = defcmap;
 setup_color(foreground,&fgcolor);
 setup_color(background,&bgcolor);
 setup_color(bordercstr,&bdcolor);
 setup_color(margincstr,&mgcolor);
 if (reverse)
  { XColor ct;
    ct = fgcolor;
    fgcolor = bgcolor;
    bgcolor = ct;
  }
}

static setup_numbers()
{
 if (bordermstr) margin = atoi(bordermstr);
 if (borderwstr) borderwidth = atoi(borderwstr);
}

static setup_windows(Name,name,x,y,w,h)
char *Name;
char *name;
int x,y;
unsigned int w,h;
{
 int bits;
 unsigned long int attrmask;
 unsigned long int gcvalmask;
 XSetWindowAttributes attr;
 XGCValues gcval;
#ifdef X11R3
 XSizeHints sizehints;
#else
 XTextProperty wn_prop;
 XTextProperty in_prop;
 XSizeHints normal_hints;
 XWMHints wm_hints;
 XClassHint class_hints;
#endif

 bits = XParseGeometry(geometryspec,&x,&y,&w,&h);
 if (bits & XNegative) x = width + x - w;
 if (bits & YNegative) y = height + y - h;
 attrmask = 0;
 attr.background_pixel = mgcolor.pixel;
 attrmask |= CWBackPixel;
 attr.border_pixel = bdcolor.pixel;
 attrmask |= CWBorderPixel;
 attr.backing_store = NotUseful;
 attrmask |= CWBackingStore;
 attr.event_mask = StructureNotifyMask;
 attrmask |= CWEventMask;
 w -= 2 * borderwidth;
 h -= 2 * borderwidth;
 topwin = XCreateWindow(disp,rootwin,x,y,w,h,borderwidth,depth,InputOutput,CopyFromParent,attrmask,&attr);
#ifdef X11R3
 sizehints.flags = 0;
 sizehints.min_width = (panw ? panw-1 : 1);
 sizehints.min_height = (panw ? panh : 1);
 sizehints.flags |= PMinSize;
 sizehints.width = w;
 sizehints.height = h;
 sizehints.flags |= (bits & (WidthValue|HeightValue)) ? USSize : PSize;
 if (bits & (XValue|YValue))
  { sizehints.x = x;
    sizehints.y = y;
    sizehints.flags |= USPosition;
  }
 XSetStandardProperties(disp,topwin,Name,name,None,argv,argc,&sizehints);
#else	
 wn_prop.value = (unsigned char *)Name;
 wn_prop.encoding = XA_STRING;
 wn_prop.format = 8;
 wn_prop.nitems = strlen((char *)wn_prop.value);
 in_prop.value = (unsigned char *)name;
 in_prop.encoding = XA_STRING;
 in_prop.format = 8;
 in_prop.nitems = strlen((char *)in_prop.value);
 normal_hints.flags = PMinSize | PResizeInc;
 normal_hints.x = x;
 normal_hints.y = y;
 normal_hints.flags |= (bits & (XValue|YValue)) ? USPosition : PPosition;
 normal_hints.width = w;
 normal_hints.height = h;
 normal_hints.flags |= (bits & (WidthValue|HeightValue)) ? USSize : PSize;
 normal_hints.min_width = (panw ? panw-1 : 1);
 normal_hints.min_height = (panw ? panh : 1);
 normal_hints.width_inc = 1;
 normal_hints.height_inc = 1;
 wm_hints.flags = InputHint;
 wm_hints.input = True;
 class_hints.res_name = name;
 class_hints.res_class = Name;
 XSetWMProperties(disp,topwin,&wn_prop,&in_prop,argv,argc,&normal_hints,&wm_hints,&class_hints);
#endif
 if (wincmap != defcmap) XSetWindowColormap(disp,topwin,wincmap);
 attrmask = 0;
 attr.background_pixel = bgcolor.pixel;
 attrmask |= CWBackPixel;
 attr.backing_store = NotUseful;
 attrmask |= CWBackingStore;
 attr.event_mask = (ExposureMask |
		    ButtonMotionMask |
		    ButtonPressMask |
		    ButtonReleaseMask);
 attrmask |= CWEventMask;
 win = XCreateWindow(disp,topwin,0,0,1,1,0,depth,InputOutput,CopyFromParent,attrmask,&attr);
 XMapRaised(disp,win);
 gcvalmask = 0;
 if (font)
  { gcval.font = font->fid;
    gcvalmask |= GCFont;
  }
 gcval.foreground = fgcolor.pixel;
 gcvalmask |= GCForeground;
 gcval.background = bgcolor.pixel;
 gcvalmask |= GCBackground;
 wingc = XCreateGC(disp,win,gcvalmask,&gcval);
 revgc = XCreateGC(disp,win,gcvalmask,&gcval);
 XSetForeground(disp,revgc,bgcolor.pixel);
 XSetBackground(disp,revgc,fgcolor.pixel);
 XMapRaised(disp,topwin);
 resize(w,h);
}

static setup_pixmap()
{
	if (pixmap != None)
	 { XFreePixmap (disp, pixmap);
	 }
	if (winw-panw > 0)
	 { pixmap = XCreatePixmap (disp, win, winw-panw, winh, depth);
	   XSetForeground(disp,wingc,bgcolor.pixel);
	   XFillRectangle(disp,pixmap,wingc,0,0,winw-panw,winh);
	   XSetForeground(disp,wingc,fgcolor.pixel);
	 }
	else
	 { pixmap = None;
	 }
}

int (*resizeHandler)();
int (*redrawHandler)();
int (*motionHandler)();
int (*buttonHandler)();

#define BUTTON_BORDER_WIDTH	2

void grf4X11GetButtonExtent(b)
BUTTON_DESC *b;
{
	int direction;
	int fontAscent;
	int fontDescent;
	int margin;
	XCharStruct cs;

	XTextExtents (font, b->name, strlen(b->name), 
		      &direction,
		      &fontAscent,
		      &fontDescent,
		      &cs);
	margin = 1 + BUTTON_BORDER_WIDTH;
	b->coffX = margin - cs.lbearing;
	b->coffY = margin + MAX(cs.descent,fontDescent);
	b->minw = 2*margin + (cs.rbearing-cs.lbearing);
	b->minh = 2*margin + MAX(cs.ascent,fontAscent) +
			     MAX(cs.descent,fontDescent);
}

void grf4X11DrawButton(b)
BUTTON_DESC *b;
{
	int baseX, baseY;
	int cbaseX, cbaseY;

	baseX = b->x;
	baseY = (winh-1) - b->y - b->h + 1;
	cbaseX = baseX + b->coffX + (b->w - b->minw)/2;
	cbaseY = (winh-1) - b->y - b->coffY - (b->h - b->minh)/2;

	if (!(b->flags & BF_NOTBOXED))
	 { XFillRectangle(disp,win,wingc,baseX,baseY,b->w,b->h);
	 }
	else
	 { XFillRectangle(disp,win,revgc,baseX,baseY,b->w,b->h);
	 }
	if (b->flags & BF_ILLUMINATED)
	 { XFillRectangle (disp,win,wingc,
			     baseX+BUTTON_BORDER_WIDTH,
			     baseY+BUTTON_BORDER_WIDTH,
			     b->w-2*BUTTON_BORDER_WIDTH,
			     b->h-2*BUTTON_BORDER_WIDTH);
	   XDrawImageString(disp, win, revgc, cbaseX, cbaseY,
			    b->name, strlen(b->name));
	 }
	else
	 { XFillRectangle (disp,win,revgc,
			     baseX+BUTTON_BORDER_WIDTH,
			     baseY+BUTTON_BORDER_WIDTH,
			     b->w-2*BUTTON_BORDER_WIDTH,
			     b->h-2*BUTTON_BORDER_WIDTH);
	   XDrawImageString(disp, win, wingc, cbaseX, cbaseY,
			    b->name, strlen(b->name));
	 }
}

void grf4X11EventHandler(code, fxn)
int code;
int (*fxn)();
{
	switch (code)
	 { case REDRAW_EVENT:
	    { redrawHandler = fxn;
	      break;
	    }
	   case RESIZE_EVENT:
	    { resizeHandler = fxn;
	      break;
	    }
	   case MOTION_EVENT:
	    { motionHandler = fxn;
	      break;
	    }
	   case BUTTON_EVENT:
	    { buttonHandler = fxn;
	      break;
	    }
	 }
}

static x11GetCursorState (xp, yp)
int *xp, *yp;
{
#if 0
	Window root_ret, child_ret;
	int root_x_ret, root_y_ret;
	int win_x_ret, win_y_ret;
	unsigned int mask_ret;

	XQueryPointer (disp, win, 

	if (root_ret == rootwin)
	 { root_x, root_y relative to the root window
	   win_x, win_y relative to the window origin
	   mask is the state of the mod keys and the pointer buttons
	   mask & Button1Mask, etc.
	 }
#endif
}

static x11GetButtonState (up, num)
int *up;
int num;
{
	
}

static eachcycle()
{
	XEvent e;

	XSync(disp,False);
	while (XQLength(disp) > 0)
	 { XNextEvent(disp,&e);
	   handle_event(&e);
	 }
}

static handle_event(e)
XEvent *e;
{
 int x, y;

 switch (e->type)
  { default:
       break;
    case ConfigureNotify:
     { int w, h;

       /* XConfigureEvent - xconfigure */

       w = e->xconfigure.width;
       h = e->xconfigure.height;
       if (w == winw && h == winh)
	{ /* Just a move event */
	  redisplay(0, 0, w, h);
	  if (panw)
	   { XDrawLine(disp,win,wingc,winw-panw,0,winw-panw,winh-1);
	   }
	  if (redrawHandler)
	   { (*redrawHandler)();
	   }
	}
       else
	{ /* This is a resize event */
	  resize (w, h);
	  if (panw)
	   { XDrawLine(disp,win,wingc,winw-panw,0,winw-panw,winh-1);
	   }
    	  if (resizeHandler)
	   { (*resizeHandler)(w,h);
	   }
	}
       /* draw buttons in any case */
       break;
     }
    case Expose:
       /* XExposeEvent - xexpose */
       if (e->xexpose.window == win)
	{ redisplay(e->xexpose.x,e->xexpose.y,
		    e->xexpose.width,e->xexpose.height);
	  if (panw)
	   { XDrawLine(disp,win,wingc,winw-panw,0,winw-panw,winh-1);
	   }
	  if (redrawHandler)
	   { (*redrawHandler)();
	   }
	}
       break;
    case GraphicsExpose:
       /* XGraphicsExposeEvent - xgraphicsexpose */
       /* XXX - shouldn't depend on being able to cast a Window into a Drawable (but how else?) */
       if (e->xgraphicsexpose.drawable == (Drawable)win)
	{ redisplay(e->xgraphicsexpose.x,e->xgraphicsexpose.y,
		    e->xgraphicsexpose.width,e->xgraphicsexpose.height);
	  if (panw)
	   { XDrawLine(disp,win,wingc,winw-panw,0,winw-panw,winh-1);
	   }
	  if (redrawHandler)
	   { (*redrawHandler)();
	   }
	}
       break;
    case MotionNotify:
     { if (motionHandler)
	{ (*motionHandler)(e->xmotion.x, (winh-1)-e->xmotion.y);
	}
       break;
     }
    case ButtonPress:
     { if (buttonHandler)
	{ (*buttonHandler)((int)e->xbutton.button, /*pressed=*/1, 
			   e->xbutton.x, (winh-1)-e->xmotion.y);
	}
       break;
     }
    case ButtonRelease:
     { if (buttonHandler)
	{ (*buttonHandler)((int)e->xbutton.button, /*pressed=*/0,
			   e->xbutton.x, (winh-1)-e->xmotion.y);
	}
       break;
     }
  }
}

static resize(topw,toph)
int topw;
int toph;
{
 int x;
 int y;
 int w;
 int h;

 x = margin;
 y = margin;
 w = topw - (2 * margin);
 h = toph - (2 * margin);
 XMoveResizeWindow(disp,win,x,y,w,h);
 XClearArea(disp,win,0,0,0,0, False/*(do not create "expose" event)*/);
 winw = w;
 winh = h;
 setup_pixmap();
}

static redisplay(x,y,w,h)
int x;
int y;
int w;
int h;
{
	/* clip w so that x+w <= winw-panw */
	if (x+w > winw-panw)
	 { w = winw-panw-x;
	 }
	if (pixmap != None && w > 0)
	 { XCopyArea (disp, pixmap, win, wingc, x, y, w, h, x, y);
	 }
}

void grf4X11Clear (x,y,w,h)
int x, y, w, h;
{
	/* Clear the memory image prior to drawing */

	if (pixmap != None)
	 { XSetForeground(disp,wingc,bgcolor.pixel);
	   XFillRectangle(disp,pixmap,wingc,x,y,w,h);
	   XSetForeground(disp,wingc,fgcolor.pixel);
	 }
}

void grf4X11Draw (x1,y1,x2,y2)
int x1,y1,x2,y2;
{
	/* Draw a line into the memory image */

	if (pixmap != None)
	 { XDrawLine(disp,pixmap,wingc,x1,y1,x2,y2);
	 }
}

void grf4X11GetWindowSize (w, h, directionOfY)
int *w, *h;
int *directionOfY;
{
	*w = winw;
	*h = winh;
	*directionOfY = -1;
}

void grf4X11Flush (x, y, w, h)
int x, y, w, h;
{
	/* Flush the memory image to the output image. */

	redisplay (x, y, w, h);
}

void grf4X11Cycle()
{
	/* catch events that we are waiting for, and handle them
	   as required. */

	eachcycle();
	XFlush (disp);
}

void grf4X11Color(color)
int color;
{
}

void grf4X11Wait(sd)
int sd;
{
	fd_set fdset;
	int xfd, n;

	xfd = XConnectionNumber(disp);
	do
	 { FD_ZERO (&fdset);
	   if (sd >= 0)
	    { FD_SET (sd, &fdset);
	    }
	   FD_SET (xfd, &fdset);
	   XFlush (disp);
	   while ((n = select (FD_SETSIZE, &fdset, NULL, NULL, NULL)) < 0 &&
		  errno == EINTR)
	      ;
	   if (n < 0)
	    { perror ("grf4Wait() -- error in select");
	      exit (-1);
	    }
	   if (FD_ISSET(xfd, &fdset))
	    { eachcycle();
	    }
	   XFlush (disp);
	 }
	while (sd >= 0 ? !FD_ISSET(sd, &fdset) : 1);
}

grf4X11Select (gEvnt, rfds, wfds, efds, timeout)
int *gEvnt;
fd_set *rfds, *wfds, *efds;
struct timeval *timeout;
{
	fd_set rset;
	int xfd, n;

	if (!rfds)
	 { rfds = &rset;
	   FD_ZERO (rfds);
	 }
	if (gEvnt)
	 { *gEvnt = 0;
	 }

	/* set xfd to the file descriptor for X events */
	xfd = XConnectionNumber(disp);

	FD_SET (xfd, rfds);

	XFlush (disp);
	n = select (FD_SETSIZE, rfds, wfds, efds, timeout);
	if (n > 0)
	 { if (FD_ISSET(xfd, rfds))
	    { eachcycle();	/* queue event occurred; handle */
	      FD_CLR (xfd, rfds);
	      if (gEvnt)
	       { *gEvnt = 1;
	       }
	      n--;
	    }
	 }
	return(n);
}

grf4X11Init (label, fgcolor, bgcolor, x,y,w,h)
char *label;
int fgcolor;
int bgcolor;
int x,y,w,h;
{
	int ac = 1;
	char *dummyProgName = "dummyProgName";
	char **av = &dummyProgName;

	char Nbuf[256];
	char nbuf[256];

	strcpy(nbuf, label);
	strcpy(Nbuf, label);
	nbuf[0] = tolower(nbuf[0]);
	Nbuf[0] = toupper(Nbuf[0]);

	saveargv(ac,av);
	handleargs(ac,av);
	if ((disp = XOpenDisplay(displayname)) == 0)
	 { return (-1);
	 }

	scr = XDefaultScreenOfDisplay(disp);
	width = XWidthOfScreen(scr);
	height = XHeightOfScreen(scr);
	depth = XDefaultDepthOfScreen(scr);
	rootwin = XRootWindowOfScreen(scr);
	defcmap = XDefaultColormapOfScreen(scr);
	visual = XDefaultVisualOfScreen(scr);
	setup_db();

	maybeset(&geometryspec, defaultValue(
		 nbuf, "geometry", Nbuf, "Geometry"));
	maybeset(&fontname, defaultValue(
		 nbuf, "font", Nbuf, "Font"));
	maybeset(&foreground, defaultValue(
		 nbuf, "foreground", Nbuf, "Foreground"));
	maybeset(&background, defaultValue(
		 nbuf, "background", Nbuf, "Background"));
	maybeset(&bordercstr, defaultValue(
		 nbuf, "borderColor", Nbuf, "BorderColor"));
	maybeset(&borderwstr, defaultValue(
		 nbuf, "borderWidth", Nbuf, "BorderWidth"));
	maybeset(&bordermstr, defaultValue(
		 nbuf, "borderMargin", Nbuf, "BorderMargin"));
	maybeset(&margincstr, defaultValue(
		 nbuf, "marginColor", Nbuf, "Background"));
	maybeset(&name, defaultValue(
		 nbuf, "name", Nbuf, "Name"));
	maybeset(&iconname, defaultValue(
		 nbuf, "iconName", Nbuf, "IconName"));

	setup_font();
	if (bgcolor)
	 { reverse = 1;
	 }
	setup_colors();
	setup_numbers();

	buttonInit (&panw, &panh);

	if (x == -1 && y == -1)
	 { x = y = 200;
	 }
	else if (x == -1)
	 { x = y;
	 }
	else if (y == -1)
	 { y = x;
	 }
	if (w == -1 && h == -1)
	 { w = h = 300;
	 }
	else if (w == -1)
	 { w = h;
	 }
	else if (h == -1)
	 { h = w;
	 }
	setup_windows(Nbuf,nbuf,300,300,MAX(w,panw),MAX(h,panh));

	if (panw)
	 { XDrawLine(disp,win,wingc,winw-panw,0,winw-panw,winh-1);
	 }

	return (1);
}

grf4X11SetupFxns (ftab)
struct grf4fxnTable *ftab;
{
	ftab->getWindowSize = grf4X11GetWindowSize;
	ftab->cycle = grf4X11Cycle;
	ftab->wait = grf4X11Wait;
	ftab->select = grf4X11Select;
	ftab->color = grf4X11Color;
	ftab->eventHandler = grf4X11EventHandler;

	ftab->drawButton = grf4X11DrawButton;
	ftab->getButtonExtent = grf4X11GetButtonExtent;

	ftab->pxlDraw = grf4X11Draw;
	ftab->pxlFlush = grf4X11Flush;
	ftab->pxlClear = grf4X11Clear;

	return (1);
}

#else

#include <stdio.h>

grf4X11Init ()
{
	return(-1);
}

grf4X11SetupFxns()
{
	fprintf (stderr, "grf4Init(): X11 support not available\n");
	return (-1);
}

#endif
