/* file xport2.c */
#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 <stdio.h>
#include <math.h>
#include "ana_structures.h"
#include "defs.h"
 /* following is icon bitmap */
#include "ana_bitmap.h"

#define MAXWINDOW       50
#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(), xwd();
 extern	Window Select_Window();
 /* define some fixed colors for the 8 bit image representations, make sure
 there are FIXED_COLORS of these */
 extern	int	white_pixel,red_pixel,green_pixel,blue_pixel,yellow_pixel;
 extern	int	black_pixel, darkgreen_pixel, purple_pixel;
 static char *fixed_color_names[] = {"white","red","green","blue","yellow",
 		"black","darkgreen", "purple"};
 union   types_ptr { byte *b; short *w; int *l; float *f; double *d;};
 static char    *display_name = NULL;
 static Display *display;
 Atom	wm_delete;
 static XVisualInfo     visual_info;
 static XVisualInfo     *visualList;
 static XSetWindowAttributes    attributes;
 static Screen  *screen;
 static XColor *colors;
 static int    screen_num, colormin, colormax, ncolorcells;
 static int    maxwin = MAXWINDOW, maxmap = MAXMAPS;
 static int    connect_flag = 0, last_wid = 0, depth, color_cells_to_try=128;
 static int	invert_flag=0;	/* used by drawlines */
 static unsigned int     display_width, display_height, display_cells;
 static double last_time;
 static int    xcoord, ycoord, ana_button, ana_keycode, ana_keysym, root_x, root_y;
 static int	ana_keystate;
 static int	tvplanezoom = 1;
 static unsigned int    kb;
 static float	xhair, yhair;
 static Window win[MAXWINDOW];	/* these are the window ID's, int's */
 static Window	selected_window;
 static GC     gc[MAXWINDOW], gcnot[MAXWINDOW];
 static GC	gcmap[MAXMAPS], gcmapnot[MAXMAPS], gcmaperase[MAXMAPS];
 /* the size of each of the windows and pixmaps for our use */
 static 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 */
 static int	drawingareas[MAXWINDOW];
 static int	xerrors;
 static XFontStruct     *font_info[MAXWINDOW];
 /* lookup table pointers for the windows, used for true color visuals */
 static int	*window_lookups[MAXWINDOW];
 static Visual  *vis;
 static XImage  *xi, *zimage;
 static Pixmap  icon_pixmap, maps[MAXMAPS], back_pixmap;
 static Colormap        colormap, def_colormap;
 static XColor  cells[256];
 static XColor  colorcell, rgb_def;	/* some scratch colorcells */
 static unsigned  long  pixels[256];    
 /* these can be volitle if there are several visuals */
 static int rmask, gmask, bmask, rshift, gshift, bshift;
 /* some of these are user accessible variables */
 static int	visual_class;		/* 0 - 5 for X visual class */
 static int	visual_depth;
 /* 1/19/2000 - flags to track window mods */
 static int	window_mod_flag[MAXWINDOW];	/* to track window mods */
 static unsigned short *look16to16 = NULL;	/* used in tvmix16win to keep a table
 				once we've made it */
 static unsigned short *blend_imc = NULL;	/* for a combined image */
 static int	blend_nx, blend_ny;		/* for checks */
 static int	blend_w1 = -1, blend_w2 = -1, blend_w3 = -1;
 static int	blend_feedback;
 
 static short	*lookup16truecolor = 0;
 static unsigned int	*lookup24truecolor = 0;
 static int	xold, yold, true_color24=0, true_color16=0;
 static float	tvix, tviy, tvixb, tviyb;
 static unsigned  long  background_color, foreground_color;
 static int ck_window(int wid);
 static int ck_events();
 static int set_defw(int wid);
 static int ana_xcreat(int wid, unsigned int height, unsigned int width, int xpos, int ypos, int pflag);
 static void get_shifts16();
 static int setforegroundcolor(int wid);
 /*-------------------------------------------------------------------------*/
static 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;
 }
 /*-------------------------------------------------------------------------*/
static 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);
 colormap = XCreateColormap(display, RootWindow(display,screen_num),
        vis, AllocNone);
 /* 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;
 }
 /*-------------------------------------------------------------------------*/
static 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);
 
 /* 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;
 }
 /*-------------------------------------------------------------------------*/
static int setup_x()		/* one time connect and default color table setup */
 {
 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);
 printf(" default depth, planes = %d %d\n", default_depth,default_planes);
 } /* 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
  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_xtvlct2(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) {
 /* the 24 bit TrueColor case */
 cmax = 256 - FIXED_COLORS;
 sfac = (float) n / (float) cmax;
 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);
 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_xtvlctraw2(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_xopen2(narg,ps)  /* explicitly sets the display name for x setup */
 /* for a second display */
 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_xexist2(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_xport2(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);
 
 }
 /*--------------------------------------------------------------------------*/
static int ck_window(wid)	/* checks if a window value is in allowed range */
 int     wid;
 {
 int     mapid;
 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;
 }
 /*-------------------------------------------------------------------------*/
static 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;
 }
 /*-------------------------------------------------------------------------*/
static 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;
 }
 /*-------------------------------------------------------------------------*/
static 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;
 char    *display_name = NULL;
 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\n");
 
 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);
    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);
    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_xsetbackground2(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_xsetforeground2(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);
 }
 /*-------------------------------------------------------------------------*/
static 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;
 }
 /*-------------------------------------------------------------------------*/
static 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_xdelete2(narg,ps)		/* delete a window or a pixmap */
 int  narg, ps[];
 {
 int    wid;
 if (int_arg_stat(ps[0], &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_xraise2(narg,ps)			/* raise (popup) a window */
 int  narg, ps[];
 {
 int    wid;
 if (int_arg_stat(ps[0], &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_xlower2(narg,ps)			/* lower a window */
 int  narg, ps[];
 {
 int    wid;
 if (int_arg_stat(ps[0], &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_xerase2(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_xtv2(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;
 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 */
 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 */
 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;
 }
 /*------------------------------------------------------------------------*/
static void get_shifts16()
 {
 /* sets up shifts, assumes masks already in rmask, gmask, and bmask
 the masks may come from several sources */
 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;
 }
 /*------------------------------------------------------------------------*/
int ana_xtvplane2(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.
 */
 {
 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;
 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) ip = int_arg( ps[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 = wd[wid];		hq = 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;
 }
 //printf("nx, 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);
  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 */
  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 incase we have 24 bit pixels, otherwise need to pad
 lines, some concern that this may not be honored in all cases */
 /* 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;
 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++];
 }
 xi->data = (char *) psave;
 XPutImage(display, win[wid], gc[wid], xi, ixs, iys, ixw, iyw, nx, ny);
 /* destroyImage will zap p24 */
 XDestroyImage(xi);
 } 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_xcopy2(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;
 }
 /*------------------------------------------------------------------------*/
