/* file xport.c, most of the X windows code, has to interact with motif.c
   if motif widgets are used */
 /* 9/11/99 some code taken from xwd.c, should put in the copyright notice */
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <X11/Xatom.h>
#include <X11/cursorfont.h>
#include <Xm/MwmUtil.h>
#include <Xm/Xm.h>
#include <X11/Xmu/WinUtil.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "ana_structures.h"
#include "defs.h"
 /* following is icon bitmap */
#include "ana_bitmap.h"

#define MAXWINDOW       100
#define MAXMAPS         20
#define	FIXED_COLORS	8	/* used for color maps with fixed visuals */
 extern  int     scalemin, scalemax;
 extern  float   xfac, yfac, xlimit, ylimit;
 extern  int     ixlow, iylow, ixhigh, iyhigh;
 extern  struct sym_desc sym[];
 extern double systime();
 extern	char   *strsave(char  *s);
 extern int ReadColors(), xerr();
 extern	Window Select_Window();
 int xfontylabel(float x, float y, char *label, float *xleftmost);
 /* define some fixed colors for the 8 bit image representations, make sure
 there are FIXED_COLORS of these */
 int	white_pixel = 255, red_pixel = 254, green_pixel = 253, blue_pixel = 252;
 int	yellow_pixel = 251, black_pixel = 250, darkgreen_pixel = 249;
 int	purple_pixel = 248;
 static char *fixed_color_names[] = {"white","red","green","blue","yellow",
 		"black","darkgreen", "purple"};
 void	get_shifts16();
 void	get_shifts32();
 void	swapl(char *x,int n);
 union   types_ptr { byte *b; short *w; int *l; float *f; double *d;};
 char    *display_name = NULL;
 Display *display, *display2, *display3;
 Atom	wm_delete;
 XVisualInfo     visual_info;
 XVisualInfo     *visualList;
 XSetWindowAttributes    attributes;
 Screen  *screen;
 XColor *colors;
 int    screen_num, colormin, colormax, ncolorcells;
 int    maxwin = MAXWINDOW, maxmap = MAXMAPS;
 int    connect_flag = 0, last_wid = 0, depth, color_cells_to_try=128;
 int	connect_flag2 = 0, connect_flag3 = 0;
 int	invert_flag=0, image_string_flag=0;	/* used by drawlines */
 unsigned int     display_width, display_height, display_cells;
 double last_time;
 int    xcoord, ycoord, ana_button, ana_keycode, ana_keysym, root_x, root_y;
 int	ana_keystate;
 int	tvplanezoom = 1;
 int	clear_outside_flag = 1;
 unsigned int    kb;
 float	xhair, yhair;
 Window win[MAXWINDOW];	/* these are the window ID's, int's */
 Window	selected_window;
 GC     gc[MAXWINDOW], gcnot[MAXWINDOW];
 GC	gcmap[MAXMAPS], gcmapnot[MAXMAPS], gcmaperase[MAXMAPS];
 
 /* a scratch Drawable and GC for common usage */
 Drawable	scrat_Drawable;
 GC		scrat_GC;
 int	scrat_ixs, scrat_iys, scrat_w, scrat_h;
 /* the size of each of the windows and pixmaps for our use */
 int     wd[MAXWINDOW], ht[MAXWINDOW],wdmap[MAXMAPS], htmap[MAXMAPS];
 /* a motif connection, needed to link these windows to motif drawing
 areas, also see code in ana_xcreat */
 int	drawingareas[MAXWINDOW];
 int	xerrors;
 XFontStruct     *font_info[MAXWINDOW], *font_info_maps[MAXMAPS];
 /* lookup table pointers for the windows, used for true color visuals */
 int	*window_lookups[MAXWINDOW];
 Visual  *vis;
 XImage  *xi, *zimage;
 Pixmap  icon_pixmap, maps[MAXMAPS], back_pixmap;
 Colormap        colormap, def_colormap;
 XColor  cells[256];
 XColor  colorcell, rgb_def;	/* some scratch colorcells */
 unsigned  long  pixels[256];    
 /* these can be volatile if there are several visuals */
 unsigned  long rmask, gmask, bmask;
 int rshift, gshift, bshift;
 int rshift32, gshift32, bshift32;
 /* some of these are user accessible variables */
 int	visual_class;		/* 0 - 5 for X visual class */
 int	visual_depth;
 /* 1/19/2000 - flags to track window mods */
 int	window_mod_flag[MAXWINDOW];	/* to track window mods */
 unsigned short *look16to16 = NULL;	/* used in tvmix16win to keep a table
 				once we've made it */
 unsigned short *blend_imc = NULL;	/* for a combined image */
 int	blend_nx, blend_ny;		/* for checks */
 int	blend_w1 = -1, blend_w2 = -1, blend_w3 = -1;
 int	blend_feedback;
 int	xroot_coord_mode = 1;
 
 short	*lookup16truecolor = 0;
 unsigned int	*lookup24truecolor = 0;
 int	xold, yold, true_color24=0, true_color16=0;
 float	tvix, tviy, tvixb, tviyb;
 unsigned  long  background_color, foreground_color;
 float	fac, base, black_level;
 int	alpha_mode, screenByteOrder, clientByteOrder;
 int load_to_triplet(XImage *image, char *pout, int nx, int ny);
 /*-------------------------------------------------------------------------*/
int setup_pseudo8()
 {
 int	ncolors, i, iq, nc, n, j;
 unsigned long	*plane_mask;
 float	fac;
 /* setup for a psuedo color 8 bit visual, this is the one we like to get */
 def_colormap = DefaultColormap(display, screen_num);
 vis = DefaultVisual(display, screen_num);
 /* needs some thought, the color_cells_to_try parameter makes less sense
 now, we always what a valid color table, what we now do is return the
 default color table */
 colormap = def_colormap;
 nc = MAX(color_cells_to_try, 0);

 /* don't bother doing this if we didn't want any colors, we have the
 default colormap already */

 if (nc <= 0) return 1;
 printf("trying for a 8 bit pseudo color visual\n");
 depth = 8;	/* note, PseudoColor is type 3 */

 if (!XMatchVisualInfo(display, screen_num, depth, PseudoColor,&visual_info))
	return -1;
 vis = visual_info.visual;
 depth = visual_info.depth;
 colormap = XCreateColormap(display, RootWindow(display,screen_num),
        vis, AllocNone);
 /* have to do an AllocNone or we won't be able to free or allow use
 of XAllocNamedColor */
 printf("colormap created = %d\n", colormap);
 /* get the colors for the default color map */
 ncolors = ReadColors(vis, def_colormap, &colors);
 printf("ncolors = %d\n", ncolors);

 /* allocate all the colors for this copy */
 if ( XAllocColorCells(display,colormap, False, plane_mask,0,pixels, ncolors) == 0 )
   {  printf("could not allocate %d colorcells for images\n", ncolors); }

 /* load these into our own colormap */
 for (i = 0; i < ncolors; i++) {
 cells[i].pixel = colors[i].pixel;
 cells[i].flags = colors[i].flags;
 cells[i].red = colors[i].red;
 cells[i].green = colors[i].green;
 cells[i].blue = colors[i].blue;
 } 
 XStoreColors(display, colormap, cells, ncolors);
 
 /* use only 128 colors for images, from 64 to 191 */
 colormin = 64;	 colormax = 191;
 ncolorcells = 128;
 scalemin = colormin;	scalemax = colormax;
 nc = 128;
 /* set them */
 fac = 65535./nc;
 for (i=colormin; i <= colormax;i++) {
 cells[i].pixel = i; cells[i].flags = DoRed|DoGreen|DoBlue;
 cells[i].red = cells[i].green = cells[i].blue =
			(unsigned short)(((float) (i - colormin)) * fac);
 }
 i = colormax;
 cells[i].red = cells[i].green = cells[i].blue = 65535;
 i = colormin;
 cells[i].red = cells[i].green = cells[i].blue = 0;
 
 XStoreColors(display,colormap, &cells[colormin], nc);
 /* also allocate our standard set of fixed colors, others can be assigned
 later by user */
 n = FIXED_COLORS;
 j = 255;
 for (i=0;i<n;i++) {
 XStoreNamedColor(display, colormap, fixed_color_names[i], j,DoRed|DoBlue|DoGreen);
 j--;
 }

 /* now free 192 to 255-FIXED_COLORS, these can be allocated */
 n = FIXED_COLORS;
 n = 64 - n;
 XFreeColors(display, colormap, &pixels[192], n, 0);
 /* we should not be doing this, but find that on SGI Indy's, the colormap
 never works unless we do an initial install */
 XInstallColormap(display, colormap);
 visual_class = PseudoColor; /* for user applications, this is 3 */
 return 1;
 }
 /*-------------------------------------------------------------------------*/
int setup_true24()
 {
 int	i;
 /* setup for a truecolor 24 bit visual, second choice is 32 bit */
 printf("trying for a 24 bit true color visual\n");
 if (XMatchVisualInfo(display, screen_num,24,TrueColor,&visual_info) == 0)
  { printf("could not find 24 bit depth visual, trying 32\n");
    if (XMatchVisualInfo(display, screen_num,32,TrueColor,&visual_info) == 0)
		return -1;	}
 vis = visual_info.visual;
 depth = visual_info.depth;
 printf("depth = %d\n", depth);
 /* masks ? */
 rmask = visual_info.red_mask; gmask = visual_info.green_mask; bmask = visual_info.blue_mask;
 get_shifts32();
 printf("rmask, gmask, bmask = %#x, %#x, %#x\n", rmask, gmask, bmask);
 printf("rshift32, gshift32, bshift32 = %#x, %#x, %#x\n", rshift32, gshift32, bshift32);
 colormap = XCreateColormap(display, RootWindow(display,screen_num),
        vis, AllocNone);
 //printf("visual id = %d\n", visual_info.visualid);
 /* reserve some of the 256 colors for fixed colors, hence */
 scalemin = 0;
 scalemax = 255 - FIXED_COLORS;
 visual_class = TrueColor; /* for user applications, this is 4 */
 true_color24 = 1;
 return 1;
 }
 /*-------------------------------------------------------------------------*/
int setup_true16()
 {
 int	i;
 /* setup for a truecolor 16 bit visual */
 if (!XMatchVisualInfo(display, screen_num, 16, TrueColor ,&visual_info))
 if (!XMatchVisualInfo(display, screen_num, 15, TrueColor ,&visual_info))
 	return -1;
 vis = visual_info.visual;
 depth = visual_info.depth;
 printf("depth = %d\n", depth);
 colormap = XCreateColormap(display, RootWindow(display,screen_num),
        vis, AllocNone);
 printf("in xport, colormap, vis, depth = %d %d %d\n", colormap, vis, depth);
 printf("in xport, *vis = %d\n", *vis);
 rmask = visual_info.red_mask;
 gmask = visual_info.green_mask;
 bmask = visual_info.blue_mask;
 get_shifts16();
 
 /* the lookup table is done for each window now, individually */
 /* reserve some of the 256 colors for fixed colors, hence */
 scalemin = 0;
 scalemax = 255 - FIXED_COLORS;
 visual_class = TrueColor; /* for user applications, this is 4 */
 return 1;
 }
 /*-------------------------------------------------------------------------*/
int setup_x()		/* connect and color table setup for a display */
 {
 unsigned        int     width, height;
 int     x,y;
 unsigned        int     border_width = 1;
 unsigned        int     icon_width, icon_height,class;
 /* unsigned        int     valuemask; */
 XTextProperty window, icon;
 XSizeHints      size_hints;
 XIconSize       *size;
 XWMHints        wm_hints;
 XClassHint      class_hints;
 int     count;
 XEvent  report;
 int     default_depth, default_planes, *depths, ndepth;
 int     vmatch, vs;
 int     window_size = 0;
 int     i, iq, nc, ic, ncontig, jq, icontig;
						  /* start execution here */
 if (!connect_flag) {            /* already done ?*/
   if ((display = XOpenDisplay(display_name)) == NULL) {
	   printf("can't connect to X display\n");  return -1; }
   XSetErrorHandler(xerr);		/* setup our own error handler */
   screen_num = DefaultScreen(display);
   screen = DefaultScreenOfDisplay(display);
   display_width = DisplayWidth(display, screen_num);
   display_height = DisplayHeight(display, screen_num);
   display_cells = DisplayCells(display, screen_num);
   printf("width, height, cells = %d %d %d\n",display_width, display_height,
   display_cells);
   printf("min, max # of color maps = %d, %d\n", MinCmapsOfScreen(screen),
 	  MaxCmapsOfScreen(screen));
   depths = XListDepths(display, screen_num, &ndepth);
   printf("# of available depths = %d\n", ndepth);
   for (i=0;i<ndepth;i++) { printf("depth: %d\n", depths[i]); }
   default_depth = DefaultDepth(display, screen_num);
   default_planes = DisplayPlanes(display, screen_num);
   /* 6/7/2008 - determine the client and server endians, 1 is bigendian or MSBFirst */
   { int one = 1; clientByteOrder = (*(char *)&one == 0); }
   screenByteOrder = ImageByteOrder(display);
   printf(" default depth, planes = %d %d\n", default_depth,default_planes);
   printf("client/server byte orders (1 is MSBFirst) = %d/%d\n", clientByteOrder, screenByteOrder);
 } /* end of initial connect */

 /* currently, we only do visual/colormap setups once */
 if (connect_flag) return 1;
 connect_flag = 1;
 if (true_color24) {
  if (setup_true24() != 1) { 
    printf("failed to setup 24 bit TrueColor, please try something else\n");
    return -1; }
  } else
  
 if (true_color16) {
  if (setup_true16() != 1) { 
    printf("failed to setup 16 bit TrueColor, please try something else\n");
    return -1; }
 } else
  /* disable the 16 bit search */
  if (setup_pseudo8() != 1) { 
    printf("failed to setup 8 bit PseudoColor, looking for a 16 bit visual\n");
    //if (setup_true16() != 1) {
    //printf("failed to setup 16 bit TrueColor, looking for 24 bit\n");
    if (setup_true24() != 1) {
    printf("failed with 8 bit, 16 bit, and 24 bit attempts\nno imaging possible");
    depth = 0;
    return -1;
    }
    //}
    }
 
 /* the GC's that were defined here to be shared by all windows are now
 defined separately for each one in order to support multiple visuals.
 A GC has to have the same depth as the visual used by a window.
 We only support one visual currently, so in the meantime it just helps
 by insuring that the GC's are properly created for the windows. The common
 practice of using the default window for the drawable in the GC blows up
 if the default visual isn't the one used.
 */
 visual_depth = depth;	/* the user readable depth */
 /* get an Atom for XSetWMProtocols for WN_DELETE_WINDOW */
 wm_delete = XInternAtom(display, "WM_DELETE_WINDOW", False);
 printf("wm_delete = %d\n", wm_delete);
 printf("end of setup\n");
 XSynchronize(display, True);
 return 1;
 }
/*-------------------------------------------------------------------------*/
int ana_xtvrct(narg,ps)	/* read color table, scale to 0-255 */
 /* this is under development */
 /* a function that returns a (3,ncol) array */
 int  narg, ps[];
 {
 /* if no arg, get the screen default color map */
 int i, ncolors, result_sym, dim[2];
 Colormap cmap;
 XColor *colors;
 char    *ptr;
 struct  ahead   *h;

 if (ck_events() != 1) return -1;
 cmap = colormap;
 if (narg == 0) {
 cmap =
  XListInstalledColormaps(display, RootWindow(display,screen_num), &i)[0];
 } else {
 }
 ncolors = ReadColors(vis, cmap, &colors);
 if (ncolors <= 0) return -1;
 printf("ncolors = %d\n", ncolors);
 /* only makes real sense for pseudo color, but can extend later */
 dim[0] = 3;   dim[1] = ncolors;
 result_sym = array_scratch(0, 2, dim);
 h = (struct ahead *) sym[result_sym].spec.array.ptr;
 ptr = (char *) ( (char *) h + sizeof( struct ahead ) );
 /* load as RGB, scale to 0-255 range */
 for (i = 0; i < ncolors; i++) {
  *ptr++ = (byte) (colors[i].red >> 8);
  *ptr++ = (byte) (colors[i].green >> 8);
  *ptr++ = (byte) (colors[i].blue >> 8);
 }
 free(colors);
 return result_sym;
 }
 /*-------------------------------------------------------------------------*/
int ana_xgetwinid(narg,ps)	/* get a window's ID */
 /* this is under development */
 /* a function that returns the ID of a window you click on if no args,
 otherwise returns the ID of the input ana window */
 int  narg, ps[];
 {
 int	result_sym, wid;
 if (ck_events() != 1) return -1;
 if (narg >=1 ) {
 if (int_arg_stat(ps[0], &wid) != 1) return -1;
 if (ck_window(wid) != 1) return -1;
 selected_window = win[wid];
 } else {
 selected_window = Select_Window(display);
 }
 //printf("selected_window = %d, %#x\n", selected_window,selected_window);
 /* now try for a better one */
 selected_window = XmuClientWindow (display, selected_window);
 //printf("selected_window = %d, %#x\n", selected_window,selected_window);
 result_sym = scalar_scratch(2);
 sym[result_sym].spec.scalar.l = (int) selected_window;
 return result_sym;
 }
 /*-------------------------------------------------------------------------*/
int ana_xtvlct(narg,ps)	/* load color table, scaling to available range */
 /* expect 3 arrays for RGB, range (0 - 1.0) */
 /* add the window as a fourth argument  11/3/99 */
 int  narg, ps[];
 {
 int	nc, iq, len[3], n, i, j, wid, cmax;
 float	fac, sfac;
 float	*p[3];
 struct	ahead	*h;
					 /* 3 args must be 1-D vectors */
 if (ck_events() != 1) return -1;
 for (i=0;i<3;i++) {
   iq = ps[i];
   if ( sym[iq].class != 4 ) return execute_error(66);
   h = (struct ahead *) sym[iq].spec.array.ptr;
   if ( h->ndim != 1) return execute_error(107); 	/* ck if 1-D */
   iq = ana_float(1, &iq);			/* float each one */
   h = (struct ahead *) sym[iq].spec.array.ptr;
   len[i] = h->dims[0];
   p[i] = (float *) ((char *)h + sizeof(struct ahead));
 }
 n = MIN(len[0], len[1]);	/* get smallest and use it for # to load */
 n = MIN(n, len[2]);
 /* printf("color n = %d\n", n); */
 fac = 65535.;
 /* determine the window */
 if (narg > 3) { if (int_arg_stat(ps[3], &wid) != 1) return -1; }
 	else wid = last_wid;
 if (ck_window(wid) != 1) return -1;
 if (wid < 0 ) { printf("color tables not supported for pixmaps\n");
 	return 0; }

 /* handle different visuals */
 /* presently 8 bit Pseudo and 16 bit TrueColor */
 
 if (depth == 8) {
   /* the 8 bit PseudoColor case, wid is not relevant and not used */
   nc = colormax - colormin + 1;
   sfac = (float) n / (float) nc;
   for (i=colormin;i <= colormax;i++) {
   cells[i].pixel = pixels[i]; cells[i].flags = DoRed|DoGreen|DoBlue;
   j = (int) rint( (float) (i- colormin) * sfac);
   /* printf("color table i = %d, j = %d\n", i,j); */
   cells[i].red   =  (unsigned short)( *(p[0] + j) * fac);
   cells[i].green  = (unsigned short)( *(p[1] + j) * fac);
   cells[i].blue   = (unsigned short)( *(p[2] + j) * fac);
   }
   /* 12/17/97 - but also insure that last cell is the last color in table,
   the first is already OK */
   n = n - 1;
   cells[colormax].red =   *(p[0] + n) * fac;
   cells[colormax].green = *(p[1] + n) * fac;
   cells[colormax].blue =  *(p[2] + n) * fac;
   /* printf("final colors\n"); */
   /*
   for (i=colormin;i <= colormax;i++) {
    printf("i, rgb = %d, %d %d %d\n", i, cells[i].red, cells[i].green, cells[i].blue);
   }
   printf("nc = %d\n", nc);
   */
   XStoreColors(display,colormap, &cells[colormin], nc);

 } else if (depth == 16 || depth == 15) {
   /* the 16 bit TrueColor case */
   //printf("color for 16, wid = %d\n", wid);
   cmax = 256 - FIXED_COLORS;
   sfac = (float) n / (float) cmax;
   lookup16truecolor = (short *) window_lookups[wid];
   for (i=0; i<cmax; i++) {
     j = (int) rint( (float) (i) * sfac);
     colorcell.red = (unsigned short) (*(p[0]+j)*fac);
     colorcell.blue = (unsigned short) (*(p[2]+j)*fac);
     colorcell.green = (unsigned short) (*(p[1]+j)*fac);
     XAllocColor(display,colormap, &colorcell);
     lookup16truecolor[i] = colorcell.pixel;
   }
 } else if (depth == 24 || depth == 32) {
   /* the 24 bit TrueColor case */
   cmax = 256 - FIXED_COLORS;
   sfac = (float) n / (float) cmax;
   lookup24truecolor = (unsigned int *) window_lookups[wid];
   for (i=0; i<cmax; i++) {
     j = (int) rint( (float) (i) * sfac);
     colorcell.red = (unsigned short) (*(p[0]+j)*fac);
     colorcell.blue = (unsigned short) (*(p[2]+j)*fac);
     colorcell.green = (unsigned short) (*(p[1]+j)*fac);
     XAllocColor(display,colormap, &colorcell);
     /* we need to check for server/client endian mismatch */
     if (clientByteOrder != screenByteOrder) swapl((char *)&colorcell.pixel,1);
     lookup24truecolor[i] = colorcell.pixel;
   }
 } else {
 printf("problem with X display, unsupported depth = %d\n", depth);
 return 0;
 }
 
 XFlush(display);                 /* or it won't happen for a long time */
 return 1;
 }
 /*-------------------------------------------------------------------------*/
int ana_xtvlctraw(narg,ps) /* load color table starting at first cell */
 /* expect 3 arrays for RGB, range 0-255, if number exceeds available
 cells, only that part will be loaded */
 int  narg, ps[];
 {
 int	nc, iq, len[3], n, i, j, nq;
 float	fac, sfac;
 union	types_ptr p[3];
 struct	ahead	*h;
					 /* 3 args must be 1-D vectors */
 if (ck_events() != 1) return -1;
 for (i=0;i<3;i++) {
 iq = ps[i];
 if ( sym[iq].class != 4 ) return execute_error(66);
 h = (struct ahead *) sym[iq].spec.array.ptr;
 if ( h->ndim != 1) return execute_error(107); 	/* ck if 1-D */
						 /* float each one */
 iq = ana_long(1, &iq);
 h = (struct ahead *) sym[iq].spec.array.ptr;
 len[i] = h->dims[0];
 p[i].l = (int *) ((char *)h + sizeof(struct ahead));
 }
 n = MIN(len[0], len[1]);	/* get smallest and use it for # to load */
 n = MIN(n, len[2]);
 nc = colormax - colormin + 1;
 if (n > nc)
   printf("warning, only first %d colors out of %d can be loaded\n",nc,n);
 nc = MIN(n, nc);
 fac = 256;
 
 j = 0;
 for (i=colormin;i < colormin+nc;i++) {
 cells[i].pixel = pixels[i]; cells[i].flags = DoRed|DoGreen|DoBlue;
 cells[i].red   =  (unsigned short)( *(p[0].l + j) * fac);
 cells[i].green =  (unsigned short)( *(p[1].l + j) * fac);
 cells[i].blue   = (unsigned short)( *(p[2].l + j) * fac);
 j++;
 }
 XStoreColors(display,colormap, &cells[colormin], nc);
 XFlush(display);                 /* or it won't happen for a long time */
 return 1;
 }
 /*-------------------------------------------------------------------------*/
int ana_xopen(narg,ps)  /* explicitly sets the display name for x setup */
 int  narg, ps[];
 {
 if ( sym[ ps[0] ].class != 2 ) return execute_error(70);
 display_name = strsave((char *) sym[ps[0] ].spec.array.ptr);
 return 1;
 }
 /*-------------------------------------------------------------------------*/
int ana_xexist(narg,ps)	/* return 1 if window exists */
 /* argument is port # */
 int  narg, ps[];
 {
 int     wid;
 if (int_arg_stat(ps[0], &wid) != 1) return -1;
 if (wid < 0 ) {
 if ( maps[-wid] != 0 ) return 1;
 } else {                                /* window case */
 if ( win[wid] != 0 ) return 1;
 }
 /* no such, return an ana 0 */
 return 4;
 }
 /*-------------------------------------------------------------------------*/
int ana_xport(narg,ps)	/* open a window or pixmap */
 /* arguments are port #, width , height (default is 512x512) */
 /* if window already open and no new size, get parameters */
 int  narg, ps[];
 {
 int     wid, mapid, xpos, ypos, pflag;
 unsigned        int     width, height;
 if (ck_events() != 1) return -1;
 wid = int_arg( ps[0] );
 width = height = 512;
 pflag = 0;  xpos = 0; ypos = 0;
 if (narg > 1 ) width = int_arg( ps[1] );      /*get width if specified */
 if (narg > 2 ) height = int_arg( ps[2] );     /*get height if specified */
 if (narg > 3 ) { pflag = 1;  xpos = int_arg( ps[3]);
   if (narg > 4 ) ypos = int_arg( ps[4]); }
 if (ck_window(wid) != 1) return -1;
 if (wid < 0 ) {
					 /* pixmap case */
 /* check if pixmap already created, if so and no size, just set last_wid */
 mapid = - wid;
 if ( maps[mapid] != 0 ) {
   if (narg < 2)
   { set_defw(wid);  return 1; } else { ana_xdelete(1,ps); }}
 } else {                                /* window case */
 /* check if window already created, if so and no size, just set last_wid,
 if a size specified, check if the same and re-do if not */
 /* also ignore resizing if it is a drawing area, instead the drawing area
 should be resized by the user (could do it here but ...) */
 if ( win[wid] != 0 ) {
   if (narg < 2)
   { set_defw(wid);  return 1; } else {
   /* need to check this size with existing size */
   /* if used for a drawing area, we don't want to allow resize here */
   if (drawingareas[wid] != 0) return 1;

   if (width == wd[wid] && height == ht[wid])
   { set_defw(wid);  return 1; } else {
    ana_xdelete(1,ps);} }}
 }
		 /* if we get here, we now create the window or pixmap */
 return  ana_xcreat(wid, height, width, xpos, ypos, pflag);
 
 }
 /*--------------------------------------------------------------------------*/
int ck_window(wid)	/* checks if a window value is in allowed range */
 int     wid;
 {
 int     mapid;
 //printf("wid = %d\n", wid);
 if (wid < 0 ) {                                 /* pixmap case */
 mapid = - wid;
 if ( mapid > MAXMAPS ) {
   printf("pixmap number range is 0 to %d, %d is out of range\n",maxmap, mapid);
   return -1; }
 } else {                                        /* window case */
 if ( wid > MAXWINDOW ) {
   printf("window number range is 0 to %d, %d is out of range\n",maxwin, wid);
   return -1; }
 }
 return  1;
 }
 /*-------------------------------------------------------------------------*/
int ck_events()		/* checks events for focus and size changes */
 /* updates the last_wid and any window sizes */
 /* will also change last_win to a window with a button or key pressed even
 if focus not changed; i.e., ANA's focus for a plot or tv can be changed
 without changing the X focus
 also note that the ANA "focus" will always be the last ANA window and ignores
 other windows including the xterm (or whatever) that ANA is running in */
 {
 XEvent  report;
 int     nev, i, j, iq;
 Window	wq;
 if (connect_flag != 1)
    if (setup_x() != 1 ) { printf("error in setup_x\n"); return -1; }

 XFlush(display);
 nev = XPending( display);
 /* printf("number of events = %d\n",nev); */
 if (nev <=0 ) { /*printf("no pending events\n");*/	return 1; }
 for (i=0;i<nev;i++) {
 XNextEvent(display, &report);
 switch (report.type) {
  case ButtonPress:
 wq = report.xbutton.window;
 break;
  case KeyPress:
 wq = report.xkey.window;
 break;
 /* 11/21/92 don't change the default ana window unless a button or key
	pressed or configuration changed; i.e., disable the focusin
	case below */
 /*  case FocusIn:
 wq = report.xfocus.window;
 break;
*/
  case ConfigureNotify:
 wq = report.xconfigure.window;
 break;
  case ClientMessage:
 /*
 printf("ClientMessage, window = %d\n", report.xclient.window);
 printf("format = %d\n", report.xclient.format);
 printf("atom = %d\n", report.xclient.data.l[0]);
 */
 /* check if window manager tried to kill a window */
 if ( (Atom) report.xclient.data.l[0] == wm_delete) {
 /* verify that it is an ANA window */
 iq = -1;
 for (j=0;j<MAXWINDOW;j++) {
 if (win[j] == report.xclient.window) { iq = j; break; } }
 wq = 0;	/* ensure we don't set pointer to it */
 if (iq != -1) {
 XDestroyWindow(display, report.xclient.window);
 win[iq] = 0;
 XFlush(display);                 /* or it won't vanish for a long time */
 } }
 break;
  default:
 wq = 0;
 break;
}
 /* which ANA window ? */
 if (wq != 0) {
 iq = -1;
 for (j=0;j<MAXWINDOW;j++) {
 if (win[j] == wq)
	 { iq = j; break; }
 }
 if (iq != -1)
  { last_wid = iq;
  if ( report.type == ConfigureNotify ) { wd[iq] = report.xconfigure.width;
   ht[iq] = report.xconfigure.height; }
   set_defw(iq); }
 } }
 return  1;
 }
 /*-------------------------------------------------------------------------*/
int set_defw(wid)	/* sets last_wid and plotting context */
 /* assumes window is defined */
 /* 5/19/96, added a check of current size in case it got changed via a motif
 drawing area */
 int     wid;
 {
 Bool	status;
 XWindowAttributes	wat;
 int     mapid;
 last_wid = wid;
 if (wid < 0 ) {                                 /* pixmap case */
 mapid = - wid;
 xfac = wdmap[mapid];    yfac = htmap[mapid];
 } else {                                        /* window case */
 status = XGetWindowAttributes(display, win[wid], &wat);
 xfac = wd[wid] = wat.width; yfac = ht[wid] = wat.height;
 /* printf("set_defw results, status %d, wid %d,wd %d, ht %d\n", status, wid,
 	wd[wid], ht[wid]); */
 }
 ixlow = 0;  iylow = 0;  ixhigh = xfac - 1;  iyhigh = yfac - 1;
 /* but now make xfac and yfac equal to the larger of the 2 */
 /* 5/27/96, think this should be smaller of the 2 instead ? */
 xfac = yfac = MAX( xfac, yfac);
 /* xfac = yfac = MIN( xfac, yfac); */
 /*printf("xfac, yfac = %e %e\n",xfac,yfac);
 printf("ixlow, iylow, ixhigh, iyhigh = %d %d %d %d\n",ixlow, iylow,
	 ixhigh, iyhigh);
 */
 return  1;
 }
 /*-------------------------------------------------------------------------*/
int ana_xcreat(wid, height, width, xpos, ypos, pflag)
 int  wid, xpos, ypos, pflag;
 unsigned        int     width, height;
 {
 int     xq, yq;
 unsigned        int     border_width = 1;
 unsigned        int     icon_width, icon_height, valuemask=0;
 static	char    window_name[64], icon_name[8], *pq;
 static	XTextProperty	windowName, iconName;
 XSizeHints      size_hints;
 XIconSize       *size;
 XWMHints        wm_hints;
 XClassHint      class_hints;
 int     count;
 XEvent  report;
 int     default_depth, default_planes;
 XVisualInfo     visual_info;
 XColor  cfore, cback;
 XVisualInfo     *visualList;
 XSetWindowAttributes    attributes;
 Cursor cursor;
 int     vmatch, vs;
 int     window_size = 0;
 int     i, iq, nc, ic, mapid,n,j;
  extern	Widget	ana_widget_id[];
 XWindowAttributes	wat;
						 /* start execution here */
 if (setup_x() != 1 ) { printf("error in setup_x\n"); return -1; }
 
 if (wid >= 0) {                 /* window case */
   /* if this window is associated with a motif drawing area, then the window
   will already be created (we check) and we just modify it a bit and setup
   the gc */
   if (drawingareas[wid] == 0) {
     /* not a drawing area, do all setups */
     wd[wid] = width;  ht[wid] = height;
     sprintf( window_name, "ana window %-2d", wid);
     sprintf( icon_name, "ana %-2d", wid);
     /* some things I've learned, if the visual is not the default, it is
     essential to define the border_pixel, also any GC defined must have the
     same depth as the visual used the window. So 8 bit and 16 bit windows
     can't use the same GC's. */
     valuemask = CWBorderPixel|CWBackPixel|CWColormap|CWEventMask|CWBitGravity;
     attributes.colormap = colormap;
     attributes.background_pixel = 0;
     attributes.border_pixel = 0;
     attributes.bit_gravity = StaticGravity;
     attributes.event_mask = ButtonPressMask|ButtonReleaseMask|KeyPressMask|ExposureMask;

     attributes.backing_store = WhenMapped; /*note that Always screws up things
					      not sure why yet */
     /* note that contents still disappear when window is iconized, may need
     to use our own pixmap to store and not count on server */
     valuemask |= CWBackingStore;


     //printf("depth = %d\n", depth);
     //printf("XCreateWindow start, width/height = %d/%d\n", width, height);

     win[wid] = XCreateWindow(display, RootWindow(display,screen_num), xpos, ypos,
      width, height, border_width, depth, InputOutput, vis, valuemask, &attributes);
     //printf("wid = %d, win[wid] = %d\n", wid, win[wid]);
     icon_pixmap = XCreateBitmapFromData(display, win[wid], icon_bitmap_bits,
	     icon_bitmap_width, icon_bitmap_height);

     wm_hints.initial_state = NormalState;
     wm_hints.input = True;
     wm_hints.icon_pixmap = icon_pixmap;
     wm_hints.flags = StateHint | IconPixmapHint | InputHint;

     if (pflag) size_hints.flags = USPosition | USSize;
       else size_hints.flags = PPosition | PSize;

     pq = &window_name[0];
     XStringListToTextProperty ( &pq, 1, &windowName);
     pq = &icon_name[0];
     XStringListToTextProperty ( &pq, 1, &iconName);

     XSetWMProperties(display, win[wid], &windowName, &iconName, 0 ,0 ,&size_hints
     ,&wm_hints, 0 );
     iq = XSetWMProtocols(display, win[wid], &wm_delete, 1);
     XSelectInput( display, win[wid], ExposureMask | KeyPressMask | 
	ButtonPressMask | StructureNotifyMask | SubstructureNotifyMask |
	FocusChangeMask );
   } else {
     /* a motif drawing area, if window not already created, return an error */
     /* assume we are using same display for X and Motif */
      //printf("setting up a window from drawing %d\n", drawingareas[wid]);
      //printf("widget %d\n", ana_widget_id[drawingareas[wid]]);
      if ((win[wid] = XtWindowOfObject(ana_widget_id[drawingareas[wid]])) == 0 ) {
	printf("cannot get window number from motif drawing area\n");
	return -1; }
     //printf("win[wid] = %d\n", win[wid]);
     if (XGetWindowAttributes(display, win[wid], &wat) == False) {
      printf("cannot get window attributes for motif drawing area\n");
      return -1; }
     ht[wid] = wat.width;	wd[wid] = wat.height;
     valuemask |= CWBackPixel;
     attributes.background_pixel = WhitePixel(display, screen_num);
     valuemask |= CWBackingStore;
     attributes.backing_store = WhenMapped; /*note that Always screws up things
					      not sure why yet */
     XChangeWindowAttributes(display, win[wid], valuemask, &attributes);
     /* XSelectInput( display, win[wid], ExposureMask | KeyPressMask | 
	ButtonPressMask | StructureNotifyMask | SubstructureNotifyMask |
	FocusChangeMask ); */
   }

   /* the gc and cursor setup are done for ordinary and drawing area windows */
   gc[wid] = XCreateGC(display, win[wid],0,NULL);
   /* because we may not be using the default visual, don't use BlackPixel
   or WhitePixel */
   //XSetForeground(display, gc[wid], BlackPixel(display, screen_num));
   //XSetBackground(display, gc[wid], WhitePixel(display, screen_num));
   XAllocNamedColor(display, colormap, "black", &colorcell, &rgb_def);
   XSetForeground(display, gc[wid], colorcell.pixel);
   XAllocNamedColor(display, colormap, "white", &colorcell, &rgb_def);
   XSetBackground(display, gc[wid], colorcell.pixel);
   /* also must do this because our erase use Clears */
   XSetWindowBackground(display,win[wid], colorcell.pixel);

   /* make a GC for drawing "not" lines in ana_xnotdraw */
   gcnot[wid] = XCreateGC(display, win[wid],0,NULL);
   XSetFunction(display, gcnot[wid], GXinvert);

   /* 5/15/96 changed from XC_crosshair */
   cursor = XCreateFontCursor(display, XC_top_left_arrow);
   XAllocNamedColor(display, colormap, "red", &cfore, &rgb_def);
   //XAllocNamedColor(display, colormap, "white", &cfore, &rgb_def);
   XAllocNamedColor(display, colormap, "black", &cback, &rgb_def);
   XRecolorCursor(display, cursor, &cfore, &cback);
   XDefineCursor(display, win[wid], cursor);
   XFreeCursor(display, cursor);

   /* mapping and waiting for the expose is not done for drawing areas */

   if (drawingareas[wid] == 0) {
     XMapWindow( display, win[wid]);
     XFlush(display);
     XSelectInput( display, win[wid], ExposureMask | KeyPressMask | 
      ButtonPressMask | StructureNotifyMask | SubstructureNotifyMask |
      FocusChangeMask );

     while (1) {           /* wait for the first expose event before returning */
     XNextEvent( display, &report);
     if ( report.type == Expose ) {
	     if ( report.xexpose.count == 0 ) break;  }
     }
   }
   /* and setup a lookup table if this is a true color visual */

    if (visual_class == TrueColor) {
     int	cmax, fac, j, i;
     cmax = 256 - FIXED_COLORS;
     fac = 65535./cmax;
     if (depth == 16 || depth == 15) {
      //printf("color lookup for wid %d\n", wid);
      window_lookups[wid] = (int *) malloc(256 * sizeof(short));
      lookup16truecolor = (short *) window_lookups[wid];
      for (i=0;i<cmax;i++) {
      colorcell.red = colorcell.blue = colorcell.green = (unsigned short) (i*fac);
      XAllocColor(display,colormap, &colorcell);
      lookup16truecolor[i] = colorcell.pixel;
      }
      /* fixed colors, awkward, should make cleaner */
      n = FIXED_COLORS;
      j = 255;
      for (i=0;i<n;i++) {
      XAllocNamedColor(display, colormap, fixed_color_names[i], &colorcell, &rgb_def);
      lookup16truecolor[j--] = colorcell.pixel;
      }
    }  else if (depth == 24 || depth == 32) {
      window_lookups[wid] = (int *) malloc(256 * sizeof(unsigned int));
      lookup24truecolor = (unsigned int *) window_lookups[wid];
      for (i=0;i<cmax;i++) {
	colorcell.red = colorcell.blue = colorcell.green = (unsigned short) (i*fac);
	XAllocColor(display,colormap, &colorcell);
	/* we need to check for server/client endian mismatch */
	if (clientByteOrder != screenByteOrder) swapl((char *)&colorcell.pixel,1);
	lookup24truecolor[i] = colorcell.pixel;
      }
      n = FIXED_COLORS;
      j = 255;
      for (i=0;i<n;i++) {
	XAllocNamedColor(display, colormap, fixed_color_names[i], &colorcell, &rgb_def);
	/* we need to check for server/client endian mismatch */
	if (clientByteOrder != screenByteOrder) swapl((char *)&colorcell.pixel,1);
	lookup24truecolor[j--] = colorcell.pixel;
      }
    }

   }

 } else {                                /* pixmap case */
   mapid = - wid;
   if ( mapid > MAXMAPS ) {
     printf("pixmap number range is 0 to %d, %d is out of range\n", mapid,maxmap);
     return -1; }
   if (maps[mapid] == 0)
     maps[mapid] = XCreatePixmap(display, RootWindow(display,screen_num),
	    width, height, depth);
   wdmap[mapid] = width;  htmap[mapid] = height;
   gcmap[mapid] = XCreateGC(display, maps[mapid],0,NULL);
   XSetForeground(display, gcmap[mapid], BlackPixel(display, screen_num));
   XSetBackground(display, gcmap[mapid], WhitePixel(display, screen_num));
   /* a special gc for "erasing" pixmaps */
   gcmaperase[mapid] = XCreateGC(display, maps[mapid],0,NULL);
   XSetForeground(display, gcmaperase[mapid], WhitePixel(display, screen_num));
   XSetBackground(display, gcmaperase[mapid], WhitePixel(display, screen_num));
   gcmapnot[mapid] = XCreateGC(display, maps[mapid],0,NULL);
   XSetFunction(display, gcmapnot[mapid], GXinvert);
 }
 set_defw(wid);
 //printf("done in ana_xcreat\n");
 return 1;
 }
 /*-------------------------------------------------------------------------*/
int ana_xsetinputs(narg,ps)		/* set the input mask */
 int  narg, ps[];
 {
 int    wid, iq;
 Cursor cursor;
 if (ck_events() != 1) return -1;
 if (int_arg_stat(ps[0], &wid) != 1) return -1;
 if (ck_window(wid) != 1) return -1;
 XSelectInput( display, win[wid],  KeyPressMask | ButtonPressMask);
 return 1;
 }
 /*-------------------------------------------------------------------------*/
int ana_xcursor(narg,ps)		/* set the cursor */
 int  narg, ps[];
 {
 int    wid, iq;
 Cursor cursor;
 XColor	cfore, cback;
 char	*cfore_default = {"red"};
 char	*cback_default = {"black"};
 char	*pc;
 if (ck_events() != 1) return -1;
 if (int_arg_stat(ps[0], &wid) != 1) return -1;
 if (int_arg_stat(ps[1], &iq) != 1) return -1;
 if (ck_window(wid) != 1) return -1;
 cursor = XCreateFontCursor(display, iq);
 if (narg > 2) {
 /* get foreground color */
 if ( sym[ ps[2] ].class != 2 ) return execute_error(70);
 pc = (char *) sym[ps[2] ].spec.array.ptr;
 } else { pc = cfore_default; }
 if ( XAllocNamedColor(display, colormap, pc, &cfore, &rgb_def) != 1 )
 	{printf("error in cursor foreground color\n");  return -1; }
 if (narg > 3) {
 /* get background color */
 if ( sym[ ps[3] ].class != 2 ) return execute_error(70);
 pc = (char *) sym[ps[3] ].spec.array.ptr;
 } else { pc = cback_default; }
 if ( XAllocNamedColor(display, colormap, pc, &cback, &rgb_def) != 1 )
 	{printf("error in cursor background color\n");  return -1; }
 XRecolorCursor(display, cursor, &cfore, &cback);
 XDefineCursor(display, win[wid], cursor);
 XFreeCursor(display, cursor);
 XFlush(display);
 return 1;
 }
 /*-------------------------------------------------------------------------*/
int ana_xsetbackground(narg,ps)		/* set the background color */
 /* setbackground, window, color */
 int  narg, ps[];
 {
 int    wid, iq;
 unsigned long	pix;
 char	*pc;
 if (ck_events() != 1) return -1;
 if (int_arg_stat(ps[0], &wid) != 1) return -1;
 if (ck_window(wid) != 1) return -1;
 /* try to figure out the color */
 /* a string ? */
 if ( sym[ ps[1] ].class != 2 ) return execute_error(70);
 pc = (char *) sym[ps[1] ].spec.array.ptr;
 if ( XAllocNamedColor(display, colormap, pc, &colorcell, &rgb_def) != 1 )
 	{printf("error in background color\n");  return -1; }
 if (wid < 0 )  {		                   /* pixmap case */
 if ( maps[-wid] == 0 ) ana_xcreat(wid, 512, 512,0,0,0);
 XSetBackground(display, gcmap[-wid], colorcell.pixel);
 XSetWindowBackground(display, maps[-wid], colorcell.pixel);
 } else {                                                /* window case */
 /* does window exist? If not create a default size */
 if ( win[wid] == 0 ) ana_xcreat(wid, 512, 512,0,0,0);
 XSetBackground(display, gc[wid], colorcell.pixel);
 XSetWindowBackground(display,win[wid], colorcell.pixel);
 }
 /* printf("colorcell.pixel = %d\n", colorcell.pixel);*/
 background_color = (long) colorcell.pixel;
 XFlush(display);
 return 1;
 }
 /*-------------------------------------------------------------------------*/
int ana_xsetforeground(narg,ps)		/* set the foreground color */
 int  narg, ps[];
 {
 int    wid, iq;
 unsigned long	pix;
 char	*pc;
 if (ck_events() != 1) return -1;
 if (int_arg_stat(ps[0], &wid) != 1) return -1;
 if (ck_window(wid) != 1) return -1;
 /* try to figure out the color */
 /* a string ? */
 if ( sym[ ps[1] ].class != 2 ) return execute_error(70);
 pc = (char *) sym[ps[1] ].spec.array.ptr;
 if ( XAllocNamedColor(display, colormap, pc, &colorcell, &rgb_def) == 0 )
 	{printf("error in foreground color\n");  return -1; }
 return setforegroundcolor( wid);
 }
 /*-------------------------------------------------------------------------*/
int setforegroundcolor(int wid)
 {
 foreground_color = (long) colorcell.pixel;
 if (wid < 0 )  {			                 /* pixmap case */
 if ( maps[-wid] == 0 ) ana_xcreat(wid, 512, 512,0,0,0);
 XSetForeground(display, gcmap[-wid], colorcell.pixel);
 } else {                                                /* window case */
 /* does window exist? If not create a default size */
 if ( win[wid] == 0 ) ana_xcreat(wid, 512, 512,0,0,0);
 XSetForeground(display, gc[wid], colorcell.pixel);
 }
 /* printf("colorcell.pixel = %d\n", colorcell.pixel);*/
 XFlush(display);
 return 1;
 }
 /*-------------------------------------------------------------------------*/
int getXcolor(char *name, float *red, float *green, float *blue, int flag)
 {
 /* messy, if flag is 0, we just lookup the rgb values for the named color,
 if flag = 1, we also look it up and then apply it to the default X window,
 both of the above return the rgb values in red, green, blue
 if flag = 2, the red, green, blue are inputs to be used for the default
 X window drawing color */
 
 if ( ck_events() != 1) return -1;
 if (flag != 2) {
 if ( XLookupColor(display, colormap, name, &rgb_def, &colorcell) != 1 )
 	{printf("error in XLookupColor\n");  return -1; }
 *red = (float) rgb_def.red;
 *green = (float) rgb_def.green;
 *blue = (float) rgb_def.blue;
 } else {
 rgb_def.red = (unsigned short) 65535.* *red;
 rgb_def.green = (unsigned short) 65535.* *green;
 rgb_def.blue= (unsigned short) 65535.* *blue;
 }
 if (flag) {
 	if ( XAllocColor(display, colormap, &colorcell) == 0)
	 { printf("WARNING: could not allocate color cell\n"); return 1; }
	 return setforegroundcolor( last_wid);
 }
 return 1;
 }
 /*-------------------------------------------------------------------------*/
int ana_xdelete(narg,ps)		/* delete a window or a pixmap */
 int  narg, ps[];
 {
 int    wid, i;
 /* 7/10/2004 - allow several and loop */
 for (i=0;i<narg;i++) {
   if (int_arg_stat(ps[i], &wid) != 1) return -1;
   if (ck_window(wid) != 1) return -1;
   if (wid < 0 )  {			                 /* pixmap case */
   XFreePixmap(display, maps[-wid]);
   maps[-wid] = 0;
   } else {                                                /* window case */
   XDestroyWindow(display, win[wid]);
   win[wid] = 0; }
 }
 XFlush(display);                 /* or it won't vanish for a long time */
 return 1;
 }
 /*--------------------------------------------------------------------------*/
int ana_xraise(narg,ps)			/* raise (popup) a window */
 int  narg, ps[];
 {
 int    wid, i;
 /* 7/10/2004 - allow several and loop */
 for (i=0;i<narg;i++) {
   if (int_arg_stat(ps[i], &wid) != 1) return -1;
   if (ck_window(wid) != 1) return -1;
   /* a no-op for a pixmap */
   if ( wid >= 0 ) {
   if ( win[wid] == 0 ) return -1;
   XRaiseWindow(display, win[wid]);
   }
 }
 return 1;
 }
 /*--------------------------------------------------------------------------*/
int ana_xlower(narg,ps)			/* lower a window */
 int  narg, ps[];
 {
 int    wid, i;
 for (i=0;i<narg;i++) {
   if (int_arg_stat(ps[i], &wid) != 1) return -1;
   if (ck_window(wid) != 1) return -1;
   /* a no-op for a pixmap */
   if ( wid >= 0 ) {
   if ( win[wid] == 0 ) return -1;
   XLowerWindow(display, win[wid]);
   }
 }
 return 1;
 }
 /*--------------------------------------------------------------------------*/
int ana_xerase(narg,ps)			/* erase a window */
 int  narg, ps[];
 {
 int    wid, x,y,h,w, mapid;
 if (ck_events() != 1) return -1;
 if (narg > 0) { if (int_arg_stat(ps[0], &wid) != 1) return -1; }
	else wid = last_wid;
 if (ck_window(wid) != 1) return -1;
 if (wid < 0 ) {
 /* for pixmaps, we have to use rectangle fill since there isn't
 a defined background */
 /* 2/24/97 but the fill puts in the foreground color and we want to load with
 the background. No easy way to  just switch them so we assume the standard
 background for the erase and create a GC with this as foreground! */
 x=y=0;
 mapid = - wid;
 if ( maps[mapid] == 0 ) ana_xcreat(wid, 512, 512,0,0,0);
 w= wdmap[mapid];  h = htmap[mapid];
 XFillRectangle(display, maps[mapid], gcmaperase[mapid], x,y,w,h);
 /*printf("sorry, can't erase a pixmap\n"); return -1;*/
 } else {
 if ( win[wid] == 0 ) ana_xcreat(wid, 512, 512,0,0,0);
 /* 10/31/94 allow clearing a part using XClearArea */
 if ( narg < 2) XClearWindow(display, win[wid]); else {
 /* more complicated partial clear */
 x=y=h=w=0;
 if (narg > 1) { if (int_arg_stat(ps[1], &x) != 1) return -1; }
 if (narg > 2) { if (int_arg_stat(ps[2], &y) != 1) return -1; }
 if (narg > 3) { if (int_arg_stat(ps[3], &w) != 1) return -1; }
 if (narg > 4) { if (int_arg_stat(ps[4], &h) != 1) return -1; }
 XClearArea(display, win[wid], x,y,w,h, False);
 }
 XFlush(display);                 /* or it won't vanish for a long time */
 }
 return 1;
 }
 /*------------------------------------------------------------------------*/
int ana_xtv(narg,ps)
 int narg, ps[];
 /* 11/30/95 (Zoe's birthday!) started modifying to do all the orientations
 the normal tv scan has the image upside down wrt cart. and people often
 want to have images in cart. coords. which is !iorder=0, tv scan is 2,
 support all the others even though they are rarely used */
 /* call is: tv, image, [ix, iy, win] */
 {
 extern	int	iorder;
 int	i,iq, *ptr, nx, ny, nd,ix,iy,wid, mapid, nxx, nyy, hq, wq, n, m;
 byte	*p, *q, *qsave;
 struct  ahead   *h;
 if (ck_events() != 1) return -1;
 iq = ps[0];
 wid = last_wid;
 if ( sym[iq].class != 4 ) return execute_error(66);
 h = (struct ahead *) sym[iq].spec.array.ptr;
 nd = h->ndim;
 if ( nd != 2) { printf("xtv - array must be 2-D\n");  return -1; }
 nx = h->dims[0];        ny = h->dims[1];
 ix = 0;         iy = 0;
 if (narg > 1) { if (int_arg_stat(ps[1], &ix) != 1) return -1; }
 if (narg > 2) { if (int_arg_stat(ps[2], &iy) != 1) return -1; }
 if (narg > 3) { if (int_arg_stat(ps[3], &wid) != 1) return -1; }
 if (iorder % 2 == 0) {hq = iy+ny; wq = ix+nx; } else {hq = iy+nx; wq = ix+ny;}
 if (wid < 0 ) {
 /* does pixmap exist? If not create to fit image */
  mapid = -wid;                                   /* pixmap case */
 if ( maps[mapid] == 0 ) ana_xcreat(wid, hq, wq,0,0,0);
 hq = htmap[mapid];	wq = wdmap[mapid];
 } else {			/* window case */
 /* does window exist? If not create to fit image */
 if ( win[wid] == 0 ) ana_xcreat(wid, hq, wq,0,0,0);
 hq = ht[wid];	wq = wd[wid];
 window_mod_flag[wid] = 0;
 }
 /* check if image fits (at least partially) in the window/pixmap */
 /* now check if in the window, this was modified to support all orientations
 the odd ones flip nx and ny */
 if (iorder % 2 == 0) { nxx = MIN( nx, wq - ix);  nyy = MIN( ny, hq - iy); }
 	else { nxx = MIN( ny, wq - ix);  nyy = MIN( nx, hq - iy); }
 if ( nxx < 0 || nyy < 0 ) {
	 printf("xtv - completely off window\n"); return -1; }
 if ( sym[iq].type != 0 ) {
 /* scale using current values of scalemax and scalemin */
 iq = ana_scale(1, &ps[0]); }
 h = (struct ahead *) sym[iq].spec.array.ptr;
 ptr = (int *) ( (char *) h + sizeof( struct ahead ) );
 
 /* if the orientation is not 2, then we have to flip the image using
 another buffer, malloc what we need now. Note that we need to deallocate
 this later */
 
 if (iorder != 2) {
 q = qsave = (byte *) malloc(nx*ny);
 p = (byte *) ptr;
 switch (iorder) {
 case 0:	/* common, cart. coord case, just reverse in y */
 q = q + nx * ny;	m = ny;
 while (m--) {	q = q - nx;  n = nx;  while (n--) *q++ = *p++; q = q - nx;
 } break;
 case 4:	/* transpose in x and y, note nx and ny interchanged */
 m = ny;  ny = nx;  nx = m;
 q = q + nx*ny;
 while (m--) { n = ny;  while (n--) {  q -= nx; *q = *p++; } q = q +nx*ny+1;
 } break;
 case 6:	/* transpose plus reverse in x, note nx and ny interchanged */
 m = ny;  ny = nx;  nx = m;
 while (m--) { n = ny;  while (n--) { *q = *p++;  q += nx; } q = q -nx*ny+1;
 } break;
 case 3:	/* reverse in x */
 m = ny;
 while (m--) {	q = q + nx;  n = nx;  while (n--) *--q = *p++; q = q + nx;
 } break;
 case 7:	/* transpose plus reverse in y, note nx and ny interchanged */
 m = ny;  ny = nx;  nx = m;  q = q + nx -1;
 while (m--) { n = ny;  while (n--) { *q = *p++;  q += nx; } q = q -nx*ny-1;
 } break;
 case 1:	/* reverse in x and y */
 q = q + nx * ny;	m = ny;
 while (m--) { n = nx;  while (n--) *--q = *p++;
 } break;
 case 5:	/* transpose plus reverse in x,y, note nx and ny interchanged */
 m = ny;  ny = nx;  nx = m;  q = q + ny*nx -1;
 while (m--) { n = ny;  while (n--) { *q = *p++;  q -= nx; } q = q +nx*ny-1;
 } break;
 }
 ptr = (int *) qsave;
 }
 
		 /* create image structure */
 if (depth == 8) {
   xi = XCreateImage(display,vis,8,ZPixmap,0, (char *) ptr ,nx,ny,8,0);
 if (wid < 0 ) {
   mapid = - wid;
   XPutImage(display, maps[mapid], gcmap[mapid], xi, 0,0,ix,iy, nxx,nyy);
 } else {
   /* printf("xtv, win[wid], gc[wid] %d %d\n", win[wid], gc[wid]);*/
                        	 /* window case */
   /*printf("some tv details, ix %d, iy %d, nxx %d, nyy %d\n", ix,iy,nxx,nyy);*/
   XPutImage(display, win[wid], gc[wid], xi, 0,0,ix,iy, nxx,nyy);
 }
 /* now dealloc the image structure but not the data if iorder = 2 */
 if (iorder == 2) xi->data = NULL;
 } else if (depth == 16 || depth == 15) {
 short	*p16, *psave;
 p = (byte *) ptr;
 /* need a 16 bit image array for the display */
 p16 = psave = (short *) malloc(nx*ny*sizeof(short));
 /* use current lookup table to translate */
 lookup16truecolor = (short *) window_lookups[wid];
 m = ny*nx;  while (m--) *p16++ = lookup16truecolor[*p++];
 xi = XCreateImage(display,vis,depth,ZPixmap,0,(char *) psave ,nx,ny,16,0);
 XPutImage(display, win[wid], gc[wid], xi, 0,0,ix,iy, nxx,nyy);
 /* destroyImage will zap p16 but we also need to get qsave if iorder != 2 */
 if (iorder != 2) free(qsave);
 } else if (depth == 24 || depth == 32) {
   /* 24 and 32 currently treated almost the same, unless the 24 depth
   actually uses 24 bit pixels (varies by system) */
   unsigned int	*p24, *psave;
   byte	*p = (byte *) ptr;
   /* use current lookup table to translate */
   lookup24truecolor = (unsigned int *) window_lookups[wid];
   xi = XCreateImage(display,vis,depth,ZPixmap,0, NULL ,nx,ny,8,0);
   /* use 8 for bitpad in case we have 24 bit pixels, otherwise need to pad */
   /* we can now check if this has 24 or 32 bit pixels, many 24 depths actually
   use 32 bit pixels but not all */
   //printf("xi->bits_per_pixel = %d\n", xi->bits_per_pixel);
   //printf("xi->byte_order = %d, LSBFirst, MSBFirst are %d, %d\n", xi->byte_order,LSBFirst, MSBFirst);
   if (xi->bits_per_pixel == 24) {
   /* note that the visual info block doesn't tell us the bits_per_pixel */
   /* need a 24 bit image array for the display */
   int	n, nd4, nr;
   int	x1, x2, x3, x4;
   unsigned int	*pin, *pout, *p24;
   p = (byte *) ptr;
   n = xi->width * xi->height;
   pout = psave = (unsigned int *) malloc( ((n*3+3)/4) * sizeof(unsigned int));
   nd4 = n/4;
   nr = n - nd4*4;
#if LITTLEENDIAN
   while (nd4--) {
     x1 = lookup24truecolor[*p++];
     x2 = lookup24truecolor[*p++];
     *pout++ = x1 + ((x2 & 0xff) << 24);
     x3 = lookup24truecolor[*p++];
     *pout++ = (x2 >> 8) + ( x3 << 16);
     x4 = lookup24truecolor[*p++];
     *pout++ = (x3 >> 16) + (x4 << 8);
   }
   if (nr > 0) {
     x1 = lookup24truecolor[*p++];
     if (nr > 1) x2 = lookup24truecolor[*p++]; else x2 = 0;
     *pout++ = x1 + ((x2 & 0xff) << 24);
     if (nr > 2) x3 = lookup24truecolor[*p++]; else x3 = 0;
     if (nr > 1) *pout++ = (x2 >> 8) + ( x3 << 16);
     if (nr > 2) *pout++ = (x3 >> 16);
     }
#else
   while (nd4--) {
     x1 = lookup24truecolor[*p++];
     x2 = lookup24truecolor[*p++];
     *pout++ = x1 << 8 + x2 >> 16;
     x3 = lookup24truecolor[*p++];
     *pout++ = x2 << 16 + x3 >> 16;
     x4 = lookup24truecolor[*p++];
     *pout++ = x3 << 24 + x4;
   }
   if (nr > 0) {
     x1 = lookup24truecolor[*p++];
     if (nr > 1) x2 = lookup24truecolor[*p++]; else x2 = 0;
     *pout++ = x1 << 8 + x2 >> 16;
     if (nr > 2) x3 = lookup24truecolor[*p++]; else x3 = 0;
     if (nr > 1) *pout++ = x2 << 16 + x3 >> 16;
     if (nr > 2) *pout++ = x3 << 24;
     } 
#endif
 } else {
   /* assume 32 bit pixels */
   p24 = psave = (unsigned int *) malloc(nx*ny*sizeof(unsigned int));
   p = (byte *) ptr;
   /* use current lookup table to translate */
   /* but check if the server/client byte orders match, we may have to reverse */
   m = ny*nx;  while (m--) *p24++ = lookup24truecolor[*p++];
 }
 xi->data = (char *) psave;
 XPutImage(display, win[wid], gc[wid], xi, 0,0,ix,iy, nxx,nyy);
 /* destroyImage will zap p24 but we also need to get qsave if iorder != 2 */
 if (iorder != 2) free(qsave);
 } else {
   printf("problem with X display, unsupported depth = %d\n", depth);
   return 0;
 }
 XDestroyImage( xi);
 XFlush(display);
 /* set the globals to corners of image */
 tvix = ix;	tvixb = ix + nxx;
 tviy = MAX(0, hq - iy - nyy);	tviyb = MIN( hq - 1, tviy + nyy);
 return 1;
 }
 /*------------------------------------------------------------------------*/
int ana_tv16(narg,ps)
 int narg, ps[];
 /* this may be a temporary routine, use for directly writing a 16 bit
 array to a 16 bit display. Could be part of a more general tv routine perhaps.
 */
 /* call is: tv16, image, [ix, iy, win] */
 {
 int	i,iq, *ptr, nx, ny, nd,ix,iy,wid, nxx, nyy, hq, wq, n;
 struct  ahead   *h;
 if (ck_events() != 1) return -1;
 iq = ps[0];
 wid = last_wid;
 if ( sym[iq].class != 4 ) return execute_error(66);
 if ( sym[iq].type != 1 ) return execute_error(111);
 h = (struct ahead *) sym[iq].spec.array.ptr;
 nd = h->ndim;
 if ( nd != 2) { printf("tv16 - array must be 2-D\n");  return -1; }
 nx = h->dims[0];        ny = h->dims[1];
 ix = 0;         iy = 0;
 if (narg > 1) ix = int_arg( ps[1] );
 if (narg > 2) iy = int_arg( ps[2] );
 if (narg > 3) wid = int_arg( ps[3] );
 /* check depth, to avoid misuse */
 if (depth != 16 && depth != 15) {
 	printf("tv16 only intended for 16 (or 15) bit visuals\n");
	return 0; }
 hq = iy+ny; wq = ix+nx;
 if (wid < 0 ) {
  /* don't support pixmaps since this may not be a permanent routine */
  printf("tv16 does not support pixmaps\n");
  return 0;
 } else {			/* window case */
 /* does window exist? If not create to fit image */
 if ( win[wid] == 0 ) ana_xcreat(wid, hq, wq,0,0,0);
 hq = ht[wid];	wq = wd[wid];
 }
 /* ignore iorder, so always in orientation 2 */
 nxx = MIN( nx, wq - ix);  nyy = MIN( ny, hq - iy);
 ptr = (int *) ( (char *) h + sizeof( struct ahead ) );

 xi = XCreateImage(display,vis,depth,ZPixmap,0, (char *) ptr ,nx,ny,
 	16,0);
 XPutImage(display, win[wid], gc[wid], xi, 0,0,ix,iy, nxx,nyy);
 xi->data = NULL;
 XDestroyImage(xi);
 XFlush(display);
 return 1;
 }
 /*------------------------------------------------------------------------*/
int ana_tv16lookup(narg,ps)
 int narg, ps[];
 /* this may be a temporary routine, use for writing a 16 bit array to a
 16 bit display using a 16in/16out lookup table. Could be part of a more
 general tv routine perhaps.
 */
 /* call is: tv16lookup, image, lookup, [ix, iy, win]
 both image and lookup must be 16 bits */
 {
 int	i,iq, nx, nxlt, ny, nd,ix,iy,wid, nxx, nyy, hq, wq, n;
 short	*psave, *lookup;
 unsigned short	*ptr;
 struct  ahead   *h;
 if (ck_events() != 1) return -1;
 wid = last_wid;
 iq = ps[0];
 if ( sym[iq].class != 4 ) return execute_error(66);
 if ( sym[iq].type != 1 ) return execute_error(111);
 h = (struct ahead *) sym[iq].spec.array.ptr;
 nd = h->ndim;
 if ( nd != 2) { printf("tv16lookup - array must be 2-D\n");  return -1; }
 nx = h->dims[0];        ny = h->dims[1];
 ptr = (unsigned short *) ( (char *) h + sizeof( struct ahead ) );
 /* get lookup table */
 iq = ps[1];
 if ( sym[iq].class != 4 ) return execute_error(66);
 if ( sym[iq].type != 1 ) return execute_error(111);
 h = (struct ahead *) sym[iq].spec.array.ptr;
 nd = h->ndim;
 nxlt = h->dims[0];
 if ( nd != 1 || nxlt != 65536) {
 	printf("tv16lookup - lookup table must be 65536 and 1-D\n"); 
	return -1; }
 lookup = (short *) ( (char *) h + sizeof( struct ahead ) );
 
 ix = 0;         iy = 0;
 if (narg > 2) { if (int_arg_stat(ps[2], &ix) != 1) return -1; }
 if (narg > 3) { if (int_arg_stat(ps[3], &iy) != 1) return -1; }
 if (narg > 4) { if (int_arg_stat(ps[4], &wid) != 1) return -1; }
 /* check depth, to avoid misuse */
 if (depth != 16 && depth != 15) {
 	printf("tv16 only intended for 16 (or 15) bit visuals\n");
	return 0; }
 hq = iy+ny; wq = ix+nx;
 if (wid < 0 ) {
  /* don't support pixmaps since this may not be a permanent routine */
  printf("tv16 does not support pixmaps\n");
  return 0;
 } else {			/* window case */
 /* does window exist? If not create to fit image */
 if ( win[wid] == 0 ) ana_xcreat(wid, hq, wq,0,0,0);
 hq = ht[wid];	wq = wd[wid];
 }
 /* ignore iorder, so always in orientation 2 */
 nxx = MIN( nx, wq - ix);  nyy = MIN( ny, hq - iy);

 /* need a 16 bit image array for the display */
 psave = (short *) malloc(nx*ny*sizeof(short));
 /* use current lookup table to translate */
 {
  /* the unfolding didn't seem to help on a PC, perhaps done anyway by
  the compiler */
  register unsigned short	*p;
  register short	*p16;
  register int	nd4;
  int	m, nr;
  p = ptr;
  p16 = psave;
  m = ny*nx;
  nd4 = m/4;	nr = m - 4*nd4;
  while (nd4-- >0) {
   *p16++ = lookup[*p++];
   *p16++ = lookup[*p++];
   *p16++ = lookup[*p++];
   *p16++ = lookup[*p++];
  }
 /* the rest */
   while (nr-- >0) *p16++ = lookup[*p++];
 }
 xi = XCreateImage(display,vis,depth,ZPixmap,0, (char *) psave ,nx,ny,
 	16,0);
 XPutImage(display, win[wid], gc[wid], xi, 0,0,ix,iy, nxx,nyy);
 //xi->data = NULL;
 XDestroyImage(xi);
 XFlush(display);
 return 1;
 }
 /*------------------------------------------------------------------------*/
int ana_tvrct16(narg,ps)
 int narg, ps[];
 /* a function, returns a color mapping for 16 bit truecolor visual,
 this may not be a permanent function. Returned is a 16 bit array with the
 best available colors for the RGB inputs. */
 /* 1/17/00 - modified for dual purpose, if there is a single scalar
 argument, we read back the color table for that window. This is more
 consistent with tvrct usage which will call this routine for 15/16 bit
 visuals. */
 {
 int	result_sym, dim[1], *ptr;
 int	nc, iq, len[3], n, i, j, wid;
 float	fac, sfac;
 float	*p[3];
 struct	ahead	*h;
 if (ck_events() != 1) return -1;
 /* check depth, to avoid misuse */
 if (depth != 16 && depth != 15) {
 	printf("tvrct16 only intended for 16 (or 15) bit visuals\n");
	return 0; }
 if (narg == 1) {
   if (int_arg_stat(ps[0], &wid) != 1) return -1;
   if (ck_window(wid) != 1) return -1;
   if (wid < 0) { printf("tvrct16 - pixmaps not supported\n");  return; }
   if ( win[wid] == 0 ) ana_xcreat(wid, 512, 512,0,0,0);
   dim[0] = 256;
   result_sym = array_scratch(2, 1, dim);
   h = (struct ahead *) sym[result_sym].spec.array.ptr;
   ptr = (int *) ( (char *) h + sizeof( struct ahead ) );
   /* we assume that the 16 bit lookups are 256 I*2 long */
   bcopy((char *) ptr, (char *) window_lookups[wid], 512);

 } else {

   for (i=0;i<3;i++) {
     iq = ps[i];
     if ( sym[iq].class != 4 ) return execute_error(66);
     h = (struct ahead *) sym[iq].spec.array.ptr;
     if ( h->ndim != 1) return execute_error(107); 	/* ck if 1-D */
     iq = ana_float(1, &iq);			/* float each one */
     h = (struct ahead *) sym[iq].spec.array.ptr;
     len[i] = h->dims[0];
     p[i] = (float *) ((char *)h + sizeof(struct ahead));
   }
   n = MIN(len[0], len[1]);	/* get smallest and use it for # to load */
   n = MIN(n, len[2]);
   fac = 65535.;
   printf("n = %d\n", n);


   dim[0] = n;
   result_sym = array_scratch(2, 1, dim);
   h = (struct ahead *) sym[result_sym].spec.array.ptr;
   ptr = (int *) ( (char *) h + sizeof( struct ahead ) );
   /* the 16 bit TrueColor case */
   for (i=0; i<n; i++) {
     colorcell.red = (unsigned short) (*(p[0]+i)*fac);
     colorcell.blue = (unsigned short) (*(p[2]+i)*fac);
     colorcell.green = (unsigned short) (*(p[1]+i)*fac);
     XAllocColor(display,colormap, &colorcell);
     *ptr++ = colorcell.pixel;
   }
 }
 return result_sym;
 }
 /*------------------------------------------------------------------------*/
int ana_tvconvert16(narg,ps)
 int narg, ps[];
 /* a function, converts a three color (rgb component) image into
 a 16 bit truecolor image by just scaling to the available color
 components in the 16 bit table. The input is 3 byte arrays representing
 rgb. Returns a 16 bit array ready for display with tv16.
 call is: x16 = tvconvert16(r, g, b) */
 {
 int	result_sym, dim[2];
 int	xq, yq;
 short	*ptr;
 int	nc, iq, nx, ny, n, i, j, m;
 float	fac, sfac;
 byte	*p[3];
 struct	ahead	*h;
 if (ck_events() != 1) return -1;
 /* check depth, to avoid misuse */
 if (depth != 16 && depth != 15) {
 	printf("tvconvert16 only intended for 16 (or 15) bit visuals\n");
	return 0; }
 if (ck_events() != 1) return -1;
 for (i=0;i<3;i++) {
 iq = ps[i];
 if ( sym[iq].class != 4 ) return execute_error(66);
 if ( sym[iq].type != 0 ) return execute_error(118);
 h = (struct ahead *) sym[iq].spec.array.ptr;
  if (i) {
    if (h->dims[0] != nx || h->dims[1] != ny)
    	return execute_error(103);
  } else { nx = h->dims[0];  ny = h->dims[1]; }
 p[i] = (byte *) ((char *)h + sizeof(struct ahead));
 }
 dim[0] = nx;   dim[1] = ny;
 result_sym = array_scratch(1, 2, dim);
 h = (struct ahead *) sym[result_sym].spec.array.ptr;
 ptr = (short *) ( (char *) h + sizeof( struct ahead ) );

 /* get the ranges in the 16 bit truecolor representation */
 n = m = nx * ny;
 while (m--) {
  xq = *p[2]++;
  if (bshift > 0) xq = xq << bshift;  else  xq = xq >> (-bshift);
  yq = xq & bmask;
  xq = *p[1]++;
  if (gshift > 0) xq = xq << gshift;  else  xq = xq >> (-gshift);
  yq = yq | (xq & gmask);
  xq = *p[0]++;
  if (rshift > 0) xq = xq << rshift;  else  xq = xq >> (-rshift);
  *ptr++ = (short) (yq | (xq & rmask));
 }
 return result_sym;
 }
 /*------------------------------------------------------------------------*/
int ana_tvblend_mov(narg,ps)
 int narg, ps[];
 {
 /* takes 2 images, does all the clipping to get common overlap (including
 the output window boundary) and uses current "blend" mapping to make a
 16 bit result and puts it into output window. Used for displaying "on the
 fly" overlay (blended) movies.
 call is: tvblend_mov(m1, it1, m2, it2, ix1, iy1, ix2, iy2, wout)
 where m1 and m2 must be symbol arrays of 2-D images */
 /* ix1, iy1 are the coords of the cutout for the it1 image in m1 while
 ix2, iy2 are the cutout for m2. These define the offset between the 2
 images and the lower LHS in the output window. A negative value means
 that the window extends beyond the image. The remaining parts of the
 images and the size of the window clip the result. Empty sections of the
 window can be optionally erased; if not, whatever was there is unchanged.*/

 static	unsigned short *pshort = NULL, *pshort2 = NULL;
 static	int bsize = 0, last_wq, last_hq;
 static XImage  *xi;
 int	i, iq, wout, nd, ip, j, nz, nx[2], ny[2], class, wq, hq, mq;
 unsigned char *sptr[2], *p1, *p2;
 unsigned short *p3, *out;
 int	ix1, iy1, ix2, iy2, xfac, yfac, m, n, nxs1, nxs2;
 int	i1, i2, j1, j2, i1p, i2p, j1p, j2p;
 struct	ahead	*h;
 struct sym_desc *psym;
 XWindowAttributes	wat;
 /* check depth, to avoid misuse, also need to have connected to X */
 if (ck_events() != 1) return -1;
 if (depth != 16 && depth != 15) {
 	printf("tvblend_mov only intended for 16 (or 15) bit visuals\n");
	return 0; }
 /* get pointers and sizes of the 2 images */
 for (i=0;i<2;i++) {
 iq = i * 2;
 class = sym[ps[iq]].class;
 if (class != SYM_ARR) return execute_error(135);
 h = (struct ahead *) sym[ps[iq]].spec.array.ptr;
 nd = h->ndim;
 nz = 1; for (j=0;j<nd;j++) nz *= h->dims[j];	/*# of elements */
 /* get the idex for the desired image */
 if (int_arg_stat(ps[iq + 1], &ip) != 1) return -1;
 if (ip >= nz || ip < 0)
 { printf("tvblend_mov - out of range symbol (%d)\n", ip);  return -1; }
 psym = (struct sym_desc *) ((char *)h + sizeof(struct ahead));
 psym = psym + ip;
 /* this is now a pointer to the specified symbol, check if 2-D, etc */
 if ( psym->class != ARRAY) return execute_error(66);
 h = (struct ahead *) psym->spec.array.ptr;
 nd = h->ndim;
 if ( (nd != 2) || psym->type != 0) {
 	printf("tvblend_mov - symbol must be 2-D I*1\n");  return -1; }
 nx[i] = h->dims[0];        ny[i] = h->dims[1];
 sptr[i] = (unsigned char *) ( (char *) h + sizeof( struct ahead ) );
 }
 /* grab the remaining arguments */
 if (int_arg_stat(ps[4], &ix1) != 1) return -1;
 if (int_arg_stat(ps[5], &iy1) != 1) return -1;
 if (int_arg_stat(ps[6], &ix2) != 1) return -1;
 if (int_arg_stat(ps[7], &iy2) != 1) return -1;
 if (int_arg_stat(ps[8], &wout) != 1) return -1;
 
 /* get size of window */
 if (wout < 0 ) {
 j = - wout;
 xfac = wdmap[j];	yfac = htmap[j];
 } else {
 xfac = wd[wout];	yfac = ht[wout];
 }
 /* work out image limits within window */
 /* not doing zoom yet */
 if (ix1 < 0) i1 = -ix1; else i1 = 0;
 if (iy1 < 0) j1 = -iy1; else j1 = 0;
 xfac = xfac - 1;
 yfac = yfac - 1;
 i2 = i1 + nx[0] - 1 - ix1;
 j2 = j1 + ny[0] - 1 - iy1;
 i1 = MIN(i1, xfac);
 i2 = MIN(i2, xfac);
 j1 = MIN(j1, yfac);
 j2 = MIN(j2, yfac);

 if (ix2 < 0) i1p = -ix2; else i1p = 0;
 if (iy2 < 0) j1p = -iy2; else j1p = 0;
 i2p = i1p + nx[1] - 1 - ix2;
 j2p = j1p + ny[1] - 1 - iy2;
 i1p = MIN(i1p, xfac);
 i2p = MIN(i2p, xfac);
 j1p = MIN(j1p, yfac);
 j2p = MIN(j2p, yfac);
 
 /* get overlap, already clipped to window */
 i1 = MAX(i1, i1p);
 i2 = MIN(i2, i2p);
 j1 = MAX(j1, j1p);
 j2 = MIN(j2, j2p);
 if (i1 >= i2 || j1 >= j2) {
  /* no overlap, just return */
  return 1;
 }
 
 /* compute size of array and allocate, if done previously, try to re-use */
 wq = i2 - i1 + 1;
 hq = j2 - j1 + 1;
 //printf("wq, hq = %d %d\n", wq, hq);
 mq = 2*wq*hq;
 if (mq > bsize) {
   if (pshort != NULL) free(pshort);
   pshort = (unsigned short *) malloc(mq);
   bsize = mq;
  }
 
 /* get starting positions in each array */
 p1 = sptr[0] + i1 + ix1 + nx[0]* (j1 + iy1);
 p2 = sptr[1] + i1 + ix2 + nx[1]* (j1 + iy2);
 nxs1 = nx[0] - wq;
 nxs2 = nx[1] - wq;
 //printf("nxs1, nxs2 = %d %d\n", nxs1, nxs2);
 p3 = pshort;
 if (look16to16 == NULL) {
  printf("allocating for look16to16\n");
  look16to16 = (unsigned short *) malloc(256*256*2);
 }
 out = (unsigned short *) look16to16;
 n = hq;
 while (n--) {
  m = wq;
  while (m--) {
  iq = (unsigned int) *p1++ + (((unsigned int) (*p2++)) << 8);
  *p3++ = out[iq];
  }
  p1 = p1 + nxs1;
  p2 = p2 + nxs2;
 }
 
 /* we keep the last XImage and re-use if possible, this assumes that
 we always are working with the same depth in a given session. Here we
 only support the 15/16 bit images for blends. */
 if (wq != last_wq || hq != last_hq) {
   /* too bad, destroy the old xi but not the data (done separately) */
   if (xi != NULL) {
    xi->data = NULL;
    XDestroyImage(xi);
   }
   /* create a new one */
 xi = XCreateImage(display,vis,depth,ZPixmap,0,(char *) pshort, wq, hq, 16, 0);
 last_wq = wq;	last_hq = hq;
 }
 /* now display the result */
 //printf("i1,j1, wq,hq = %d %d %d %d\n", i1,j1, wq,hq);
 /* 12/12/2000 - also check for blank areas to erase */
 if (clear_outside_flag) {
  int	x, y, w, h;
  if (i1 > 0) {
    x = y = h = 0;
    w = i1;
    XClearArea(display, win[wout], x,y,w,h, False);
   }
 if (j1 > 0) {
    x = y = w = 0;
    h = j1;
    XClearArea(display, win[wout], x,y,w,h, False);
   }
 if ( (i1+wq) <= xfac) {
    h = w = y = 0;
    x = i1 + wq;
    XClearArea(display, win[wout], x,y,w,h, False);
   }
 if ((j1+hq) <= yfac) {
    h = w = x = 0;
    y = j1 + hq;
    XClearArea(display, win[wout], x,y,w,h, False);
   }
 }
 XPutImage(display, win[wout], gc[wout], xi, 0,0,i1,j1, wq,hq);
 XFlush(display);
 
 return 1;
 }
 /*------------------------------------------------------------------------*/
int ana_tvmix16ct(narg,ps)
 int narg, ps[];
 /* 1/17/00 - modified to allow first 2 arguments to be window #'s if
 they are scalars rather than arrays */
 /* a function, generates a 16x16 color table for mixing 2 8 bit images.
 May be temporary whilst I test ideas. For 16 bit visuals only. */
 /* call is  table = tvmix16ct(map1, map2, fac, base)
 where fac and base control the mixing, if fac = 0, then base =(0,256) does
 linear interpolation between the 2 images. More generally, an alpha is
 computed using fac*image2 + base. The image2 value is the entry # in map2
 (normally the intensity increases with entry #).
 */
 {
 int	iq, nd, nx, nd2, nx2, m, n, dim[2], result_sym, wid;
 short	*out, *map1, *map2;
 struct	ahead	*h;
 float	fac, base;
 /* check depth, to avoid misuse, also need to have connected to X */
 if (ck_events() != 1) return -1;
 if (depth != 16 && depth != 15) {
 	printf("tvmix16ct only intended for 16 (or 15) bit visuals\n");
	return 0; }
 /* the 2 color maps, these are normally 256 long */
 /* 1/17/00 - could also be window ID's, then we get the color map for
 the window */
 iq = ps[0];
 if ( sym[iq].class == 1 ) {
  /* get color map for window */
  if (int_arg_stat(iq, &wid) != 1) return -1;
  if (ck_window(wid) != 1) return -1;
  if (wid < 0) { printf("tvmix16ct - pixmaps not supported\n");  return; }
  if ( win[wid] == 0 ) ana_xcreat(wid, 512, 512,0,0,0);
  map1 = (short *) window_lookups[wid];
  nd = 1;  nx = 256;
 } else {
  /* color map input as an array */
  if ( sym[iq].class != 4 ) return execute_error(101);
  if ( sym[iq].type != 1 ) return execute_error(111);
  h = (struct ahead *) sym[iq].spec.array.ptr;
  nd = h->ndim;
  nx = h->dims[0];
  map1 = (short *) ((char *)h + sizeof(struct ahead));
 }
 iq = ps[1];
 if ( sym[iq].class == 1 ) {
  /* get color map for window */
  if (int_arg_stat(iq, &wid) != 1) return -1;
  if (ck_window(wid) != 1) return -1;
  if (wid < 0) { printf("tvmix16ct - pixmaps not supported\n");  return; }
  if ( win[wid] == 0 ) ana_xcreat(wid, 512, 512,0,0,0);
  map2 = (short *) window_lookups[wid];
  nd2 = 1;  nx2 = 256;
 } else {
  /* color map input as an array */
 if ( sym[iq].class != 4 ) return execute_error(101);
 if ( sym[iq].type != 1 ) return execute_error(111);
 h = (struct ahead *) sym[iq].spec.array.ptr;
 nd2 = h->ndim;
 nx2 = h->dims[0];
 map2 = (short *) ((char *)h + sizeof(struct ahead));
 }
 if ( nd != 1 || nd2 != 1) {
   printf("tvmix16 - color map arrays must be 1-D\n");  return -1; }
 if (nx != 256 || nx2 != 256) {
   printf("tvmix16 - color map arrays must be 256 long\n");  return -1; }
 /* the mixing factor is optional, if not present or < 0, we use the
 second image to determine an overlay alpha */
 fac = 1.0;	base = 0.0;
 if (narg > 2) { if (float_arg_stat(ps[2], &fac) != 1) return -1; }
 if (narg > 3) { if (float_arg_stat(ps[3], &base) != 1) return -1; }
 /* all checking done */
 dim[0] = 256*256;
 result_sym = array_scratch(1, 1, dim);
 h = (struct ahead *) sym[result_sym].spec.array.ptr;
 out = (short *) ((char *)h + sizeof(struct ahead));
 {
  int	xq, yq, in1, in2, a, ac, zq, pix1, pix2;
  int	yqr, yqb, yqg, i;
  short	 *mq;
  rmask = visual_info.red_mask;
  gmask = visual_info.green_mask;
  bmask = visual_info.blue_mask;
  i = 0;
  m = 256;
  while (m--) {
  pix2 = (int) *map2++;
  ac = (int) (fac * (float) (i++) + base);
  ac = MIN(ac, 256);   ac = MAX(ac, 0);  a = 256 - ac;
  yqb = (pix2 & bmask) * ac;
  yqg = (pix2 & gmask) * ac;
  yqr = (pix2 & rmask) * ac;
  mq = map1;	n = 256;
   while (n--) {
    pix1 = (int) *mq++;
    xq = (pix1 & bmask) * a;
    zq = ((xq + yqb) >> 8) & bmask;
    xq = (pix1 & gmask) * a;
    zq = zq | (((xq + yqg) >> 8) & gmask);
    xq = (pix1 & rmask) * a;
    zq = zq | (((xq + yqr) >> 8) & rmask);
    *out++ = (short) zq;
   }
  }
 }
 return result_sym;
 }
 /*------------------------------------------------------------------------*/
void blend_out(w3, nx, ny, ptr)
 int	w3, nx, ny;
 unsigned short	*ptr;
 {
 /* used by ana_tvmix16win and tvreblend */
 int	m;
 unsigned short	*out;
 m = nx*ny;
 out = (unsigned short *) look16to16;
 /* if a null ptr is passed, we set up an XImage, otherwise assume already
 done and valid, we then destroy it here */
 if (!ptr) {
 ptr = (unsigned short *) malloc(nx*ny*2);
 xi = XCreateImage(display,vis,depth,ZPixmap,0,(char *) ptr,nx,ny,16,0);
 }
 {
 unsigned short	*p1, *p2;
 p1 = ptr;
 p2 = (unsigned short *) blend_imc;
 /* now convert */
 while (m--) *p1++ = out[*p2++];
 }

 /* now check the output window size and match to nx, ny if necessary */
 if ( win[w3] == 0 ) ana_xcreat(w3, ny, nx,0,0,0);
 nx = MIN(nx, wd[w3]); 	ny = MIN(ny, ht[w3]);
 /* these are always matched, so all 0 offsets */
 /* only need to consider areas on right and bottom */
 if (clear_outside_flag) {
  int	x, y, w, h;
  if (nx < wd[w3]) {
     h = w = y = 0;
     x = nx;
     XClearArea(display, win[w3], x,y,w,h, False);
    }
  if (ny < ht[w3]) {
     h = w = x = 0;
     y = ny;
     XClearArea(display, win[w3], x,y,w,h, False);
    }
  }
 
 XPutImage(display, win[w3], gc[w3], xi, 0,0,0,0, nx,ny);
 XDestroyImage(xi);  /* should also free ptr */
 }
 /*------------------------------------------------------------------------*/
int ana_blend_ct(narg,ps)
 int narg, ps[];
 /* return a copy of the internal blend color mapping */
 {
 unsigned short	*p3;
 unsigned short	*out;
 struct	ahead	*h;
 int	dim[2], result_sym;
 if (look16to16 == NULL) {
 printf("allocating for look16to16\n");
 look16to16 = (unsigned short *) malloc(256*256*2);
 }
 out = (unsigned short *) look16to16;
 dim[0] = 256*256;
 result_sym = array_scratch(1, 1, dim);
 h = (struct ahead *) sym[result_sym].spec.array.ptr;
 p3 = (unsigned short *) ((char *)h + sizeof(struct ahead));
 bcopy((char *) p3, (char *) out, 256*256*2);
 return result_sym;
 }
  /*------------------------------------------------------------------------*/
int ana_blend_test(narg,ps)
 int narg, ps[];
/* blend_test(x1, x2), compute a blended image from byte arrays x1 and x2 */
 {
 byte	*p1, *p2;
 unsigned short	*p3;
 int	iq, nd, nx, ny, nd2, nx2, ny2, *map1, *map2, m;
 int	result_sym, mfac, mix_flag;
 short	*fac;
 unsigned short	*out;
 struct	ahead	*h;
 if (ck_events() != 1) return -1;
 /* first the 2 image arrays */
 iq = ps[0];
 if ( sym[iq].class != 4 ) return execute_error(101);
 if ( sym[iq].type != 0 ) return execute_error(118);
 h = (struct ahead *) sym[iq].spec.array.ptr;
 nd = h->ndim;
 nx = h->dims[0];        ny = h->dims[1];
 p1 = (byte *) ((char *)h + sizeof(struct ahead));
 iq = ps[1];
 if ( sym[iq].class != 4 ) return execute_error(101);
 if ( sym[iq].type != 0 ) return execute_error(118);
 h = (struct ahead *) sym[iq].spec.array.ptr;
 nd2= h->ndim;
 nx2 = h->dims[0];        ny2 = h->dims[1];
 p2 = (byte *) ((char *)h + sizeof(struct ahead));
 if ( nd != 2 || nd2 != 2) {
   printf("blend_test - image arrays must be 2-D\n");  return -1; }
 if (nx != nx2 || ny != ny2) {
   printf("blend_test - image arrays must match in size\n");  return -1; }
 result_sym = array_clone(iq, 1);
 h = (struct ahead *) sym[result_sym].spec.array.ptr;
 p3 = (unsigned short *) ((char *)h + sizeof(struct ahead));
 m = nx * ny;
 if (look16to16 == NULL) {
   printf("allocating for look16to16\n");
   look16to16 = (unsigned short *) malloc(256*256*2);
 }
 out = (unsigned short *) look16to16;
 {
   unsigned int	iq;
   int	nd4, nr;
   nd4 = m/4;	nr = m - nd4*4;
   /* now convert */
   //while (m--) {
   /* the unwrap (x4) improves timing about 15% on the SGI O2 */
   while (nd4--) {
      iq = (unsigned int) *p1++ + (((unsigned int) (*p2++)) << 8);
      //iq = iq + (((unsigned int) (*p2++)) << 8);
      //printf("*p1, *p2 = %d, %d, iq = %d\n",*p1, *p2, iq);
      //printf("iq = %d\n", iq);
      *p3++ = out[iq];
      iq = (unsigned int) *p1++ + (((unsigned int) (*p2++)) << 8);
      *p3++ = out[iq];
      iq = (unsigned int) *p1++ + (((unsigned int) (*p2++)) << 8);
      *p3++ = out[iq];
      iq = (unsigned int) *p1++ + (((unsigned int) (*p2++)) << 8);
      *p3++ = out[iq];
    }
    while (nr-- >0) {
      iq = (unsigned int) *p1++ + (((unsigned int) (*p2++)) << 8);
      *p3++ = out[iq];
    }

 }
 return result_sym;
 }
 /*------------------------------------------------------------------------*/
void get_shifts16()
 {
 /* sets up shifts, assumes masks already in rmask, gmask, and bmask
 the masks may come from several sources */
 /* the shifts are computed for conversion to an 8 bit color */
 int rtop, btop, gtop, xq;
 rshift = bshift = gshift = 0;
 rtop = btop = gtop = 0;
 xq = rmask;
 while (xq) { xq >>= 1; rtop++; }
 rshift = rtop - 8;
 xq = gmask;
 while (xq) { xq >>= 1; gtop++; }
 gshift = gtop - 8;
 xq = bmask;
 while (xq) { xq >>= 1; btop++; }
 bshift = btop - 8;
 }
 /*------------------------------------------------------------------------*/
void get_shifts32()
 {
 /* sets up shifts for 24/32 bit color, assumes masks already in rmask, gmask, and bmask
 the masks may come from several sources */
 /* the shifts are computed for conversion to an 8 bit color */
 int rtop, btop, gtop, xq;
 rtop = btop = gtop = 0;
 xq = rmask;
 while (xq) { xq >>= 1; rtop++; }
 rshift32 = rtop - 8;
 xq = gmask;
 while (xq) { xq >>= 1; gtop++; }
 gshift32 = gtop - 8;
 xq = bmask;
 while (xq) { xq >>= 1; btop++; }
 bshift32 = btop - 8;
 }
 /*------------------------------------------------------------------------*/
int ana_tvmix16win(narg,ps)
 int narg, ps[];
 /* 1/28/2000 - added yet another parameter for allowing opacity to
 use luminance rather than index */
 /* modified from tvmix16ct, this also reads the window contents to
 make a final blended image in a destination window */
 /* a subroutine, call is tvmix16win(w1, w2, w3, fac, base, black, mode)
 where fac and base control the mixing, if fac = 0, then base =(0,256) does
 linear interpolation between the 2 images. More generally, an alpha is
 computed using fac*image2 + base. The image2 value is the entry # in map2
 (normally the intensity increases with entry #).
 */
 {
 int	iq, nd, nx, nd2, nx2, m, n, dim[2], result_sym, w1, w2, w3;
 int	ny, i, black256, alpha_mode;
 unsigned short	*out, *map1, *map2, *ptr;
 unsigned short	*p2;
 byte	*im1, *im2, *pq, *rlook, *imc;
 struct	ahead	*h;
 float	fac, base, black_level;
 //double	t1, t2, t3, t4, ta1, ta2, ta3, ta4, tb1, tb2, tb3, tb4;
 Drawable        *src;
 /* check depth, to avoid misuse, also need to have connected to X */
 //t1 = systime();
 if (ck_events() != 1) return -1;
 if (depth != 16 && depth != 15) {
 	printf("tvmix16ct only intended for 16 (or 15) bit visuals\n");
	return 0; }
 
 /* the 2 color maps, these are normally 256 long */
 /* 1/17/00 - only window ID's for tvmix16win */
 iq = ps[0];
  /* get color map for window 1 */
  if (int_arg_stat(iq, &w1) != 1) return -1;
  if (ck_window(w1) != 1) return -1;
  if (w1 < 0) { printf("tvmix16win - pixmaps not supported\n");  return; }
  if ( win[w1] == 0 ) ana_xcreat(w1, 512, 512,0,0,0);
  map1 = (unsigned short *) window_lookups[w1];
  nd = 1;  nx = 256;
 iq = ps[1];
  /* get color map for window 2 */
  if (int_arg_stat(iq, &w2) != 1) return -1;
  if (ck_window(w2) != 1) return -1;
  if (w2 < 0) { printf("tvmix16win - pixmaps not supported\n");  return; }
  if ( win[w2] == 0 ) ana_xcreat(w2, 512, 512,0,0,0);
  map2 = (unsigned short *) window_lookups[w2];
 iq = ps[2];
  /* get destination window 3 */
  if (int_arg_stat(iq, &w3) != 1) return -1;
  if (ck_window(w3) != 1) return -1;
  if (w3 < 0) { printf("tvmix16win - pixmaps not supported\n");  return; }
 /* the destination window will be sized to the smaller of w1 and w2 */

 /* find the smaller of the 2 windows */
 nx = MIN(wd[w1], wd[w2]);  ny = MIN(ht[w1],ht[w2]);

 /* we try to avoid repeatedly reading from the source windows by checking
 if they have been modified since our last blend, the 16 bit combined
 result is saved in blend_imc. If this has not been init'ed, force the
 window reads anyhow by setting the mod flags. Also check the size
 and force a new malloc if it has changed. */
 
 if (nx != blend_nx || ny != blend_ny)
 	{ if (blend_imc) { free(blend_imc); blend_imc = NULL; }}
 if (blend_imc == NULL) { 
	window_mod_flag[w1] = window_mod_flag[w2] = 0; }
 /* also check if the windows have changed! zero appropiate flag if so */
 if (blend_w1 != w1) window_mod_flag[w1] = 0;
 if (blend_w2 != w2) window_mod_flag[w2] = 0;
 if (look16to16 == NULL) look16to16 = (unsigned short *) malloc(256*256*2);
 ptr = NULL;	/* used for 16 bit images both in and out */
 rlook = (byte *) look16to16;
 //ta1 = systime();
 /* bit BLEND_BITA is used to check if we have a blend calculation
 for this window as the first one */
#define BLEND_BITA 0x1
#define BLEND_BITB 0x2
 if (!(window_mod_flag[w1] & BLEND_BITA)) {
   /* get reverse lookup table for first window */
   /* we get twice what we need here because we'll re-use the space */
   /* keep the space for next call, may be able to use unchanged final
   table */
   bzero(rlook, 256*256);
   for (i=0;i<256;i++) rlook[map1[i]] = i;
   //ta2 = systime();

   /* extract the image from first window, specialized for 16 bit depth */
   src = &(win[w1]);
   ptr = (unsigned short *) malloc(nx*ny*2);
   /* note that we create our own image and use XGetSubImage */
   xi = XCreateImage(display,vis,depth,ZPixmap,0,(char *) ptr,nx,ny,16,0);
   XGetSubImage(display, *src, 0, 0, nx, ny, 0xffffffff, ZPixmap, xi, 0, 0);
   /* now get the 8 bit version using the reverse lookup table */
   //ta3 = systime();
   m = nx*ny;
   /* although the window has changed, we may still have a useful blend_imc
   array, the second image may even be unchanged. Note we already checked
   if size was valid. */
   if (!blend_imc) {
     printf("new blend_imc, nx, ny = %d %d\n", nx, ny);
     blend_imc = (unsigned short *) malloc(m*2);
     window_mod_flag[w2] &= ~BLEND_BITA; /* must force update of second window */
   }
   imc = pq = (byte *) blend_imc;
   /* starting point is endian dependent of course */
#if LITTLEENDIAN
#else
   pq++;
#endif
   /* imc will be the combined image, load even bytes with first window result */
   p2 = (unsigned short *) ptr;
   while (m--) { *pq++ = rlook[*p2++]; pq++; }
   window_mod_flag[w1] |= BLEND_BITA;
   XDestroyImage(xi);
 }
 //ta4 = tb1 = systime();

 /* now extract the 8 bit result from the second window */
 if (!(window_mod_flag[w2] & BLEND_BITB)) {
   bzero(rlook, 256*256);
   for (i=0;i<256;i++) rlook[map2[i]] = i;
   //tb2 = systime();
   src = &(win[w2]);
   /* we may already have a buffer and an XImage */
   if (!ptr) {
     ptr = (unsigned short *) malloc(nx*ny*2);
     /* note that we create our own image and use XGetSubImage */
     xi = XCreateImage(display,vis,depth,ZPixmap,0,(char *) ptr,nx,ny,16,0);
   }
   XGetSubImage(display, *src, 0, 0, nx, ny, 0xffffffff, ZPixmap, xi, 0, 0);
   //tb3 = systime();
   m = nx*ny;
   pq = (byte *) blend_imc;
#if LITTLEENDIAN
   pq++;
#endif
   p2 = (unsigned short *) ptr;
   /* now load the odd ones */
   while (m--) { *pq++ = rlook[*p2++]; pq++; }
   window_mod_flag[w2] |= BLEND_BITB;
   XDestroyImage(xi);
 }
 /* where are we? imc has the 2 images from w1 and w2 loaded in the
 even and odd bytes. map1 and map2 still have the color tables. rlook
 can now be re-used for the 16->16 map. ptr can then be converted
 and sent to window w3. */

 //t2 = tb4 = systime();
 /* the mixing factor is optional, if not present or < 0, we use the
 second image to determine an overlay alpha */
 fac = 1.0;	base = 0.0;	black_level = alpha_mode = 0.0;
 if (narg > 3) { if (float_arg_stat(ps[3], &fac) != 1) return -1; }
 if (narg > 4) { if (float_arg_stat(ps[4], &base) != 1) return -1; }
 if (narg > 5) { if (float_arg_stat(ps[5], &black_level) != 1) return -1; }
 if (narg > 6) { if (float_arg_stat(ps[6], &alpha_mode) != 1) return -1; }
 black256 = (int) (256.* black_level);
 black256 = MIN(black256, 256);	black256 = MAX(black256, 0);
 /* generate lookup table, 16 in 16 out */
 out = (unsigned short *) look16to16;
 {
  int	xq, yq, in1, in2, a, ac, zq, pix1, pix2;
  int	yqr, yqb, yqg, i;
  unsigned short	 *mq;
  /* move masks and shifts to setup of X so we do it only once */
//   rmask = xi->red_mask;
//   gmask = xi->green_mask;
//   bmask = xi->blue_mask;
//   get_shifts16();
  /* need some extra stuff if alpha_mode is 1 */
  i = 0;
  m = 256;
  while (m--) {
  pix2 = (int) *map2++;
  if (alpha_mode) {
   /* compute luminance and use for computing alpha */
   xq = (pix2 & rmask);
   if (rshift > 0) xq = xq >> rshift;  else  xq = xq << (-rshift);
   yq = (xq & 0xff) * 77;
   xq = (pix2 & bmask);
   if (bshift > 0) xq = xq >> bshift;  else  xq = xq << (-bshift);
   yq = yq + (xq & 0xff) * 29;
   xq = (pix2 & gmask);
   if (gshift > 0) xq = xq >> gshift;  else  xq = xq << (-gshift);
   yq = yq + (xq & 0xff) * 150;
   yq = yq >> 8;
   ac = (int) (fac * ((float) yq - black_level));
  } else {
   /* just use index value */
   ac = (int) (fac * ((float) (i++) - black_level));
  }
  ac = MAX(ac, 0);
  ac = ac + base;
  ac = MIN(ac, 256);   ac = MAX(ac, 0);  a = 256 - ac;
  yqb = (pix2 & bmask) * ac;
  yqg = (pix2 & gmask) * ac;
  yqr = (pix2 & rmask) * ac;
  mq = map1;	n = 256;
   while (n--) {
    pix1 = (int) *mq++;
    xq = (pix1 & bmask) * a;
    zq = ((xq + yqb) >> 8) & bmask;
    xq = (pix1 & gmask) * a;
    zq = zq | (((xq + yqg) >> 8) & gmask);
    xq = (pix1 & rmask) * a;
    zq = zq | (((xq + yqr) >> 8) & rmask);
    *out++ = (unsigned short) zq;
   }
  }
 }
 //t3 = systime();

 /* out can now be used to convert imc to the desired result in xi/ptr */
 blend_nx = nx;		blend_ny = ny;
 blend_w1 = w1;		blend_w2 = w2;		blend_w3 = w3;

 blend_out(w3, nx, ny, ptr);

 //t4 = systime();
 //printf("time for part 1: %g\ntime for part 2: %g\ntime for part 3: %g\n",
 //	t2-t1, t3-t2,t4-t3);
 //printf("total time = %g\n", t4 - t1);
 //printf("details, first image: %g %g %g\n",
 //	ta2-ta1, ta3-ta2, ta4-ta3);
 //printf("details, first image: %g %g %g\n",
 //	tb2-tb1, tb3-tb2, tb4-tb3);
 XFlush(display);
 return 1;
 }
 /*------------------------------------------------------------------------*/
int ana_tvmix24win(narg,ps)
 int narg, ps[];
 /* modified from tvmix16win, this reads the window contents to
 make a final blended image in a destination window */
 /* a subroutine, call is tvmix24win(w1, w2, w3, fac, base, black, mode)
 where fac and base control the mixing, if fac = 0, then base =(0,256) does
 linear interpolation between the 2 images. More generally, an alpha is
 computed using fac*image2 + base. The image2 value is the luminance of
 that image. The color table index, used for the tvmix16win routine, is not
 available here.
 */
 {
 int	iq, nd, nx, nd2, nx2, m, n, dim[2], result_sym, w1, w2, w3;
 int	ny, i, black256;
 unsigned int	*ppix1, *ppix2, *ppix3, *ptr;
 unsigned short	*out, *map1, *map2;
 unsigned short	*p2;
 byte	*im1, *im2, *pq, *rlook, *imc;
 struct	ahead	*h;
 Drawable        *src;
 XImage *xi1, *xi2, *xi3;
 /* check depth, to avoid misuse, also need to have connected to X */
 //t1 = systime();
 if (ck_events() != 1) return -1;
 if (depth != 24 && depth != 32) {
 	printf("tvmix24ct only intended for 24 (or 32) bit visuals\n");
	return 0; }
 
 iq = ps[0];
  /* get window 1 */
  if (int_arg_stat(iq, &w1) != 1) return -1;
  if (ck_window(w1) != 1) return -1;
  if (w1 < 0) { printf("tvmix24win - pixmaps not supported\n");  return; }
  if ( win[w1] == 0 ) ana_xcreat(w1, 512, 512,0,0,0);
 iq = ps[1];
  /* get window 2 */
  if (int_arg_stat(iq, &w2) != 1) return -1;
  if (ck_window(w2) != 1) return -1;
  if (w2 < 0) { printf("tvmix24win - pixmaps not supported\n");  return; }
  if ( win[w2] == 0 ) ana_xcreat(w2, 512, 512,0,0,0);
 iq = ps[2];
  /* get destination window 3 */
  if (int_arg_stat(iq, &w3) != 1) return -1;
  if (ck_window(w3) != 1) return -1;
  if (w3 < 0) { printf("tvmix24win - pixmaps not supported\n");  return; }
 /* the destination window will be sized to the smaller of w1 and w2 */

 /* find the smaller size  of the 2 windows */
 nx = MIN(wd[w1], wd[w2]);  ny = MIN(ht[w1],ht[w2]);
 //printf("nx, ny = %d, %d\n", nx,ny);

 //ta1 = systime();
 //ta2 = systime();

 /* extract the image from first window */
 src = &(win[w1]);
 ptr = (unsigned int *) malloc(nx*ny*4);
 /* note that we create our own image and use XGetSubImage */
 xi1 = XCreateImage(display,vis,depth,ZPixmap,0,(char *) ptr,nx,ny,32,0);
 XGetSubImage(display, *src, 0, 0, nx, ny, 0xffffffff, ZPixmap, xi1, 0, 0);
 ppix1 = ptr;
 /* starting point is endian dependent of course */
 /* imc will be the combined image, load even bytes with first window result */
 src = &(win[w2]);
 ptr = (unsigned int *) malloc(nx*ny*4);
 /* note that we create our own image and use XGetSubImage */
 xi2 = XCreateImage(display,vis,depth,ZPixmap,0,(char *) ptr,nx,ny,32,0);
 XGetSubImage(display, *src, 0, 0, nx, ny, 0xffffffff, ZPixmap, xi2, 0, 0);
 ppix2 = ptr;
 
 fac = 1.0;	base = 0.0;	black_level = alpha_mode = 0.0;
 if (narg > 3) { if (float_arg_stat(ps[3], &fac) != 1) return -1; }
 if (narg > 4) { if (float_arg_stat(ps[4], &base) != 1) return -1; }
 if (narg > 5) { if (float_arg_stat(ps[5], &black_level) != 1) return -1; }
 if (narg > 6) { if (float_arg_stat(ps[6], &alpha_mode) != 1) return -1; }
 /* these masks seem to be the same for both G5 and Intel Macs but the corresponding
 bytes are backwards because of the different endians */
 //printf("rmask, gmask, bmask = %#x, %#x, %#x\n", rmask, gmask, bmask);
 //printf("rshift32, gshift32, bshift32 = %#x, %#x, %#x\n", rshift32, gshift32, bshift32);
 //printf("fac, base, black_level = %g, %g, %g\n", fac, base, black_level);
 /* setup for output image */
 ppix3 = (unsigned int *) malloc(nx*ny*4);
 if (ppix3 == NULL) { printf("could not malloc output image\n"); return 0; }
 
 pq = (unsigned char *) ppix3;
 m = nx*ny;
 while (m--) {
    float	alpha, calpha;
    unsigned int pq, xq;
    float r3, g3, b3, r2, g2, b2, r1, g1, b1;
    /* alpha uses the luminance of win 2 */
    pq = *ppix2++;
    r2 = (float) ((pq & rmask) >> rshift32);
    g2 = (float) ((pq & gmask) >> gshift32);
    b2 = (float) ((pq & bmask) >> bshift32);
    xq =  r2 + g2 + b2;
    alpha = fac *((float) xq * 0.00130719 - black_level) + base;
    alpha = MAX(alpha, 0.0);   alpha = MIN(alpha, 1.0);
    calpha = 1.0 - alpha;
    pq = *ppix1++;
    r1 = (float) ((pq & rmask) >> rshift32);
    g1 = (float) ((pq & gmask) >> gshift32);
    b1 = (float) ((pq & bmask) >> bshift32);
    r3 =  alpha * r2 + calpha * r1;
    g3 =  alpha * g2 + calpha * g1;
    b3 =  alpha * b2 + calpha * b1;
    *ppix3++ = (((unsigned int) r3 << rshift32) & rmask) | (((unsigned int) g3 << gshift32) & gmask) | (((unsigned int) b3 << bshift32) & bmask);
 }
 src = &(win[w3]);
 xi3 = XCreateImage(display,vis,depth,ZPixmap,0, (char *) pq ,nx,ny,32,0);
 //printf("w1, w2, w3 = %d %d %d\n", w1,w2,w3);
 XPutImage(display, win[w3], gc[w3], xi3, 0, 0, 0, 0, nx, ny);
 /* destroyImage will zap xi3 */
 XDestroyImage(xi3);
 XDestroyImage(xi1);
 XDestroyImage(xi2);
 blend_w1 = w1;
 blend_w2 = w2;
 blend_w3 = w3;
 XFlush(display);
 return 1;
 }
 /*------------------------------------------------------------------------*/
int tv16reblend(ptr, ixs, iys, ixw, iyw, nx, ny, wid)
 byte	*ptr;
 int	nx, ny, wid, ixs, iys, ixw, iyw;
 {
 int	level, nxb, nyb, m, mx, my, excess, istride, bstride;
 unsigned short	*p2;
 byte	*pq, *p1;
 //double	t1, t2, t3, t4;
 /* the idea here is to use the existing blend mapping with the new window
 input and update the blend window, lots could go wrong */
 /* check if this is really a valid blend window, if not we zero the feedback
 flag as a good deed */
 /* note that ixs, iys are offset in the source image and ixw,iyw are position
 in the destination for the corresponding XPutImage. The ixw, iyw should
 always be > 0 here and the size of the destination should be nx+ixw by
 ny+iyw (if the cutout was done efficiently). */
 //printf(" ixs, iys, ixw, iyw, nx, ny = %d %d %d %d %d %d\n",
 //	ixs, iys, ixw, iyw, nx, ny);
 //t1 = systime();
 level = 0;
 if (wid == blend_w1) level = 1;
 if (wid == blend_w2) level = 2;
 if (!level || blend_w3 < 0) { blend_feedback = 0;  return 1; }
 /* check the size situation */
 nxb = MIN(wd[blend_w1], wd[blend_w2]);
 nyb = MIN(ht[blend_w1], ht[blend_w2]);
 /* still consistent with the blend ? */
 if (nxb != blend_nx || nyb != blend_ny) {
  /* some significant re-size, re-do the blend completely */
  /* or just cop out for early testing */
  return 1;
 }
 /* size still stable, but we may not be filling the source window in
 some situations (like connected sets with offsets or different sizes)
 so our subimage may be smaller than the blend window size. Load accordingly
 assuming that ixs, iys are always 0 */
 /* ixs, iys actually should never be non-zero, check for debug */
 if (ixs || iys) {
 	printf("internal error in tv16reblend, ixs, iys = %d %d\n", ixs, iys);
 	}
 /* poke into existing blend_imc array */
 pq = (byte *) blend_imc;
#if LITTLEENDIAN
 if (level == 2) pq++;
#else
 if (level == 1) pq++;
#endif
 p1 = ptr;
 /* this is different from loop in tvmix16win, we do a direct transfer
 here rather than the reverse lookup table and the sizes may differ */
 /* also allow for ixw and iyw != 0 */
 pq += 2*(blend_nx * iyw  + ixw);
 my = MIN(blend_ny, ny);
 my = MIN(my, blend_ny-iyw);
 mx = MIN(blend_nx, nx);
 mx = MIN(blend_nx-ixw, nx);
 /* check for wild out of range situations, think we cover them by ensuring
 that mx and my are > 0, weird values can be passed when new windows are
 created and connected that have different solar positions */
 if (mx < 0 || my < 0) {
   printf("WARNING - image position out of range in blend\n");
   return 1;  /* just a warning, not a gross error */
   }
 istride = nx - mx;
 bstride = 2*(blend_nx - mx);
 while (my--) {
  m = mx;
  while (m--) { *pq++ = *p1++; pq++; }
  p1 += istride;
  pq += bstride;
 }
 //t2 = systime();

 if (level == 2) window_mod_flag[wid] |= BLEND_BITB; else
 	window_mod_flag[wid] |= BLEND_BITA;
 
  /* and display it, note that the original XPutImage for the blend
  array was done with all 0 offsets (i.e., the destination was matched
  to the subimage). */
 p2 = NULL;
 blend_out(blend_w3, blend_nx, blend_ny, p2);
 //t3 = systime();
 //printf("reblend\ntime for part 1: %g\ntime for part 2: %g\n",
 //	t2-t1, t3-t2);
 return 1;
 }
 /*------------------------------------------------------------------------*/
int tv24reblend(pdum, ixs, iys, ixw, iyw, nxin, nyin, wid)
 int	nxin, nyin, wid, ixs, iys, ixw, iyw;
 {
 int	w1, w2, w3, nx, ny, m;
 unsigned int	*ppix1, *ppix2, *ppix3, *ptr;
 byte	*pq;
 Drawable        *src;
 XImage *xi1, *xi2, *xi3;
 /* for the computed 24 bit blend, this just does the whole calculation over, it
 depends on the new window being already drawn since it reads it back, this is
 not efficient and is only for testing */
 /* find the smaller size  of the 2 windows */
 w1 = blend_w1;
 w2 = blend_w2;
 w3 = blend_w3;
 nx = MIN(wd[w1], wd[w2]);  ny = MIN(ht[w1],ht[w2]);
 //printf("nx, ny = %d, %d\n", nx,ny);

 /* extract the image from first window */
 src = &(win[w1]);
 ptr = (unsigned int *) malloc(nx*ny*4);
 /* note that we create our own image and use XGetSubImage */
 xi1 = XCreateImage(display,vis,depth,ZPixmap,0,(char *) ptr,nx,ny,32,0);
 XGetSubImage(display, *src, 0, 0, nx, ny, 0xffffffff, ZPixmap, xi1, 0, 0);
 ppix1 = ptr;
 /* starting point is endian dependent of course */
 /* imc will be the combined image, load even bytes with first window result */
 src = &(win[w2]);
 ptr = (unsigned int *) malloc(nx*ny*4);
 /* note that we create our own image and use XGetSubImage */
 xi2 = XCreateImage(display,vis,depth,ZPixmap,0,(char *) ptr,nx,ny,32,0);
 XGetSubImage(display, *src, 0, 0, nx, ny, 0xffffffff, ZPixmap, xi2, 0, 0);
 ppix2 = ptr;

 /* the parameters were saved as globals in fac, base, black_level, and alpha mode */
 /* these masks seem to be the same for both G5 and Intel Macs but the corresponding
 bytes are backwards because of the different endians */
 //printf("rmask, gmask, bmask = %#x, %#x, %#x\n", rmask, gmask, bmask);
 //printf("rshift32, gshift32, bshift32 = %#x, %#x, %#x\n", rshift32, gshift32, bshift32);
 //printf("fac, base, black_level = %g, %g, %g\n", fac, base, black_level);
 /* setup for output image */
 ppix3 = (unsigned int *) malloc(nx*ny*4);
 if (ppix3 == NULL) { printf("could not malloc output image\n"); return 0; }
 pq = (unsigned char *) ppix3;
 m = nx*ny;
 while (m--) {
    float	alpha, calpha;
    unsigned int pq, xq;
    float r3, g3, b3, r2, g2, b2, r1, g1, b1;
    /* alpha uses the luminance of win 2 */
    pq = *ppix2++;
    r2 = (float) ((pq & rmask) >> rshift32);
    g2 = (float) ((pq & gmask) >> gshift32);
    b2 = (float) ((pq & bmask) >> bshift32);
    xq =  r2 + g2 + b2;
    alpha = fac *((float) xq * 0.00130719 - black_level) + base;
    alpha = MAX(alpha, 0.0);   alpha = MIN(alpha, 1.0);
    calpha = 1.0 - alpha;
    pq = *ppix1++;
    r1 = (float) ((pq & rmask) >> rshift32);
    g1 = (float) ((pq & gmask) >> gshift32);
    b1 = (float) ((pq & bmask) >> bshift32);
    r3 =  alpha * r2 + calpha * r1;
    g3 =  alpha * g2 + calpha * g1;
    b3 =  alpha * b2 + calpha * b1;
    *ppix3++ = (((unsigned int) r3 << rshift32) & rmask) | (((unsigned int) g3 << gshift32) & gmask) | (((unsigned int) b3 << bshift32) & bmask);
 }
 src = &(win[w3]);
 xi3 = XCreateImage(display,vis,depth,ZPixmap,0, (char *) pq ,nx,ny,32,0);
 //printf("w1, w2, w3 = %d %d %d\n", w1,w2,w3);
 XPutImage(display, win[w3], gc[w3], xi3, 0, 0, 0, 0, nx, ny);
 /* destroyImage will zap ppix3 */
 XDestroyImage(xi3);
 XDestroyImage(xi1);
 XDestroyImage(xi2);
 
 XFlush(display);
 return 1;
 }
 /*------------------------------------------------------------------------*/
int ana_tvmix16(narg,ps)
 int narg, ps[];
 /* a function, mixes 2 images using their color maps and a mixing factor
 array. May be temporary whilst I test ideas. For 16 bit visuals only.
 call is:  x16 = tvmix16(x1,x2,map1,map2,fac) */
 {
 byte	*p1, *p2;
 int	iq, nd, nx, ny, nd2, nx2, ny2, *map1, *map2, m;
 int	result_sym, mfac, mix_flag;
 short	*fac, *out;
 struct	ahead	*h;
 if (ck_events() != 1) return -1;
 /* first the 2 image arrays */
 iq = ps[0];
 if ( sym[iq].class != 4 ) return execute_error(101);
 if ( sym[iq].type != 0 ) return execute_error(118);
 h = (struct ahead *) sym[iq].spec.array.ptr;
 nd = h->ndim;
 nx = h->dims[0];        ny = h->dims[1];
 p1 = (byte *) ((char *)h + sizeof(struct ahead));
 iq = ps[1];
 if ( sym[iq].class != 4 ) return execute_error(101);
 if ( sym[iq].type != 0 ) return execute_error(118);
 h = (struct ahead *) sym[iq].spec.array.ptr;
 nd2= h->ndim;
 nx2 = h->dims[0];        ny2 = h->dims[1];
 p2 = (byte *) ((char *)h + sizeof(struct ahead));
 if ( nd != 2 || nd2 != 2) {
   printf("tvmix16 - image arrays must be 2-D\n");  return -1; }
 if (nx != nx2 || ny != ny2) {
   printf("tvmix16 - image arrays must match in size\n");  return -1; }
 result_sym = array_clone(iq, 1);
 h = (struct ahead *) sym[result_sym].spec.array.ptr;
 out = (short *) ((char *)h + sizeof(struct ahead));
 m = nx * ny;
 /* and the mixing parameter, could be an array or a scalar */
 iq = ps[4];
 if ( sym[iq].class == 4 ) {
  if ( sym[iq].type != 1 ) return execute_error(111);
  h = (struct ahead *) sym[iq].spec.array.ptr;
  nd = h->ndim;
  nx = h->dims[0];        ny = h->dims[1];
  fac = (short *) ((char *)h + sizeof(struct ahead));
  mix_flag = 1;
  if (nx != nx2 || ny != ny2 || nd != nd2) {
    printf("tvmix16 - mixing factor array must match images\n");  return -1; }
 } else {
  /* other choice is a scalar */
  if ( sym[iq].class != 1 ) {
   printf("mixing factor must be a scalar or an array\n");
   return -1;
   }
  mix_flag = 0;
  if (int_arg_stat(iq, &mfac) != 1) return -1;
  if (mfac > 256 || mfac < 0) {
    printf("mixing factor (%d) is out of range\n", mfac);
    return -1; }
 }
 /* now the 2 color maps, these are normally 256 long */
 iq = ps[2];
 if ( sym[iq].class != 4 ) return execute_error(101);
 if ( sym[iq].type != 2 ) return execute_error(133);
 h = (struct ahead *) sym[iq].spec.array.ptr;
 nd = h->ndim;
 nx = h->dims[0];
 map1 = (int *) ((char *)h + sizeof(struct ahead));
 nd = h->ndim;
 nx = h->dims[0];
 iq = ps[3];
 if ( sym[iq].class != 4 ) return execute_error(101);
 if ( sym[iq].type != 2 ) return execute_error(133);
 h = (struct ahead *) sym[iq].spec.array.ptr;
 nd2 = h->ndim;
 nx2 = h->dims[0];
 map2 = (int *) ((char *)h + sizeof(struct ahead));
 if ( nd != 1 || nd2 != 1) {
   printf("tvmix16 - color map arrays must be 1-D\n");  return -1; }
 if (nx != 256 || nx2 != 256) {
   printf("tvmix16 - color map arrays must be 256 long\n");  return -1; }
 /* all checking done */
 {
  int rmask, gmask, bmask, xq, yq, in1, in2, a, ac, zq, pix1, pix2;
  rmask = visual_info.red_mask;
  gmask = visual_info.green_mask;
  bmask = visual_info.blue_mask;
  if (mix_flag) {
  while (m--) {
   a = *fac++;
   ac = 256 - a;
   in1 = *p1++;
   in2 = *p2++;
   pix1 = map1[in1];
   pix2 = map2[in2];
   xq = (pix1 & bmask) * a;
   yq = (pix2 & bmask) * ac;
   zq = ((xq + yq) >> 8) & bmask;
   xq = (pix1 & gmask) * a;
   yq = (pix2 & gmask) * ac;
   zq = zq | (((xq + yq) >> 8) & gmask);
   xq = (pix1 & rmask) * a;
   yq = (pix2 & rmask) * ac;
   zq = zq | (((xq + yq) >> 8) & rmask);
   *out++ = (short) zq;
  }
 } else {
  a = mfac;
  ac = 256 - a;
  while (m--) {
   in1 = *p1++;
   in2 = *p2++;
   pix1 = map1[in1];
   pix2 = map2[in2];
   xq = (pix1 & bmask) * a;
   yq = (pix2 & bmask) * ac;
   zq = ((xq + yq) >> 8) & bmask;
   xq = (pix1 & gmask) * a;
   yq = (pix2 & gmask) * ac;
   zq = zq | (((xq + yq) >> 8) & gmask);
   xq = (pix1 & rmask) * a;
   yq = (pix2 & rmask) * ac;
   zq = zq | (((xq + yq) >> 8) & rmask);
   *out++ = (short) zq;
  }
 }
 }
 return result_sym;
 }
 /*------------------------------------------------------------------------*/
int ana_tvconvert16torgb(narg,ps)
 int narg, ps[];
 /* a subroutine, converts a 16 bit truecolor image to three color (rgb)
 components by just scaling the color components.
 call is: tvconvert16torgb, x, r, g, b where r,g,b are output */
 {
 int	result_sym, dim[2],nd;
 int	xq, yq, pix;
 unsigned short	*ptr;
 int	nc, iq, nx, ny, n, i, j, m;
 float	fac, sfac;
 byte	*pred, *pblue, *pgreen;
 struct	ahead	*h;
 if (ck_events() != 1) return -1;
 /* check depth, to avoid misuse */
 if (depth != 16 && depth != 15) {
 	printf("tvconvert16 only intended for 16 (or 15) bit visuals\n");
	return 0; }
 if (ck_events() != 1) return -1;
 iq = ps[0];
 if ( sym[iq].class != 4 ) return execute_error(66);
 if ( sym[iq].type != 1 ) return execute_error(111);
 h = (struct ahead *) sym[iq].spec.array.ptr;
 ptr = (unsigned short *) ( (char *) h + sizeof( struct ahead ) );
 nd = h->ndim;
 if ( nd != 2) { printf("tvconvert16torgb - array must be 2-D\n");  return -1; }
 nx = h->dims[0];       ny = h->dims[1];
 dim[0] = nx;		dim[1] = ny;

 /* set up the 3 output arrays as byte arrays of the same size */
 iq = ps[1];
 if (redef_array(iq, 0, 2, dim) != 1) return -1; 
 h = (struct ahead *) sym[iq].spec.array.ptr;
 pred = (byte *) ((char *)h + sizeof(struct ahead));
 iq = ps[3];
 if (redef_array(iq, 0, 2, dim) != 1) return -1; 
 h = (struct ahead *) sym[iq].spec.array.ptr;
 pblue = (byte *) ((char *)h + sizeof(struct ahead));
 iq = ps[2];
 if (redef_array(iq, 0, 2, dim) != 1) return -1; 
 h = (struct ahead *) sym[iq].spec.array.ptr;
 pgreen = (byte *) ((char *)h + sizeof(struct ahead));

 /* get the ranges in the 16 bit truecolor representation */
//  rmask = visual_info.red_mask;
//  gmask = visual_info.green_mask;
//  bmask = visual_info.blue_mask;
//  get_shifts16();
 n = m = nx * ny;
 while (m--) {
  pix = (int) *ptr++;
  xq = (pix & rmask);
  if (rshift > 0) xq = xq >> rshift;  else  xq = xq << (-rshift);
  *pred++ = (byte) xq;
  xq = (pix & bmask);
  if (bshift > 0) xq = xq >> bshift;  else  xq = xq << (-bshift);
  *pblue++ = (byte) xq;
  xq = (pix & gmask);
  if (gshift > 0) xq = xq >> gshift;  else  xq = xq << (-gshift);
  *pgreen++ = (byte) xq;
 }
 return 1;
 }
 /*------------------------------------------------------------------------*/
int ana_xtvplane(narg,ps)
 int narg, ps[];
 /* tvplane, cube, in, ix,iy, window */
 /* blend feedback option added, still experimental and only for 16 bit
 visuals */
 /* 3/6/2000 - support symbol arrays as alternative to cubes */
 /* 3/25/99 - mods to include offsets in the window, these are done
 using negative ix and iy (maybe we should have made the offsets in the
 data neg so that tv and tvplane were consistent, think about that)
 the offset is in image pixels so if zoom is not 1, it can be more (or
 less) screen pixels
 also letting XPutImage do more of the extraction work for the common
 zoom = 1 case */
 /* use negative zoom factors for compression, not real fast */
 /* 9/21/96 allow 2-D arrays also but verify that plane is 0 */
 /* similar to tv but extracts a 2-D image (plane) from a data cube,
 avoids an extra memory transfer, works like tv, cube(*,*,in),ix,iy,window
 5/27/96 The original tvplane used ix,iy in the same way as tv but now we
 change it to mean an offset in the cube rather than one in the output
 window. Hence the output window offset is always (0,0) unless we decide
 to add more parameters. This is better adapted for scrollable windows
 where we want to fill the window but vary the part of the image displayed
 Also, drop support for pixmaps, this routine only makes sense for displayable
 windows. Also, don't set the !tvix,!tvixb stuff for this routine. Note
 that this always displays the image in scan orientation, like iorder = 2.
 */
 {
 extern int zoom_test;
 int  i, iq, nx, ny, nz, nd, ix=0, iy=0, wid, mapid, nxx, nyy, hq, wq, ip;
 int  ixw = 0, iyw = 0, ixs, iys, class, width, height;
 int	zoom_sym, ns, ms;
 char	*ptr;
 char *subfree = NULL;
 struct  ahead   *h;
 if (ck_events() != 1) return -1;
 iq = ps[0];
 wid = last_wid;	/* default if none specified */
 class = sym[iq].class;
 if ( class != ARRAY && class != SYM_ARR) return execute_error(66);
 h = (struct ahead *) sym[iq].spec.array.ptr;
 nd = h->ndim;
 ix = iy = ip = 0;
 if (narg > 1) { if (int_arg_stat(ps[1], &ip) != 1) return -1; }
 /* handle either cube or symbol array case */
 switch (class) {
  
  case ARRAY:
  if ( (nd != 3 && nd != 2) || sym[iq].type != 0) {
 	 printf("tvplane - array must be 2-D or 3-D I*1\n");  return -1; }
  nx = h->dims[0];        ny = h->dims[1];
  if (nd == 3) nz = h->dims[2]; else nz = 1;
  if (ip >= nz || ip < 0)
  { printf("tvplane - out of range plane (%d)\n", ip);  return -1; }
  /* get pointer to the unzoomed image */
  h = (struct ahead *) sym[iq].spec.array.ptr;
  ptr = (char *) ( (char *) h + sizeof( struct ahead ) ) + ip*nx*ny;
  break;
  
  case SYM_ARR:
  /* get ptr to the indicated symbol in the array, this is read only */
  {
  struct sym_desc *psym;
  int	j;
  nz = 1; for (j=0;j<nd;j++) nz *= h->dims[j];	/*# of elements */
  if (ip >= nz || ip < 0)
  { printf("tvplane - out of range symbol (%d)\n", ip);  return -1; }
  psym = (struct sym_desc *) ((char *)h + sizeof(struct ahead));
  psym = psym + ip;
  /* this is now a pointer to the specified symbol, check if 2-D, etc */
  if ( psym->class != ARRAY) return execute_error(66);
  h = (struct ahead *) psym->spec.array.ptr;
  nd = h->ndim;
  if ( (nd != 2) || psym->type != 0) {
 	 printf("tvplane - symbol must be 2-D I*1\n");  return -1; }
  nx = h->dims[0];        ny = h->dims[1];
  ptr = (char *) ( (char *) h + sizeof( struct ahead ) );
  }
  break;
 }


 if (narg > 2) { if (int_arg_stat(ps[2], &ix) != 1) return -1; }
 if (narg > 3) { if (int_arg_stat(ps[3], &iy) != 1) return -1; }
 if (narg > 4) { if (int_arg_stat(ps[4], &wid) != 1) return -1; }

 if (wid < 0 ) {
  printf("TVPLANE - pixmaps (negative window #'s) not supported, %d", wid);
  return -1; }
 /* does window exist? We must have a predefined window */
 if ( win[wid] == 0 ) {
  printf("TVPLANE - window must be pre-defined, %d\n", wid);
  return -1; }

 /* good time to mark as modified */
 window_mod_flag[wid] = 0;
 /* check if ix and iy in range, just return if not (image is off screen */
 if (ix >= nx || iy >= ny) return 1;

 /* how much do we need ? depends on destination window and zoom */
 wq = width = wd[wid];		hq = height =ht[wid];
 /* if ix (iy) negative, the amount of image needed is reduced, neg values
 are interpreted as offsets in the window now */
 if (ix >= 0) ixw = 0; else { ixw = -ix;  ix = 0; }
 if (iy >= 0) iyw = 0; else { iyw = -iy;  iy = 0; }
 //printf("initial hq, wq = %d, %d\n", hq,wq);
 /* ixs and iys are screen offset in the source array, they are just ix, iy
 for the zoom = 1 case, otherwise we zero them. We also adjust ixw, iyw
 to screen pixels. We don't need to save the originals however. */
 ixs = ix;	iys = iy;
 if (tvplanezoom > 1 )
   { wq = wq/tvplanezoom - ixw;  hq  = hq/tvplanezoom- iyw;
     ixw = ixw*tvplanezoom;
     iyw = iyw*tvplanezoom; }
 if (tvplanezoom < 0 )
   { wq = wq*ABS(tvplanezoom) - ixw;  hq  = hq*ABS(tvplanezoom)- iyw;
     ixw = ixw/ABS(tvplanezoom);
     iyw = iyw/ABS(tvplanezoom); }
 //printf("zoom hq, wq = %d, %d\n", hq,wq);
 //printf("ixw, iyw = %d, %d\n", ixw, iyw);
 //printf("adj. hq, wq = %d, %d\n", hq,wq);
 /* if either are zero, we are off the screen and return now */
 if (hq <= 0 || wq <= 0)  return 1;
 /* can't be too big, note change made 4/7/99 adding the "-ix"  and "-iy" */
 wq = MIN(wq, nx-ix);	hq = MIN(hq, ny-iy);
 /* wq and hq are the range in data space now */
 /* check this range, adjust ix if necessary */
 /* 3/25/99 - don't think the conditions below are possible */
 //if ( (ix+wq) >= nx) ix = nx - wq;
 //if ( (iy+hq) >= ny) iy = ny - hq;
 /* now extract this subarea if it is a subarea*/
 /* 3/25/99 - we only have to extract if it is a zoom */
 /* but may also a good idea if it is a 16 or 24 bit visual */
 if (tvplanezoom != 1 || depth != 8)
 {
 /* 2 obvious upgrades, if zooming, the extraction and zoom can be combined and
 the data could be re-oriented while extracting */
 /* not all zooms (esp de-zooms) require an extract */
 if (ix != 0 || iy != 0 || nx != wq || ny != hq)
 {
   char	*sub, *p;
   int	m = hq, n, stride;
   //printf("hq, wq = %d, %d\n", hq,wq);
   p = ptr;
   sub = ptr = (char *) malloc(wq*hq);
   p = p + ix+iy*nx;
   stride = nx - wq;
   while (m--) { n = wq;  while (n--) *sub++ = *p++;  p += stride; }
   nx = wq;	ny = hq;
   ixs = iys = 0;
   subfree=ptr;
 } }
 /* are we zooming? */
 if (tvplanezoom != 1 ) {
   /* now call zoomerx to get the expanded version */
   switch (tvplanezoom) {
   case 2: zoomer2(ptr, nx, ny, &zoom_sym, &ns, &ms, 0); break;
   case 3: zoomer3(ptr, nx, ny, &zoom_sym, &ns, &ms, 0); break;
   case 4: zoomer4(ptr, nx, ny, &zoom_sym, &ns, &ms, 0); break;
   case 8: zoomer8(ptr, nx, ny, &zoom_sym, &ns, &ms, 0); break;
   case 16: zoomer16(ptr, nx, ny, &zoom_sym, &ns, &ms, 0); break;
   case -2: compress2(ptr, nx, ny, &zoom_sym, &ns, &ms, 0); break;
   case -4: compress4(ptr, nx, ny, &zoom_sym, &ns, &ms, 0); break;
   default:
     printf("TVPLANE: illegal zoom factor of %d, only -4,-2,1,2,3,4,8,16 allowed\n", tvplanezoom);
     return -1;
   }
   /* get pointer to this now, assume that ns and ms are the proper dimension */
   h = (struct ahead *) sym[zoom_sym].spec.array.ptr;
   ptr = (char *) ( (char *) h + sizeof( struct ahead ) );
   nx = ns;	ny = ms;
 } else {
   /* still use zoom_sym to allow use of the extracted byte array, just have
   it point to our array */
   
 }
 //printf("\nnx, ny = %d, %d\n", nx,ny);
 //printf("ixs, iys = %d, %d\n", ixs, iys);
 //printf("ixw, iyw = %d, %d\n", ixw, iyw);

		 /* create image structure */
 if (depth == 8) {
  xi = XCreateImage(display,vis,8,ZPixmap,0, ptr ,nx,ny, 8,0);
  /* nx and ny for the XPutImage should be cropped or performance
  suffers */
  nx = MIN(width - ixw, nx - ixs);
  ny = MIN(height -iyw, ny - iys);
  if (clear_outside_flag) {
   int	x, y, w, h;
   if (ixw > 0) {
     x = y = h = 0;
     w = ixw;
     XClearArea(display, win[wid], x,y,w,h, False);
    }
  if (iyw > 0) {
     x = y = w = 0;
     h = iyw;
     XClearArea(display, win[wid], x,y,w,h, False);
    }
  if ((nx+ixw) < width) {
     h = w = y = 0;
     x = nx+ixw;
     XClearArea(display, win[wid], x,y,w,h, False);
    }
  if ((ny+iyw) < height) {
     h = w = x = 0;
     y = ny+iyw;
     XClearArea(display, win[wid], x,y,w,h, False);
    }
  }
  XPutImage(display, win[wid], gc[wid], xi, ixs, iys, ixw, iyw, nx, ny);
  /* now dealloc the image structure but not the data */
  xi->data = NULL;
  XDestroyImage(xi);
 } else if (depth == 16 || depth == 15) {
  short	*p16, *psave;
  byte	*p = (byte *) ptr;
  int	m;
  /* need a 16 bit image array for the display */
  p16 = psave = (short *) malloc(nx*ny*2);
  if (!p16) { printf("malloc error in 16 bit temp buffer\n"); return -1;}
  /* use current lookup table to translate */
  lookup16truecolor = (short *) window_lookups[wid];
  m = ny*nx;  while (m--) *p16++ = lookup16truecolor[*p++];
  xi = XCreateImage(display,vis,depth,ZPixmap,0, (char *) psave ,nx,ny,
 	 16,0);
  /* don't think ixs, iys can be non-zero because we always do a cutout */
  if (clear_outside_flag) {
   int	x, y, w, h;
   if (ixw > 0) {
     x = y = h = 0;
     w = ixw;
     XClearArea(display, win[wid], x,y,w,h, False);
    }
  if (iyw > 0) {
     x = y = w = 0;
     h = iyw;
     XClearArea(display, win[wid], x,y,w,h, False);
    }
  if ((nx+ixw) < width) {
     h = w = y = 0;
     x = nx+ixw;
     XClearArea(display, win[wid], x,y,w,h, False);
    }
  if ((ny+iyw) < height) {
     h = w = x = 0;
     y = ny+iyw;
     XClearArea(display, win[wid], x,y,w,h, False);
    }
  }
  XPutImage(display, win[wid], gc[wid], xi, ixs, iys, ixw, iyw, nx, ny);
  /* destroyImage (must do before blend check) will zap p16 */
  XDestroyImage(xi);
  /* check for blend feedback */
  if (blend_feedback)
    if (wid == blend_w1 || wid == blend_w2)
    	tv16reblend(ptr, ixs, iys, ixw, iyw, nx, ny, wid);
 } else if (depth == 24 || depth == 32) {
   unsigned int	*p24, *psave;
   byte	*p = (byte *) ptr;
   int	m;
   /* use NULL for data pointer until we find out what kind, might be better
   to do this just once for the visual but it doesn't take long */
   xi = XCreateImage(display,vis,depth,ZPixmap,0, NULL ,nx,ny,8,0);
   /* use 8 for bitpad in case we have 24 bit pixels, otherwise need to pad
   lines, some concern that this may not be honored in all cases */
   /* use current lookup table to translate */
   //printf("in tvplane, wid = %d\n", wid);
   lookup24truecolor = (unsigned int *) window_lookups[wid];
   //printf("lookup24truecolor = %d\n", lookup24truecolor);
   /* we can now check if this has 24 or 32 bit pixels, many 24 depths actually
   use 32 bit pixels but not all */
   if (xi->bits_per_pixel == 24) {
     /* note that the visual info block doesn't tell us the bits_per_pixel */
     /* need a 24 bit image array for the display */
     int	n, nd4, nr;
     int	x1, x2, x3, x4;
     unsigned int 	*pin, *pout, *p24;
     /* use current lookup table to translate */
     lookup24truecolor = (unsigned int *) window_lookups[wid];
     printf("lookup24truecolor = %d\n", lookup24truecolor);
     p = (byte *) ptr;
     n = xi->width * xi->height;
     pout = psave = (unsigned int *) malloc( ((n*3+3)/4) * sizeof(unsigned int));
     if (pout == NULL) { printf("malloc failure during 24 bit processing\n");
 	    return 0; }
     nd4 = n/4;
     nr = n - nd4*4;
#if LITTLEENDIAN
     while (nd4--) {
       x1 = lookup24truecolor[*p++];
       x2 = lookup24truecolor[*p++];
       *pout++ = x1 + ((x2 & 0xff) << 24);
       x3 = lookup24truecolor[*p++];
       *pout++ = (x2 >> 8) + ( x3 << 16);
       x4 = lookup24truecolor[*p++];
       *pout++ = (x3 >> 16) + (x4 << 8);
     }
     if (nr > 0) {
       x1 = lookup24truecolor[*p++];
       if (nr > 1) x2 = lookup24truecolor[*p++]; else x2 = 0;
       *pout++ = x1 + ((x2 & 0xff) << 24);
       if (nr > 2) x3 = lookup24truecolor[*p++]; else x3 = 0;
       if (nr > 1) *pout++ = (x2 >> 8) + ( x3 << 16);
       if (nr > 2) *pout++ = (x3 >> 16);
       }
#else
     while (nd4--) {
       x1 = lookup24truecolor[*p++];
       x2 = lookup24truecolor[*p++];
       *pout++ = x1 << 8 + x2 >> 16;
       x3 = lookup24truecolor[*p++];
       *pout++ = x2 << 16 + x3 >> 16;
       x4 = lookup24truecolor[*p++];
       *pout++ = x3 << 24 + x4;
     }
     if (nr > 0) {
       x1 = lookup24truecolor[*p++];
       if (nr > 1) x2 = lookup24truecolor[*p++]; else x2 = 0;
       *pout++ = x1 << 8 + x2 >> 16;
       if (nr > 2) x3 = lookup24truecolor[*p++]; else x3 = 0;
       if (nr > 1) *pout++ = x2 << 16 + x3 >> 16;
       if (nr > 2) *pout++ = x3 << 24;
       } 
#endif
   } else {
     /* assume 32 bit pixels */
     p24 = psave = (unsigned int *) malloc(nx*ny*sizeof(unsigned int));
     p = (byte *) ptr;
     /* use current lookup table to translate */
     m = ny*nx;  while (m--) *p24++ = lookup24truecolor[*p++];
   }
    if (clear_outside_flag) {
     int	x, y, w, h;
     if (ixw > 0) {
       x = y = h = 0;
       w = ixw;
       XClearArea(display, win[wid], x,y,w,h, False);
      }
    if (iyw > 0) {
       x = y = w = 0;
       h = iyw;
       XClearArea(display, win[wid], x,y,w,h, False);
      }
    if ((nx+ixw) < width) {
       h = w = y = 0;
       x = nx+ixw;
       XClearArea(display, win[wid], x,y,w,h, False);
      }
    if ((ny+iyw) < height) {
       h = w = x = 0;
       y = ny+iyw;
       XClearArea(display, win[wid], x,y,w,h, False);
      }
    }
   xi->data = (char *) psave;
   XPutImage(display, win[wid], gc[wid], xi, ixs, iys, ixw, iyw, nx, ny);
   /* destroyImage will zap p24 */
   XDestroyImage(xi);
   /* check for blend feedback */
   if (blend_feedback)
     if (wid == blend_w1 || wid == blend_w2)
	 tv24reblend(ptr, ixs, iys, ixw, iyw, nx, ny, wid);
 } else {
   printf("problem with X display, unsupported depth = %d\n", depth);
   return 0;
 }
 if (subfree) free(subfree);
 //subfree = NULL;
 XFlush(display);
 return 1;
 }
 /*------------------------------------------------------------------------*/
int ana_xtvtrue(narg,ps)
 /* a true color version, requires 32 bit input with 24 bit color */
 /* this is not really supported right now (1/17/00) but seems to work (5/26/2009) */
 int narg, ps[];
 {
 int  i,iq, *ptr, nx, ny, nd,ix,iy,wid, mapid, nxx, nyy, hq;
 struct  ahead   *h;
 if (true_color24 == 0) {
   printf("XTVTRUE: sorry, !truecolor not set\n");
   return -1;
 }
  if (ck_events() != 1) return -1;
 iq = ps[0];
 wid = last_wid;
 if ( sym[iq].class != 4 ) return execute_error(66);
 h = (struct ahead *) sym[iq].spec.array.ptr;
 nd = h->ndim;
 if ( (nd != 2) || (sym[iq].type != 2) ) {
 printf("XTVTRUE: array must be 2-D longword\n");  return -1; }
 nx = h->dims[0];        ny = h->dims[1];
 ix = 0;         iy = 0;
 if (narg > 1) ix = int_arg( ps[1] );
 if (narg > 2) iy = int_arg( ps[2] );
 if (narg > 3) wid = int_arg( ps[3] );
 if (wid < 0 ) {
   printf("XTVTRUE: sorry, pixmaps not supported for true color\n");
   return -1;
 } else {                                        /* window case */
 /* does window exist? If not create to fit image */
 if ( win[wid] == 0 ) ana_xcreat(wid, iy+ny, ix+nx,0,0,0);
 hq = ht[wid];
 nxx = MIN( nx, wd[wid] - ix);  nyy = MIN( ny, hq - iy);
 if ( nxx < 0 || nyy < 0 ) {
	 printf("xtv - completely off screen\n"); return -1; }
 }
 h = (struct ahead *) sym[iq].spec.array.ptr;
 ptr = (int *) ( (char *) h + sizeof( struct ahead ) );
 
		 /* create image structure */
 xi = XCreateImage(display,vis,24,ZPixmap,0, (char *) ptr ,nx,ny,32,0);
 if (wid < 0 ) {
   mapid = - wid;
   XPutImage(display, maps[mapid], gcmap[mapid], xi, 0,0,ix,iy, nxx,nyy);
 } else {                                        /* window case */
   XPutImage(display, win[wid], gc[wid], xi, 0,0,ix,iy, nxx,nyy);
 }
 /* now dealloc the image structure but not the data */
 xi->data = NULL;
 XDestroyImage( xi);
 XFlush(display);
 /* set the globals to corners of image */
 tvix = ix;	tvixb = ix + nxx;
 tviy = MAX(0, hq - iy - nyy);	tviyb = MIN( hq - 1, tviy + nyy);
 return 1;
 }
 /*------------------------------------------------------------------------*/
int ana_xcopy(narg,ps)
 int narg, ps[];
 /* 1/8/92 modified to treat negative numbers as pixmaps and 0 and >0 as
   displayed windows */
 {
 int     id1, id2, ixs, iys, ixd, iyd, w, h, ws, wf, hs, hf;
 Drawable        *src, *dest;
 GC      *cgc;
 if (ck_events() != 1) return -1;
 id1 = int_arg( ps[0] );
 id2 = int_arg( ps[1] );
 ixs = iys = ixd = iyd = 0;
 if (ck_window(id1) != 1) return -1;
 if (ck_window(id2) != 1) return -1;
 if (id1 < 0 ) { src = &(maps[-id1]); cgc = &gcmap[-id1];
	 ws = wdmap[-id1];  hs = htmap[-id1]; }
	 else { src = &(win[id1]); cgc = &gc[id1];
	 ws = wd[id1];  hs = ht[id1]; }  
 if (id2 < 0 ) { dest = &(maps[-id2]);
	 wf = wdmap[-id2];  hf = htmap[-id2]; }
	 else { dest = &(win[id2]);
	 wf = wd[id2];  hf = ht[id2]; }
 w = ws; h = hs;
 if (narg > 2) { ixs = int_arg( ps[2] ); ixd = ixs; }
 if (narg > 3) { iys = int_arg( ps[3] ); iyd = iys; }
 if (narg > 4) w = int_arg( ps[4] );
 if (narg > 5) h = int_arg( ps[5] );
 if (narg > 6) ixd = int_arg( ps[6] );
 if (narg > 7) iyd = int_arg( ps[7] );
 if ( src == NULL ) { printf("source drawable not defined\n");
		 return -1; }
 if ( dest == NULL ) { printf("dest drawable not defined\n");
		 return -1; }
 /* make w and h fit both */
 w = MIN( w, wf-ixd);    h = MIN( h, hf-iyd);
 if ( w <= 0 || h <= 0 ) { printf("xcopy - destination area out of window\n");
	 return -1; }
 XCopyArea( display, *src, *dest, *cgc, ixs, iys, w, h, ixd, iyd);
 XFlush(display);
 return 1;
 }
  /*------------------------------------------------------------------------*/
int ana_xtvread(narg,ps)
 int narg, ps[];
 {
 /* read from an X window or pixmap and create a byte array */
 /* the call is  x = tvread(...) with arguments that change order with
 the number, this was apparently done originally to allow portions of
 a default window, now also used to implement root window -- may want
 a different scheme */
 int	i,iq, nx, ny, ix, iy, wid, result_sym, dim[2];
 int	root_flag = 0, status, x, y;
 unsigned int	w, hh, bw, depth_local;
 char    *ptr;
 struct  ahead   *h;
 Drawable        src;
 Window	rt;
 /* the input arguments are all scalars */
 if (ck_events() != 1) return -1;
 wid = last_wid;
 ix = iy = 0;
 if (narg == 4 || narg == 0 || narg == 2) root_flag = 1;
 if (narg == 1) wid = int_arg( ps[0]);
 if (narg > 4 ) wid = int_arg( ps[4]); 

 if (root_flag) { src = RootWindow(display,screen_num);
 //w = nx = DisplayWidth(display, screen_num);
 //hh = ny = DisplayHeight(display, screen_num);
 } else {
 if (ck_window(wid) != 1) return -1;
 if (wid < 0 ) {
 src = (Drawable) maps[-wid];
 } else {
 src = (Drawable) win[wid];
 } }
 if ( src == 0 ) { printf("non-existent window in tvread: %d\n",wid);
	 return -1; }
 /* use XGetGeometry to get size, this works for Pixmaps also */
 status = XGetGeometry(display, src, &rt, &x, &y, &w, &hh, &bw, &depth_local);
 if (status == False) { printf("XTVREAD: XGetWindowAttributes failure\n");
 	return -1; }
 nx = (int) w;
 ny = (int) hh;
 //printf("w, h, depth from XGetGeometry = %d, %d, %d\n", w, hh,depth_local);
 
 if (narg >= 2) { ix = int_arg( ps[0]);  iy = int_arg( ps[1]); }
 if (narg >= 4) { nx = int_arg( ps[2]);  ny = int_arg( ps[3]); }

 nx = MIN( nx, w - ix);  ny = MIN( ny, hh - iy);
 if ( nx < 0 || ny < 0 ) { printf("xtvread - off screen\n"); return -1; }
 dim[0] = nx;   dim[1] = ny;
 /* the type of array is visual dependent */
 if (depth == 8) {
  result_sym = array_scratch(0, 2, dim);
  result_sym = ana_zerof( 1, &result_sym);  /* zero it in case not filled */
  h = (struct ahead *) sym[result_sym].spec.array.ptr;
  ptr = (char *) ( (char *) h + sizeof( struct ahead ) );
  /* note that we create our own image and use XGetSubImage */
  xi = XCreateImage(display,vis,8,ZPixmap,0,ptr ,nx,ny,8,0);
  XGetSubImage(display, src, ix, iy, nx, ny, 255, ZPixmap, xi, 0, 0);
 } else if (depth == 16 || depth == 15) {
   result_sym = array_scratch(1, 2, dim);
   result_sym = ana_zerof( 1, &result_sym);  /* zero it in case not filled */
   h = (struct ahead *) sym[result_sym].spec.array.ptr;
   ptr = (char *) ( (char *) h + sizeof( struct ahead ) );
   xi = XCreateImage(display,vis,depth,ZPixmap,0,(char *) ptr,nx,ny,16,0);
   XGetSubImage(display, src, ix, iy, nx, ny, 0xffffffff, ZPixmap, xi, 0, 0);
 } else if (depth == 24) {
   //printf("depth = %d\n", depth);
   result_sym = array_scratch(2, 2, dim);
   result_sym = ana_zerof( 1, &result_sym);  /* zero it in case not filled */
   h = (struct ahead *) sym[result_sym].spec.array.ptr;
   ptr = (char *) ( (char *) h + sizeof( struct ahead ) );
   xi = XCreateImage(display,vis,depth,ZPixmap,0,(char *) ptr,nx,ny,32,0);
   //printf("XCreateImage done\n");
   XGetSubImage(display, src, ix, iy, nx, ny, 0xffffffff, ZPixmap, xi, 0, 0);
 } else {
   printf("TVREAD - sorry, visual depth %d not supported yet.\n", depth);
   return 4;
 }
 xi->data = NULL;
 XDestroyImage( xi);
 XFlush(display);
 return result_sym;
 }
  /*------------------------------------------------------------------------*/
int ana_rgb2pseudo(narg,ps)
 int narg, ps[];
 {
 /* converts an RGB image into a 8 bit psuedo color and a color map */
 /* call is rgb2pseudo, rgb, pseudo, map where rgb is an input (3,nx,ny) byte array,
 psuedo is an output (nx,ny) byte array, and map is an output (3,256) I*1 array (the color
 table) */
 int iq, type, returnFlag = 1, hist[256], cmap_sym, result_sym, dim[2];
 int ngifcolors, lastColor, thisColor, lastIndex, m, nx, ny, k, n, i, nd;
 struct	ahead	*h, *h2;
 byte	*colormap, *data, *rgbinput, *ptr_r, *ptr_g, *ptr_b, *gq;
 iq = ps[0];
 if ( sym[iq].class != 4 ) return execute_error(66);
 type = sym[iq].type;
 h = (struct ahead *) sym[iq].spec.array.ptr;
 rgbinput = (byte *) ((char *)h + sizeof(struct ahead));
 nd = h->ndim;
 if (type != 0 ) 
  { printf("RGB2PSEUDO only supports input byte arrays\n");
  return -1; }
 /* check input array before we go on */
 if ( nd != 3 )
  { printf("RGB2PSEUDO - illegal image, must be a RGB 3-D array\n");
  return -1; }
 /* the first dimension must be 3 */
 if (h->dims[0] != 3) {
    printf("RGB2PSEUDO - illegal rgb image, inner count must be 3, got %d\n", h->dims[0] );
    return -1; }
 nx = h->dims[1];	ny = h->dims[2];
 /* get the colormap array, this is output as a symbol */
 dim[0] = 3; dim[1] = 256;
 cmap_sym = ps[2];
 if (redef_array(cmap_sym, 0, 2, dim) != 1) return -1;
 h2 = (struct ahead *) sym[cmap_sym].spec.array.ptr;
 colormap = ((byte *)h2 + sizeof(struct ahead));
 /* also setup the output image array */
 dim[0] = nx; dim[1] = ny;
 result_sym = ps[1];
 if (redef_array(result_sym, 0, 2, dim) != 1) return -1;
 h = (struct ahead *) sym[result_sym].spec.array.ptr;
 data = ((byte *)h + sizeof(struct ahead));
 bzero(hist, 256 * sizeof (int));
 bzero(colormap, 768);
 
  /* pre-set first color as 0, note that the hist array is used as a color list here */
 ngifcolors = 1;
 hist[0] = 0;
 lastColor = lastIndex = 0;
 m = ny;
 gq = data;
 ptr_r = rgbinput;  ptr_g = rgbinput+1;  ptr_b = rgbinput+2;
 while (m--) {
   n = nx;
   while (n--) {
    thisColor = *ptr_r + (*ptr_g << 8) + (*ptr_b << 16);
    ptr_r += 3;  ptr_g += 3;  ptr_b += 3;
    /* are we lucky? */
    if (thisColor == lastColor) { *gq++ = (byte) lastIndex; } else {
      /* not this time, compare to all previous colors */
      for (k=0;k<ngifcolors;k++) {
        if (thisColor == hist[k]) break;
      }
      /* have we seen this one before ? */
      if (k < ngifcolors) { *gq++ = (byte) k; lastIndex = k; } else {
        /* apparently not */
	//printf("new color %#x, last %#x, k = %d, m,n %d %d\n", thisColor,lastColor, k,m,n);
	if (k < 256) {
	  hist[ngifcolors] = thisColor;
	  lastIndex =ngifcolors;
	  *gq++ = (byte) ngifcolors;
	  ngifcolors++;
	} else {
	  //printf("too many colors\n");
	  //return error_return;
	  *gq++ = 0;
	}
       }
       lastColor = thisColor;
     }
   }
 }
 /* now load the color map the way gif wants it */
 for (i=0;i<ngifcolors;i++) {
	colormap[i*3] = (byte) (hist[i] & 0xff);
	colormap[i*3+1] = (byte) ( (hist[i] >> 8) & 0xff);
	colormap[i*3+2] = (byte) ( (hist[i] >> 16) & 0xff);
 }

 return returnFlag;
 }
  /*------------------------------------------------------------------------*/
int ana_xw2gif(narg,ps)
 int narg, ps[];
 {
 /* read from an X window or pixmap and create a gif file if possible */
 /* argument scheme same as tvread except that a file name (a string) is added
 to the end */
 int	i,iq, nx, ny, ix, iy, wid, returnFlag = 1;
 int	root_flag = 0, status, x, y;
 int	line_step, nxim, nyim, n, m, hist[256];
 unsigned int	w, hh, bw, depth_local;
 char    *ptr, *filename;
 struct  ahead   *h;
 Drawable        src;
 Window	rt;
 byte	colormap[768], *gifArray, *xptr;
 XImage  *xi;
 int	gifMallocFlag = 0, gflag;
 /* the input arguments are all scalars */
 if (ck_events() != 1) return -1;
 wid = last_wid;
 ix = iy = 0;
 if (narg == 5 || narg == 1 || narg == 3) root_flag = 1;
 if (narg == 2) wid = int_arg( ps[0]);
 if (narg > 5 ) wid = int_arg( ps[4]);
 iq = ps[narg-1];
 if (sym[iq].class != 2) { return execute_error(70); }
 filename = (char *) sym[iq].spec.array.ptr;
 //printf("file name: %s\n", filename);

 if (root_flag) { src = RootWindow(display,screen_num);
   //w = nx = DisplayWidth(display, screen_num);
   //hh = ny = DisplayHeight(display, screen_num);
 } else {
   if (ck_window(wid) != 1) return -1;
   if (wid < 0 ) {
   src = (Drawable) maps[-wid];
   } else {
   src = (Drawable) win[wid];
   }
 }
 if ( src == 0 ) { printf("non-existent window in tvread: %d\n",wid);
	 return -1; }


 /* use XGetGeometry to get size, this works for Pixmaps also */
 status = XGetGeometry(display, src, &rt, &x, &y, &w, &hh, &bw, &depth_local);
 if (status == False) { printf("xw2gif: XGetWindowAttributes failure\n");
 	return -1; }
 nx = (int) w;
 ny = (int) hh;
 //printf("w, h, depth from XGetGeometry = %d, %d, %d\n", w, hh,depth_local);
 
 if (narg >= 3) { ix = int_arg( ps[0]);  iy = int_arg( ps[1]); }
 if (narg >= 5) { nx = int_arg( ps[2]);  ny = int_arg( ps[3]); }

 nx = MIN( nx, w - ix);  ny = MIN( ny, hh - iy);
 if ( nx < 0 || ny < 0 ) { printf("xw2gif - off screen\n"); return -1; }
 xi = XGetImage(display, src, ix, iy, nx, ny, AllPlanes, ZPixmap);
 line_step = xi->bytes_per_line;
 nxim = xi->width;	nyim = xi->height;
 xptr = xi->data + xi->xoffset;
 //printf("xw2gif, ptr = %d, offset = %d\n", xi->data,  xi->xoffset);
 //printf("xw2gif, bits_per_pixel = %d\n", xi->bits_per_pixel);
 //printf("xw2gif, depth = %d\n", xi->depth);
 printf("xw2gif, byte_order = %d for server (screen) this is ", xi->byte_order);
 if (xi->byte_order == MSBFirst) printf(" big endian\n"); else printf(" little endian\n");

 if (xi->depth == 8) {
 /* assumes a pseudo color class */
 /* need a histogram to determine colors */
 byte	*pq, *p2;
 bzero(hist, 256 * sizeof (int));
 bzero(colormap, 768);
 m = nyim;
 pq = gifArray = xptr;
 while (m--) { p2 = pq;	n = nxim; 
   while(n--) { hist[*pq++]++; }
   pq = p2 + line_step;
 }

 for (i=0;i<256;i++) if (hist[i]) {
 	colorcell.pixel = i;
	XQueryColor(display, def_colormap, &colorcell);
	colormap[i*3] = colorcell.red;
	colormap[i*3+1] = colorcell.green;
	colormap[i*3+2] = colorcell.blue;
 }

 } else if (xi->depth == 16 || xi->depth == 15) {
     printf("bits_per_pixel = %d is not supported\n", xi->bits_per_pixel);
     return -1;

 } else if (xi->depth == 24 || xi->depth == 32) {
   /* we assume that the pixmap is a simple graphics and has 256 or
   fewer colors. We find the colors and make a 8 bit GIF file. */
   unsigned int *pq;
   int	ngifcolors = 0, thisColor, lastColor, lastIndex, k;
   int	rmask, gmask, bmask, matchFlag;
#if __APPLE__
   int	mcorner, ncorner;
#endif
   byte	*gq;
   int	pad, r_bias, g_bias, b_bias, bits, m, n, nbl;
   unsigned char	*ptr_r, *ptr_g, *ptr_b, *pline_r, *pline_g, *pline_b;
   gq = gifArray = malloc(nxim*nyim+1000);
   if (gq) gifMallocFlag = 1; else { printf("error with malloc for GIF\n");
      return -1; }
   rmask = xi->red_mask;
   gmask = xi->green_mask;
   bmask = xi->blue_mask;
   //printf("rmask = %#x, gmask = %#x, bmask = %#x\n", rmask, gmask, bmask);
   /* we assume these are 8 bit masks but allow any order, though the normal
   case seems to be rgb */
  if (rmask < gmask)
   if (rmask < bmask) { r_bias = 0;
     if (gmask < bmask) { g_bias=1; b_bias=2;} else { g_bias=2; b_bias=1;}
    } else { b_bias = 0; r_bias = 1; g_bias=2; }
   else
   if (gmask < bmask) { g_bias = 0;
     if (rmask < bmask) { r_bias=1; b_bias=2;} else { r_bias=2; b_bias=1;}
    } else { b_bias = 0; g_bias = 1; r_bias=2; }
  pad = 0;
  bits = xi->bits_per_pixel;
  printf("bits/pixel = %d\n", bits);
  if (bits == 24) pad = 3;
  if (bits == 32) pad = 4;
  if (!pad) { printf("can't handle %d bits per pixel\n", bits);
  	return -1; }
  //printf("pad = %d\n", pad);
  /* that is the little endian result, have to flip for big endian */
#if LITTLEENDIAN
#else
  r_bias = pad - 1 - r_bias;
  g_bias = pad - 1 - g_bias;
  b_bias = pad - 1 - b_bias;
#endif
  /* check client/server byte endian mismatch, flip the bias if not matched, probably
  won't work for 24 bit case though */
  if (clientByteOrder != screenByteOrder) {
    r_bias = pad - 1 - r_bias;
    g_bias = pad - 1 - g_bias;
    b_bias = pad - 1 - b_bias;
  }
  ptr_r = pline_r = xptr + r_bias;
  ptr_g = pline_g = xptr + g_bias;
  ptr_b = pline_b = xptr + b_bias;
  //printf("r_bias, g_bias, b_bias = %d %d %d\n",r_bias, g_bias, b_bias);
  //printf("ptr_r, ptr_g, ptr_b = %d %d %d\n",ptr_r, ptr_g, ptr_b);
  nbl = xi->bytes_per_line;
  //printf("bytes/line = %d\n", nbl);
  /* pre-set first color as 0, note that the hist array is used as a color list here */
  ngifcolors = 0;
  lastColor = -1;
  m = ny;
#if __APPLE__
  mcorner = ny - 15;
  ncorner = nx - 16;
#endif
  while (m--) {
    n = nx;
    ptr_r = pline_r;  ptr_g = pline_g;  ptr_b = pline_b;
    pline_r += nbl;   pline_g += nbl;   pline_b += nbl;
    while (n--) {
     /* we don't want the dumb little 16x15 re-size tab that Apple puts in our corner */
#if __APPLE__
     if (m > 15 || n > 16) {
#endif
      matchFlag = 0;
      thisColor = *ptr_r + (*ptr_g << 8) + (*ptr_b << 16);
      /* are we lucky? */
      if (thisColor == lastColor) { *gq++ = (byte) lastIndex; } else {
	/* not this time, compare to all previous colors */
	if (ngifcolors) for (k=0;k<ngifcolors;k++) {
          if (thisColor == hist[k]) { matchFlag = 1;  break; }
	}
	/* have we seen this one before ? */
	if (matchFlag) { *gq++ = (byte) k; lastIndex = k; } else {
          /* apparently not */
	  //printf("new color %#x, last %#x, k = %d, m,n %d %d\n", thisColor,lastColor, k,m,n);
	  if (ngifcolors < 256) {
	    hist[ngifcolors] = thisColor;
	    lastIndex =ngifcolors;
	    *gq++ = (byte) ngifcolors;
	    ngifcolors++;
	  } else {
	    //return -1;
	    *gq++ = 0;
	  }
	}
	lastColor = thisColor;
      }
#if __APPLE__
     } else *gq++ = 0;
#endif
     ptr_r += pad; ptr_g += pad; ptr_b += pad;
   }
 }
 if (ngifcolors > 255) printf("*** There were too many colors for gif, some pixels will be blanked. ***\n");
 line_step = nxim;
 /* now load the color map the way gif wants it */
 for (i=0;i<ngifcolors;i++) {
	colormap[i*3] = (byte) (hist[i] & 0xff);
	colormap[i*3+1] = (byte) ( (hist[i] >> 8) & 0xff);
	colormap[i*3+2] = (byte) ( (hist[i] >> 16) & 0xff);
 }
 } else {
   printf("unsupported pixmap depth, it is %d\n", xi->depth);
   return -1;
 }

 if (!gifwrite(gifArray, nxim, nyim, line_step, colormap, filename)) {
 	printf("error writing GIF file\n"); returnFlag = -1; }

 //printf("before destroy, ptr = %d, offset = %d\n", xi->data,  xi->xoffset);
 XDestroyImage(xi);
 if (gifMallocFlag) free(gifArray);
 return returnFlag;
 }
 /*------------------------------------------------------------------------*/
int ana_xevent(narg,ps)
 int narg, ps[];
 {
 XEvent  report;
 int     nev, i;
 XFlush(display);
 nev = XPending( display);
 printf("number of events = %d\n",nev);
 if (nev <=0 ) return 1;
 for (i=0;i<nev;i++) {
 XNextEvent(display, &report);
 printf("report.type = %d\n",report.type);
 switch (report.type) {
  case ButtonPress:
 printf("Button down, window = %d\n", report.xbutton.window);
 printf("x and y = %d %d\n",report.xbutton.x,report.xbutton.y);
 printf("button # %d\n", report.xbutton.button);
 printf("time = %x\n", report.xbutton.time);
 break;
  case ButtonRelease:
 printf("Button up, window = %d\n", report.xbutton.window);
 printf("x and y = %d %d\n",report.xbutton.x,report.xbutton.y);
 printf("button # %d\n", report.xbutton.button);
 printf("time = %x\n", report.xbutton.time);
 break;
  case KeyPress:
 printf("Key press, window = %d\n", report.xkey.window);
 printf("x and y = %d %d\n",report.xkey.x,report.xkey.y);
 printf("keycode # %d\n", report.xkey.keycode);
 printf("time = %x\n", report.xkey.time);
 break;
  case FocusIn:
 printf("Focus in, window = %d\n", report.xfocus.window);
 printf("type, mode, detail = %d %d %d\n",report.xfocus.type,report.xfocus.mode,
  report.xfocus.detail);
 break;
  case FocusOut:
 printf("Focus out, window = %d\n", report.xfocus.window);
 printf("type, mode, detail = %d %d %d\n",report.xfocus.type,report.xfocus.mode,
  report.xfocus.detail);
 break;
  case ConfigureNotify:
 printf("ConfigureNotify, window = %d\n", report.xconfigure.window);
 printf("x and y = %d %d\n",report.xconfigure.x,report.xconfigure.y);
 printf("w and h = %d %d\n",report.xconfigure.width,report.xconfigure.height);
 break;
  case DestroyNotify:
 printf("DestroyNotify, window = %d\n", report.xdestroywindow.window);
 printf("window that selected event = %d\n", report.xdestroywindow.event);
 break;
  case ClientMessage:
 printf("ClientMessage, window = %d\n", report.xclient.window);
 printf("format = %d\n", report.xclient.format);
 printf("atom = %d\n", report.xclient.data.l[0]);
 break;
  default:
 printf("an event not in current list\n");
 break; 
}
 }
 return 1;
 }
 /*------------------------------------------------------------------------*/
int ana_xpurge(narg,ps)		/* just throw away any pending X events */
 int narg, ps[];
 {
 XEvent  report;
 int     nev, i;
 if (connect_flag != 1)  return 1;  /* no op if no connection */
 XFlush(display);
 nev = XPending( display);
 for (i=0;i<nev;i++) {
 XNextEvent(display, &report);
 }
 return 1;
 }
 /*------------------------------------------------------------------------*/
int ana_xplace(narg,ps)
 /* response to a key or button press in an ana window and note the
 time and position */
 int narg, ps[];
 {
 int    i, hq, wq, nc;
 char	buffer[16];
 KeySym	keysym;
 XEvent  report;
 if (connect_flag != 1)  return 1;  /* no op if no connection */
 if (ck_events() != 1) return -1;
 /* wait for a button or key press */
 XMaskEvent(display, KeyPressMask | ButtonPressMask, &report);
 /* which window ? */
 last_wid = -1;
 for (i=0;i<MAXWINDOW;i++) {
 if (win[i] == report.xbutton.window)
	 { last_wid = i; break; }
 }
 if (last_wid == -1) { printf("impossible error, event in non-ANA window\n");
	 return -1; }
 /* preset key and button to 0, only one of these will be set */
 ana_keycode = ana_keysym = ana_button = 0;
 hq = ht[i];	wq=wd[i];
 ixhigh = wq - 1;  iyhigh = hq - 1;
 xhair = (float) xcoord/ (float) wq;
 yhair = (float) (hq - 1 - ycoord)/ (float) hq;
 last_time = report.xbutton.time;
 switch (report.type) {
  case ButtonPress:
   ana_button = report.xbutton.button;
   xcoord = report.xbutton.x;
   ycoord = report.xbutton.y;
   ana_keystate = report.xbutton.state;
   break;
  case KeyPress:
   ana_keycode = report.xkey.keycode;
   xcoord = report.xkey.x;
   ycoord = report.xkey.y;
   ana_keystate = report.xkey.state;
   nc = XLookupString(&(report.xkey), buffer, 15, &keysym, NULL);
   buffer[nc] = NULL;
   //printf("nc = %d, string = %s\n", nc, buffer);
   ana_keysym = (int) keysym;
   break;
 }
 /* return parameters if there were arguments */
 if (narg > 0) {
 if (redef_scalar( ps[0], 2, &xcoord) != 1) return execute_error(13);
 if (narg > 1) {
 if (redef_scalar( ps[1], 2, &ycoord) != 1) return execute_error(13);
 if (narg > 2) {
 if (redef_scalar( ps[2], 2, &last_wid) != 1) return execute_error(13);
 }}}
 return 1;
 }
 /*------------------------------------------------------------------------*/
int xwindow_plot(ix, iy, mode)
 int     ix, iy, mode;
 {
 int     wid, mapid;
 /* used by device independent drawing call xymov */
 /* ck_events(); */
 wid = last_wid;
 /*printf("ix, iy, mode = %d %d %d\n",ix,iy,mode);*/
 if (mode == 0) { xold = ix;  yold = iy;  return 1; }
 if (wid < 0 ) {
 mapid = - wid;
 if ( maps[mapid] == 0 ) ana_xcreat(wid, 512, 512,0,0,0);
 XDrawLine(display, maps[mapid], gcmap[mapid], xold, yold, ix, iy);
 } else {                                        /* window case */
 if ( win[wid] == 0 ) ana_xcreat(wid, 512, 512,0,0,0);
 XDrawLine(display, win[wid], gc[wid], xold, yold, ix, iy);
 }
 xold = ix;  yold = iy;
 /* XFlush(display); */
 return 1;
 }
 /*------------------------------------------------------------------------*/
GC get_gc(wid)
 int     wid;
 {
 GC		gq;
 if (wid < 0 ) {
  if (invert_flag) gq = gcmapnot[-wid]; else gq = gcmap[-wid];
 } else {
  if (invert_flag) gq = gcnot[wid]; else gq = gc[wid];
 }
 return gq;
 }
 /*------------------------------------------------------------------------*/
Drawable get_drawable(wid)
 int     wid;
 {
 Drawable	dq;
 if (wid < 0 ) {
 	dq = maps[-wid];
	if (dq == 0) ana_xcreat(wid, 512, 512,0,0,0); else set_defw(wid);
	} else {
	dq = win[wid];
	if (dq == 0) ana_xcreat(wid, 512, 512,0,0,0); else set_defw(wid);
 }
 return dq;
 }
 /*------------------------------------------------------------------------*/
int ana_xdrawline(narg, ps)
 /* subroutine, call is xdrawline, x1, y1, x2, y2, [wid] where the arguments
 can be scalars or arrays but all must match in length */
 /* used for X window drawing with lower overhead than xymov calls */
 /* better for interactive graphics */
 int     narg, ps[];
 {
 int     wid, mapid, ixs, iys, ix, iy;
 Drawable	dq;
 GC		gq;
 wid = last_wid;
 if (narg > 4) { if (int_arg_stat(ps[4], &wid) != 1) return -1; }
 dq = get_drawable(wid);
 gq = get_gc(wid);
 /* note that the set_defw should be done before getting the other
 arguments in case any of them use the window limit symbols */
 /* the arguments can be scalars (class 1 or 8) or arrays (class 4), check
 first for not class 4 as first step */
 if (sym[ ps[0] ].class != 4) {
   /* assume all scalars, int_arg_stat will complain if that doesn't happen, it
   will also handle the class 8 for us */
   if (int_arg_stat(ps[0], &ixs) != 1) return -1;
   if (int_arg_stat(ps[1], &iys) != 1) return -1;
   if (int_arg_stat(ps[2], &ix) != 1) return -1;
   if (int_arg_stat(ps[3], &iy) != 1) return -1;

   XDrawLine(display, dq, gq, ixs, iys, ix, iy);
 } else {
 /* here we expect 4 arrays of the same size */
   int	*px1, *px2, *py1, *py2, n, nx, i, nd, j, iq;
   struct  ahead   *h;
   iq = ana_long(1, &ps[0] );
   h = (struct ahead *) sym[iq].spec.array.ptr;
   nd = h->ndim;
   nx = 1; for (j=0;j<nd;j++) nx *= h->dims[j];	/*# of elements */
   px1 = (int *) ((char *) h + sizeof( struct ahead ));

   if (sym[ ps[1] ].class != 4) return execute_error(124);
   iq = ana_long(1, &ps[1] );
   h = (struct ahead *) sym[iq].spec.array.ptr;
   nd = h->ndim;
   n = 1; for (j=0;j<nd;j++) n *= h->dims[j];	/*# of elements */
   if (n != nx) return execute_error(124);
   py1 = (int *) ((char *) h + sizeof( struct ahead ));

   if (sym[ ps[2] ].class != 4) return execute_error(124);
   iq = ana_long(1, &ps[2] );
   h = (struct ahead *) sym[iq].spec.array.ptr;
   nd = h->ndim;
   n = 1; for (j=0;j<nd;j++) n *= h->dims[j];	/*# of elements */
   if (n != nx) return execute_error(124);
   px2 = (int *) ((char *) h + sizeof( struct ahead ));

   if (sym[ ps[3] ].class != 4) return execute_error(124);
   iq = ana_long(1, &ps[3] );
   h = (struct ahead *) sym[iq].spec.array.ptr;
   nd = h->ndim;
   n = 1; for (j=0;j<nd;j++) n *= h->dims[j];	/*# of elements */
   if (n != nx) return execute_error(124);
   py2 = (int *) ((char *) h + sizeof( struct ahead ));

   /* now just loop some xdrawline calls, we don't know if the lines connect */
   while (n--)  XDrawLine(display, dq, gq, *px1++, *py1++, *px2++, *py2++);
 }
 return 1;
 }
 /*------------------------------------------------------------------------*/
int ana_xinvertline(narg, ps)
 /* used for X window drawing with lower overhead than xymov calls */
 /* better for interactive graphics */
 int     narg, ps[];
 {
 int	iq;
 invert_flag = 1;
 iq = ana_xdrawline(narg, ps);
 invert_flag = 0;
 return iq;
 }
 /*------------------------------------------------------------------------*/
int ana_xinvertarc(narg, ps)
 int     narg, ps[];
 {
 int	iq;
 invert_flag = 1;
 iq = ana_xdrawarc(narg, ps);
 invert_flag = 0;
 return iq;
 }
 /*------------------------------------------------------------------------*/
int draw_params(wid, ps)
 int	wid, ps[];
 {
 /* loads some generally needed parameters into scratch areas */
 scrat_Drawable = get_drawable(wid);
 scrat_GC = get_gc(wid);
 /* assume all scalars, int_arg_stat will complain if that doesn't happen, it
 will also handle the class 8 for us */
 if (int_arg_stat(ps[0], &scrat_ixs) != 1) return 1;
 if (int_arg_stat(ps[1], &scrat_iys) != 1) return 1;
 if (int_arg_stat(ps[2], &scrat_w) != 1) return 1;
 if (int_arg_stat(ps[3], &scrat_h) != 1) return 1;
 return 0;
 }
 /*------------------------------------------------------------------------*/
int ana_xdrawarc(narg, ps)
 /* subroutine, call is xdrawarc, x1, y1, w, h, [a1, a2, win] */
 int     narg, ps[];
 {
 int     wid, xa1, xa2;
 float	a1, a2;
 wid = last_wid;
 if (narg > 6) { if (int_arg_stat(ps[6], &wid) != 1) return -1; }
 if (draw_params(wid, ps)) return -1;
 /* note that the set_defw should be done before getting the other
 arguments in case any of them use the window limit symbols */
 a1 = 0.0;	a2 = 360.0;
 if (narg > 4 ) if (float_arg_stat(ps[4], &a1) != 1) return -1;
 if (narg > 5 ) if (float_arg_stat(ps[5], &a2) != 1) return -1;
 /* convert these fp angles into X units */
 xa1 = (int) 64.*a1;	xa2 = (int) 64.*a2;

 XDrawArc(display, scrat_Drawable, scrat_GC, scrat_ixs, scrat_iys, scrat_w,scrat_h,xa1,xa2);
 return 1;
 }
 /*------------------------------------------------------------------------*/
int ana_xfillarc(narg, ps)
 /* subroutine, call is xdrawarc, x1, y1, w, h, [a1, a2, win] */
 int     narg, ps[];
 {
 int     wid, xa1, xa2;
 float	a1, a2;
 wid = last_wid;
 if (narg > 6) { if (int_arg_stat(ps[6], &wid) != 1) return -1; }
 if (draw_params(wid, ps)) return -1;
 /* note that the set_defw should be done before getting the other
 arguments in case any of them use the window limit symbols */
 a1 = 0.0;	a2 = 360.0;
 if (narg > 4 ) if (float_arg_stat(ps[4], &a1) != 1) return -1;
 if (narg > 5 ) if (float_arg_stat(ps[5], &a2) != 1) return -1;
 /* convert these fp angles into X units */
 xa1 = (int) 64.*a1;	xa2 = (int) 64.*a2;

 XFillArc(display, scrat_Drawable, scrat_GC, scrat_ixs, scrat_iys, scrat_w,scrat_h,xa1,xa2);
 return 1;
 }
 /*------------------------------------------------------------------------*/
int ana_xfillrectangle(narg, ps)
 /* subroutine, call is xfillrectangle, x1, y1, w, h, [win] */
 int     narg, ps[];
 {
 int     wid;
 wid = last_wid;
 if (narg > 4) { if (int_arg_stat(ps[4], &wid) != 1) return -1; }
 if (draw_params(wid, ps)) return -1;;
 /* note that the set_defw should be done before getting the other
 arguments in case any of them use the window limit symbols */

 XFillRectangle(display, scrat_Drawable, scrat_GC, scrat_ixs, scrat_iys, scrat_w,scrat_h);
 return 1;
 }
 /*------------------------------------------------------------------------*/
int ana_xdrawrectangle(narg, ps)
 /* subroutine, call is xdrawrectangle, x1, y1, w, h, [win] */
 int     narg, ps[];
 {
 int     wid;
 wid = last_wid;
 if (narg > 4) { if (int_arg_stat(ps[4], &wid) != 1) return -1; }
 if (draw_params(wid, ps)) return -1;;
 /* note that the set_defw should be done before getting the other
 arguments in case any of them use the window limit symbols */

 XDrawRectangle(display, scrat_Drawable, scrat_GC, scrat_ixs, scrat_iys, scrat_w,scrat_h);
 return 1;
 }
 /*------------------------------------------------------------------------*/
int ana_xflush()
 {
 XFlush(display);	return 1;
 }
 /*------------------------------------------------------------------------*/
int ana_xpen(pen)
 float     pen;
 {
 int     wid;
 GC		gq;
 Drawable	dq;
 if (ck_events() != 1) return -1;
 if (pen < 1.0 || pen > 100.) {
  printf("bad pen size passed to ana_xpen %f", pen);
  return 0; }
 wid = last_wid;
 /* don't need the drawable but get_drawable creates the window if necessary */
 /* also do the inversion GC */
 invert_flag = 1;
 dq = get_drawable(wid);
 gq = get_gc(wid);
 XSetLineAttributes(display, gq, (int) pen, LineSolid, CapRound, JoinRound);
 invert_flag = 0;
 gq = get_gc(wid);
 XSetLineAttributes(display, gq, (int) pen, LineSolid, CapRound, JoinRound);
 return 1;
 }
 /*------------------------------------------------------------------------*/
int ana_pen_invert(narg, ps)
 int     narg, ps[];
 /* does only the inversion GC, might drop this routine */
 {
 int     wid, pen;
 GC		gq;
 Drawable	dq;
 if (ck_events() != 1) return -1;
 if (int_arg_stat(ps[0], &pen) != 1) return -1;
 if (pen < 1 || pen > 100) {
  printf("bad pen size passed to ana_xpen %f", pen);
  return 0; }
 wid = last_wid;
 invert_flag = 1;
 dq = get_drawable(wid);
 gq = get_gc(wid);
 XSetLineAttributes(display, gq,(int) pen,LineSolid,CapRound,JoinRound);
 invert_flag = 0;
 return 1;
 }
 /*------------------------------------------------------------------------*/
int ana_xsetgc(narg, ps)
 int     narg, ps[];
 /* set the GC function for a given win */
 /* the available settings are:
       GXclear            0x0    0
       GXand              0x1    src AND dst
       GXandReverse       0x2    src AND NOT dst
       GXcopy             0x3    src
       GXandInverted      0x4    (NOT src) AND dst
       GXnoop             0x5    dst
       GXxor              0x6    src XOR dst
       GXor               0x7    src OR dst
       GXnor              0x8    (NOT src) AND (NOT
                                 dst)
       GXequiv            0x9    (NOT src) XOR dst
       GXinvert           0xa    NOT dst
       GXorReverse        0xb    src OR (NOT dst)
       GXcopyInverted     0xc    NOT src
       GXorInverted       0xd    (NOT src) OR dst
       GXnand             0xe    (NOT src) OR (NOT
                                 dst)
       GXset              0xf    1
 */
 {
 int fun, wid;
 if (ck_events() != 1) return -1;
 if (int_arg_stat(ps[0], &fun) != 1) return -1;
 if (fun < 0 || fun > 15) {
  printf("bad GC function passed to ana_xsetgc %d", fun);
  return 0; }
 if (narg > 1) { if (int_arg_stat(ps[1], &wid) != 1) return -1; }
	else wid = last_wid;
 if (ck_window(wid) != 1) return -1;
 printf("wid = %d, function = %d\n", wid, fun);
 XSetFunction(display, gc[wid], fun);
 return 1;
 }
 /*------------------------------------------------------------------------*/
int set_xfont(fontname, wid)
 char *fontname;
 int	wid;
 {
 /* do both the regular and the inversion GC */
 GC		gq;
 //Drawable	dq;
 XFontStruct	*font;
 invert_flag = 1;
 //dq = get_drawable(wid);
 gq = get_gc(wid);
 font = XLoadQueryFont(display, fontname);
 if (font == NULL) { printf("font does not exist: %s\n", fontname);  return -1; }
 if (wid < 0) {
   font_info_maps[-wid] = font;
 } else {
   font_info[wid] = font;
 }

 XSetFont( display, gq, font->fid);
 invert_flag = 0;
 gq = get_gc(wid);
 XSetFont( display, gq, font->fid);
 return 1;
 }
 /*------------------------------------------------------------------------*/
int ana_xfont(narg, ps)
 /* set font for a window */
 int     narg, ps[];
 {
 int      wid, iq;
 char    *fontname;
 /* first arg is a string which should be a font name */
 if (ck_events() != 1) return -1;
 iq = ps[0];
 if (sym[iq].class != 2) return execute_error(70);
 fontname = (char *) sym[iq].spec.array.ptr;
 wid = last_wid;
 if (narg > 1) wid = int_arg( ps[1]);
 return set_xfont(fontname, wid);
 }
 /*------------------------------------------------------------------------*/
int ana_ximagelabel(narg, ps)
 /* user labels, this uses XDrawImageString */
 /* xlabel, string, ix, iy, win */
 int     narg, ps[];
 {
 int	iq;
 image_string_flag = 1;
 iq = ana_xlabel(narg, ps);
 image_string_flag = 0;
 return iq;
 }
 /*------------------------------------------------------------------------*/
int ana_xlabel(narg, ps)
 /* user labels */
 /* xlabel, string, ix, iy, win */
 int     narg, ps[];
 {
 int     wid, iq, ix, iy, len, mapid, stat;
 char    *s;
 GC		gq;
 Drawable	dq;
 /* first arg is a string which will be the label */
 if (ck_events() != 1) return -1;
 iq = ps[0];
 if (sym[iq].class != 2) return execute_error(70);
 s = (char *) sym[iq].spec.array.ptr;
 len = sym[iq].spec.array.bstore - 1;
 ix = int_arg( ps[1]);   iy = int_arg( ps[2]);
 wid = last_wid;
 if (narg > 3) { wid = int_arg( ps[3]); }
 dq = get_drawable(wid);
 gq = get_gc(wid);
 if (image_string_flag) stat=XDrawImageString( display, dq, gq, ix, iy, s, len);
   else stat=XDrawString( display, dq, gq, ix, iy, s, len);
 if (stat) printf("bad XDrawString return = %d\n", stat);
 XFlush(display);
 return 1;
 }
 /*------------------------------------------------------------------------*/
int ana_xinvertlabel(narg, ps)
 int     narg, ps[];
 {
 int	iq;
 invert_flag = 1;
 iq = ana_xlabel(narg, ps);
 invert_flag = 0;
 return iq;
 }
 /*------------------------------------------------------------------------*/
int ana_xlabelwidth(narg, ps)
 /* user label width */
 int     narg, ps[];
 {
 int     wid, iq, len, result_sym;
 char    *s;
 XFontStruct	*font;
 /* arg is a string which will be the label */
 if (ck_events() != 1) return -1;
 iq = ps[0];
 if (sym[iq].class != 2) return execute_error(70);
 s = (char *) sym[iq].spec.array.ptr;
 len = sym[iq].spec.array.bstore - 1;
 wid = last_wid;
 if (wid < 0) {
   font = font_info_maps[-wid];
 } else {
   font = font_info[wid];
 }
 if (font == NULL) {
   printf("no font defined for window %d\n", wid);
   iq = 0;
 } else {
   iq = XTextWidth(font, s, len );
 }
 result_sym = scalar_scratch(2);
 sym[result_sym].spec.scalar.l = iq;
 return result_sym;
 }
 /*------------------------------------------------------------------------*/
int xlabel(s, ix, iy)
                                        /* internal call for labels */
 int     ix, iy;
 char    *s;
 {
 int     len, iq, wid, mapid;
 len = strlen(s);
 wid = last_wid;
 if (wid < 0 ) {
 mapid = - wid;
 XDrawString( display, maps[mapid], gcmap[mapid], ix, iy, s, len);
 } else {                                        /* window case */
 XDrawString( display, win[wid], gc[wid], ix, iy, s, len);
 }
 return 1;
 }
 /*------------------------------------------------------------------------*/
int xlabelwidth(s, wid)
                                        /* internal call for labels */
 char    *s;
 int	wid;
 {
 XFontStruct	*font;
 if (wid < 0) {
   font = font_info_maps[-wid];
 } else {
   font = font_info[wid];
 }
 return  XTextWidth(font, s, strlen(s) );
 }
 /*------------------------------------------------------------------------*/
void xfontsize(fs, wid)
 float fs;
 int	wid;
 {
 static	float current_xfont_size;
 char	fontname[256];
 /* 6/28/2003 - the fonts have to scale with window size (because their offset
 positions do), use the x size as a reference with 512 -> 100 font size */
 float x;
 XFontStruct	*font;
 if (wid < 0) {
   font = font_info_maps[-wid];
   x = wd[-wid];
 } else {
   font = font_info[wid];
   x = wd[wid];
 }
 x = fs * x/512.;
 if (font == NULL || current_xfont_size != x) {
  
  sprintf(fontname, "-adobe-helvetica-bold-r-normal--*-%d-100-100-P-*-ISO8859-1", (int) (x*100.));
  //printf("\nfont name: %s\n", fontname);
  set_xfont(fontname, wid);
  current_xfont_size = x; }
 }
 /*------------------------------------------------------------------------*/
int xfontxlabel(x, y, label)
 float	x, y;
 char	*label;
 {
 /* the window is not passed via plot, probably need to change that,
 so use the current default */
 extern	 float  fsized;
 extern	 int  iyhigh;
 int	ix, iy, wid;
 /* should we be here? check for a null string */
 if (*label == NULL) return	1;
 wid = last_wid;
 xfontsize(fsized, wid);	/* check font size */
 /* the xdi, ydi has to be converted to X coordinates */
 if (x < 1.0 ) x = x * xfac;
 if (y < 1.0 ) y = y * yfac;
 ix = (int) (x + .5);	iy = (int) ( y + .5);
 iy = iyhigh - iy;	/* upside down */
 /* need to center it horizontally */
 ix = ix - xlabelwidth(label, wid)/2;
 //printf("iyhigh, ix, iy = %d, %d, %d\n",iyhigh, ix, iy);
 xlabel(label, ix, iy);
 return 	1;
 }
 /*------------------------------------------------------------------------*/
int xfontylabel(float x, float y, char * label, float *xleftmost)
 //float	x, y, *xleftmost;
 //char	*label;
 {
 /* this is for the labels on the y axis, these are drawn in the
 horizontal direction */
 /* the window is not passed via plot, probably need to change that,
 so use the current default */
 extern	 float  fsized;
 extern	 int  iyhigh;
 int	ix, iy, wid;
 /* should we be here? check for a null string */
 if (*label == NULL) return	1;
 //printf("passed xleftmost = %g\n", *xleftmost);
 wid = last_wid;
 xfontsize(fsized, wid);	/* check font size */
 /* the xdi, ydi has to be converted to X coordinates */
 if (x < 1.0 ) x = x * xfac;
 if (y < 1.0 ) y = y * yfac;
 ix = (int) (x + .5);	iy = (int) ( y + .5);
 iy = iyhigh - iy;	/* upside down */
 /* right justify */
 ix = ix - xlabelwidth(label,wid);
 *xleftmost = MIN(*xleftmost, (float) ix / xfac);
 //printf("xleftmost = %g\n", *xleftmost);
 xlabel(label, ix, iy);
 return 	1;
 }
 /*------------------------------------------------------------------------*/
int xfontytitle(x, y, label)
 float	x, y;
 char	*label;
 {
 /* this is for the title on the y axis, it is drawn in the
 vertical direction which is implemented here by drawing into
 a pixmap that we flip into an image that is drawn on the screen */
 /* the window is not passed via plot, probably need to change that,
 so use the current default */
 extern	 float  fsized;
 extern	 int  iyhigh;
 int	ix, iy, wid, w, h, len, direct, ascent, descent;
 int	nbytes, i, j, bytes_per_pixel, ixx, iyy;
 unsigned long	pix;
 char	*pd;
 XCharStruct  sizes;
 XImage	*temp, *tempr;
 Pixmap px;
 XFontStruct	*font;
 /* should we be here? check for a null string */
 if (*label == NULL) return	1;
 wid = last_wid;
 xfontsize(fsized, wid);	/* check font size */
 /* the xdi, ydi has to be converted to X coordinates */
 if (x < 1.0 ) x = x * xfac;
 if (y < 1.0 ) y = y * yfac;
 ix = (int) (x + .5);	iy = (int) ( y + .5);
 iy = iyhigh - iy;	/* upside down */
 len = strlen(label);
 if (wid < 0) {
   font = font_info_maps[-wid];
 } else {
   font = font_info[wid];
 }
 XTextExtents(font, label, len, &direct, &ascent, &descent, &sizes);
 //printf("direct = %d, ascent = %d, descent = %d\n",direct, ascent, descent);
 //printf("lbearing = %d, rbearing = %d, width = %d, ascent = %d,descent = %d\n",
 // sizes.lbearing,sizes.rbearing,sizes.width,sizes.ascent,sizes.descent);
 /* get size of the label for a pixmap */
 w = sizes.width;
 iy = iy - w/2;
 h = sizes.ascent + sizes.descent;
 ix = ix - h;
 px = XCreatePixmap(display, RootWindow(display,screen_num), w, h, depth);
 /* fill with background */
 /* draw into the Pixmap, use the GC for wid */
 //XDrawImageString( display, px, gc[wid], sizes.lbearing, sizes.ascent, label, len);
 XDrawImageString( display, px, gc[wid], 0, sizes.ascent, label, len);
 /* pull out into an image */
 temp = XGetImage(display, px, 0, 0, w, h, 0xffffffff, ZPixmap);
 //printf("bits_per_pixel for XGetImage = %d\n", temp->bits_per_pixel);
 /* make an image with the modified orientation */
 tempr = XCreateImage(display,vis,depth,ZPixmap,0, NULL ,h,w,8,0);
 //printf("bits_per_pixel for XCreateImage = %d\n", tempr->bits_per_pixel);
 /* figure the size for any visual */
 nbytes = tempr->bytes_per_line * tempr->height;
 //printf("nbytes = %d, tempr->bytes_per_line = %d, tempr->height = %d\n",
 //  nbytes, tempr->bytes_per_line, tempr->height);
 pd = (char *) malloc(nbytes);
 tempr->data = pd;
 /* not efficient, but should be able to handle any combination of
 server/client with XGetPixel and XPutPixel */
 for (j=0;j<h;j++) {
   for (i=0;i<w;i++) {
    pix = XGetPixel(temp, i, j);
    XPutPixel(tempr, j, w - i - 1, pix);
   }
 }
 ixx = iyy = 0;
 /* crop if necessary */
 if (iy < 0) { iyy = -iy; iy = 0; }
 if ( (iy+w) > iyhigh) w = iyhigh - iy;
 if (ix < 0) { ixx = -ix; ix = 0; }
 if ( (ix+h) > ixhigh) h = ixhigh - ix;
 XPutImage(display, win[wid], gc[wid], tempr, ixx, iyy, ix, iy, h ,w); 
 XFreePixmap(display, px);
 return 	1;
 }
 /*------------------------------------------------------------------------*/
int ana_xquery_f(narg,ps)
 /* get current location of mouse and state of button */
 /* this is the function version, returns 1 if in the specified window */
 int narg, ps[];
 {
 int	iq, wid;
 Bool	status;
 Window	qroot, qchild;
 /*ck_events();*/
 if (narg > 0) wid = int_arg( ps[0]); else wid = last_wid;
 status = XQueryPointer(display, win[wid], &qroot, &qchild, &root_x,
 &root_y,&xcoord, &ycoord, &kb);
 /* though it may seem silly, we find out whether we are in the specified
 window by checking the pointer coords., when a better way is found ... */
 if (xcoord <0 || ycoord < 0) return 4;		/* a zip, not in window */
 if (xcoord >= wd[wid] || ycoord >= ht[wid]) return 4;
 /* pointer must be in window, return the symbol # that is an int 1 */
 return 1;
 }
 /*------------------------------------------------------------------------*/
int ana_xquery(narg,ps)
 /* get current location of mouse and state of button */
 int narg, ps[];
 {
 /* this just calls the function and ignores the return status */
 ana_xquery_f(narg, ps);
 return 1;
 }
 /*------------------------------------------------------------------------*/
int ana_xwindowinfo(narg,ps)
 /* type some window attributes */
 int narg, ps[];
 {
 int	iq, wid;
 Bool	status;
 XWindowAttributes	wat;

 if (narg > 0) wid = int_arg( ps[0]); else
 	{  if (ck_events() != 1) return -1;	wid = last_wid; }
 if ( win[wid] == 0 ) { printf("no such window %d\n", wid); return 4; }
 status = XGetWindowAttributes(display, win[wid], &wat);
 if (status == False) { printf("XWINDOWINFO: XGetWindowAttributes failure\n");
 	return 0; }
 printf("location: (%d, %d)\n    size: (%d, %d) depth: %d\n",
 	wat.x, wat.y,wat.width,wat.height, wat.depth);
 printf("backing store: %d\n", wat.backing_store);
 printf("NotUseful, WhenMapped, Always = %d %d %d\n", NotUseful, WhenMapped, Always);
 /* also set some of the ana parameters */
 return 1;
 }
 /*------------------------------------------------------------------------*/
int ana_xroot_coord_id(narg,ps)
 /* gets the root or screen coord for a window using the id,
 call is  xroot_coord, win_id, root_x, root_y, nx, ny
 the root_x and y, nx, ny are returned values */
 int narg, ps[];
 {
 xroot_coord_mode = 0;
 return ana_xroot_coord(narg,ps);
 }
 /*------------------------------------------------------------------------*/
int ana_xroot_coord(narg,ps)
 /* gets the root or screen coord for the window,
 call is  xroot_coord, win, root_x, root_y, nx, ny
 the root_x and y, nx, ny are returned values */
 int narg, ps[];
 {
 int	iq, wid, absx, absy, nx, ny;
 Bool	status;
 Window dummywin, w;
 XWindowAttributes	wat;

 if (int_arg_stat(ps[0], &wid) != 1) return -1;
 if (xroot_coord_mode) {
 if (ck_window(wid) != 1) return -1;
 if ( win[wid] == 0 ) { printf("no such window %d\n", wid); return 4; }
 /* no position for a pixmap so just return (0,0) and the size, also
 set w=NULL as a flag to avoid calls below */
 if ( wid < 0 ) { 
 	w = NULL; absx = absy = 0;  nx = wdmap[-wid];  ny = htmap[-wid]; }
  else {  w = win[wid]; }
 } else w = wid;
 if (w) {
 status = XTranslateCoordinates(display, w, RootWindow(display, screen_num),
	0, 0, &absx, &absy, &dummywin);
 if (status == False) { printf("XROOT_COORD: XTranslateCoordinates failure\n");
 	return 0; }
 status = XGetWindowAttributes(display, w, &wat);
 if (status == False) { printf("XWINDOWINFO: XGetWindowAttributes failure\n");
 	return 0; }
 nx = wat.width;  ny = wat.height;
 }
 if (redef_scalar( ps[1], 2, &absx) != 1) return execute_error(13);
 if (redef_scalar( ps[2], 2, &absy) != 1) return execute_error(13);
 if (redef_scalar( ps[3], 2, &nx) != 1) return execute_error(13);
 if (redef_scalar( ps[4], 2, &ny) != 1) return execute_error(13);
 xroot_coord_mode = 1;	// always set the mode to 1 before return
 return 1;
 }
 /*------------------------------------------------------------------------*/
int ana_xwd(narg,ps)
 /* given the ana window #, organizes a call to xwd */
 int narg, ps[];
 {
 int	wid, result_sym;
 Window src;
 if (int_arg_stat(ps[0], &wid) != 1) return -1;
 if ( win[wid] == 0 ) { printf("no such window %d\n", wid); return 4; }
 src = win[wid];
 result_sym = xwd(src);
 return result_sym;
 }
 /*------------------------------------------------------------------------*/
int ana_xwarpmouse(narg,ps)
 /* given the ana window # and location, moves pointer */
 int narg, ps[];
 {
 int	wid, ix, iy;
 Window dest;
 if (int_arg_stat(ps[0], &wid) != 1) return -1;
 if ( win[wid] == 0 ) { printf("no such window %d\n", wid); return 4; }
 dest = win[wid];
 if (int_arg_stat(ps[1], &ix) != 1) return -1;
 if (int_arg_stat(ps[2], &iy) != 1) return -1;
 XWarpPointer(display, NULL, dest, 0,0,0,0, (unsigned int) ix, (unsigned int) iy);
 return 1;
 }
 /*------------------------------------------------------------------------*/
int ana_xsetinputfocus(narg,ps)
 /* given the ana window # and location, moves pointer */
 int narg, ps[];
 {
 int	wid, ix, iy;
 Window dest;
 if (int_arg_stat(ps[0], &wid) != 1) return -1;
 if ( win[wid] == 0 ) { printf("no such window %d\n", wid); return 4; }
 dest = win[wid];
 XSetInputFocus(display, dest, RevertToPointerRoot, CurrentTime);
 return 1;
 }
 /*------------------------------------------------------------------------*/
int ana_xwd_id(narg,ps)
 /* given the X window ID (not the ana window #), organizes a call to xwd */
 int narg, ps[];
 {
 int	wid, result_sym;
 Window src;
 if (int_arg_stat(ps[0], &wid) != 1) return -1;
 src = (Window) wid;
 result_sym = xwd(src);
 return result_sym;
 }
 /*------------------------------------------------------------------------*/
int ana_xwd_root(narg,ps)
 /* reads a specified rectangle from the root screen, call is:
 image = xwd_root(ix, iy, nx, ny) */
 int narg, ps[];
 {
 int	ix, iy, nx, ny, result_sym, dim[3], stat;
 unsigned char *pout;
 struct  ahead   *h;
 if (int_arg_stat(ps[0], &ix) != 1) return -1;
 if (int_arg_stat(ps[1], &iy) != 1) return -1;
 if (int_arg_stat(ps[2], &nx) != 1) return -1;
 if (int_arg_stat(ps[3], &ny) != 1) return -1;
 /* for our result we need a (3,nx,ny) byte array */
 dim[1] = nx;	dim[2] = ny;	dim[0] = 3;
 result_sym = array_scratch(0, 3, dim);
 h = (struct ahead *) sym[result_sym].spec.array.ptr;
 pout = (char *) ( (char *) h + sizeof( struct ahead ) );
 stat = xwd_root(ix, iy, nx, ny, pout);
 return result_sym;
 }
 /*------------------------------------------------------------------------*/
int xwd(src)
 Window src;
 {
 Window dummywin;
 int absx, absy, x, y;
 unsigned width, height;
 int dwidth, dheight;
 int bw, depth, nx, ny, class, dim[3], result_sym, m, testflag = 1;
 XWindowAttributes win_info;
 XImage *image;
 Bool	status;
 struct  ahead   *h;
 char    *ptr, *pout;
 /* internal routine to read an X window using code gleamed from xwd,
 converts result into an I*1 rgb array */
 /* use XGetWindowAttributes to get size, this works for Pixmaps also */
 status = XGetWindowAttributes(display, src, &win_info);
 if (status == False) { printf("XWD: XGetWindowAttributes failure\n");
 	return 0; }
 /* use xwd code fragments to clip to screen */
 status = XTranslateCoordinates(display, src, RootWindow(display, screen_num),
	0, 0, &absx, &absy, &dummywin);
 if (status == False) { printf("XWD: XTranslateCoordinates failure\n");
 	return 0; }
 win_info.x = absx;
 win_info.y = absy;
 width = win_info.width;
 height = win_info.height;
 bw = 0;

 /* following puts the borders on */
 absx -= win_info.border_width;
 absy -= win_info.border_width;
 bw = win_info.border_width;
 width += (2 * bw);
 height += (2 * bw);

 dwidth = DisplayWidth (display, screen_num);
 dheight = DisplayHeight (display, screen_num);


 /* the xwd clip to viewable window, note unusual comma operator */
 if (absx < 0) width += absx, absx = 0;
 if (absy < 0) height += absy, absy = 0;
 if (absx + width > dwidth) width = dwidth - absx;
 if (absy + height > dheight) height = dheight - absy;

 /* now back to coords in window */
 x = absx - win_info.x;
 y = absy - win_info.y;

 image = XGetImage (display, src, x, y, width, height, AllPlanes, ZPixmap);
  if (!image) { printf("XWD: XGetImage failure\n");
 	return 0; }
 /* now we have to decode, handle truecolor (16,24,32) and 8 bit pseudo */
 class = win_info.visual->class;
 depth = image->depth;
 nx = image->width;
 ny = image->height;
 printf("depth = %d, nx, ny = %d %d\n", depth, nx, ny);
 printf("  bytes_per_line = %d\n", image->bytes_per_line);
 /* for our result we need a (3,nx,ny) byte array */
 dim[1] = nx;	dim[2] = ny;	dim[0] = 3;
 result_sym = array_scratch(0, 3, dim);
 h = (struct ahead *) sym[result_sym].spec.array.ptr;
 pout = (char *) ( (char *) h + sizeof( struct ahead ) );
 if (class == DirectColor || class == TrueColor) {
  if (depth == 16 || depth == 15) {
  unsigned short	*ptr, *pline;
  int	pix, xq, m, n, nbl;
  /* the 16 bit (or 15) truecolor visual, convert to rgb byte arrays */
  printf("in the 16 bit section\n");
//   rmask = image->red_mask;
//   gmask = image->green_mask;
//   bmask = image->blue_mask;
//   get_shifts16();
  ptr = pline = (unsigned short *) image->data;
  nbl = image->bytes_per_line;
  nbl = nbl/sizeof(unsigned short);
  m = ny;
  while (m--) {
   n = nx;
   ptr = pline;    pline += nbl;
   while (n--) {
   pix = (int) *ptr++;
   xq = (pix & rmask);
   if (rshift > 0) xq = xq >> rshift;  else  xq = xq << (-rshift);
   *pout++ = (byte) xq;
   xq = (pix & gmask);
   if (gshift > 0) xq = xq >> gshift;  else  xq = xq << (-gshift);
   *pout++ = (byte) xq;
   xq = (pix & bmask);
   if (bshift > 0) xq = xq >> bshift;  else  xq = xq << (-bshift);
   *pout++ = (byte) xq;
  } }
 } else if (depth == 24 || depth == 32) {
   printf("true color case\n");
   //if (testflag) { XFree(image);  return result_sym; }

   if (load_to_triplet(image, pout, nx, ny) != 1) {
      printf("xwd error\n"); result_sym = -1;  goto xwd_exit; }
  } else {
  printf("sorry - this depth %d not supported by xwd\n", depth);
 }
 } else if (class == PseudoColor) {
  unsigned char	*ptr, *pline;
  int	ncolors, i, m, n, nbl;
  XColor *colors;
  Visual  *vis;
  printf("in the 8 bit PseudoColor section\n");
  ptr = pline = (unsigned char *) image->data;
  /* use the Pseudo color table to convert to rgb components */
  ncolors = win_info.visual->map_entries;
  printf("ncolors from win_info= %d\n", ncolors);
  vis = win_info.visual;
  printf("vis id = %#x, %d\n", vis, vis);
  printf("col id = %#x, %d\n", win_info.colormap, win_info.colormap);
  ncolors = ReadColors(vis, win_info.colormap, &colors);
  //printf("ncolors = %d\n", ncolors);
  //for (i=0;i<ncolors;i++) printf("%d - %d, %d, %d\n", i, colors[i].red,
  //	 colors[i].green, colors[i].blue);
  if (ncolors <= 0) return -1;
  nbl = image->bytes_per_line;
  m = ny;
  while (m--) {
   n = nx;
   ptr = pline;    pline += nbl;
   while (n--) {
   i = *ptr++;
   *pout++ = (byte) (colors[i].red >> 8);
   *pout++ = (byte) (colors[i].green >> 8);
   *pout++ = (byte) (colors[i].blue >> 8);
  } }
  XFree(colors);
 } else {
   printf("sorry - this visual class %d not supported by xwd\n", class);
 }
 xwd_exit:
 XFree(image->data);
 XFree(image);
 return result_sym;
 }
 /*------------------------------------------------------------------------*/
int ana_get_box_root(narg,ps)
 /* interactively get a box on the screen, loads the passed args
 call is getbox_root, ix, iy, nx, ny */
 int narg, ps[];
 {
 int	iq;
 int	box_decr[4];
 iq = get_box_root(box_decr);
 printf("box: %d %d %d %d\n", box_decr[0],box_decr[1],box_decr[2],box_decr[3]);
 if (narg > 0) {
 if (redef_scalar( ps[0], 2, &box_decr[0]) != 1) return execute_error(13);
 if (narg > 1) {
 if (redef_scalar( ps[1], 2, &box_decr[1]) != 1) return execute_error(13);
 if (narg > 2) {
 if (redef_scalar( ps[2], 2, &box_decr[2]) != 1) return execute_error(13);
 if (narg > 3) {
 if (redef_scalar( ps[3], 2, &box_decr[3]) != 1) return execute_error(13);
 }}}}
 return 1;
 }
 /*------------------------------------------------------------------------*/
