
/*
 * xanim_x11.c
 *
 * Copyright (C) 1990,1991,1992,1993,1994 by Mark Podlipec. 
 * All rights reserved.
 *
 * This software may be freely copied, modified and redistributed
 * without fee provided that this copyright notice is preserved 
 * intact on all copies and modified copies.
 * 
 * There is no warranty or other guarantee of fitness of this software.
 * It is provided solely "as is". The author(s) disclaim(s) all
 * responsibility and liability with respect to this software's usage
 * or its effect upon hardware or computer systems.
 *
 */

#include "xanim.h"
#include <Intrinsic.h>
#include <StringDefs.h>
#include <Shell.h>
#include <sys/signal.h>
#ifndef VMS
#include <sys/times.h>
#endif
#include <ctype.h>
#include "xanim_x11.h"

void XA_Read_Pixel_Value();
 
void xanim_expose();
void xanim_key();
void xanim_button();
void xanim_resize();
void xanim_events();
void X11Setup();
void X11_Show_Visuals();
void X11_OutPut_Visual_Class();
void X11_Init_Image_Struct();
void X11_Get_Shift();
void X11_Pre_Setup();
void X11_Setup_Window();
void X11_Make_Nice_CHDR();
void X11_Get_Colormap();

void XA_Install_CMAP();
void IFF_Buffer_HAM6();
void IFF_Buffer_HAM8();
void UTIL_Mapped_To_Bitmap();
void UTIL_Mapped_To_Mapped();


/*********************************** X11 stuff */
Display       *theDisp;
int	       theScreen;
Visual        *theVisual;
Colormap       theCmap;
Window         mainW;
GC             theGC;
XImage        *theImage;
XColor         defs[256];
/******************************** Xt stuff */
extern XA_CHDR *xa_chdr_now;
extern XA_ANIM_HDR *cur_file;
extern ULONG xa_title_flag;
extern ULONG xa_anim_flags;
extern char xa_title[];
extern ULONG x11_window_x,x11_window_y;
extern ULONG xa_buff_x,xa_buff_y;
extern ULONG xa_allow_resizing;
extern ULONG xa_allow_nice;
extern ULONG xa_speed_scale;

XtAppContext  theContext;

#define ACTIONTABLE_SIZE 4
XtActionsRec actionTable[] = {
        {"Expose", xanim_expose},
        {"Configure", xanim_resize},
        {"KeyUp", xanim_key},
        {"ButtonPress", xanim_button}
};

static struct _resource {
  int anim;
} resource;

#define offset(field)   XtOffset(struct _resource *, field)

XtResource application_resources[] = {
  {"anim", "Anim", XtRBoolean, sizeof (Boolean),
     offset(anim), XtRString, "False" },
};

String   Translation =
"<Expose>:Expose()\n\
<Configure>:Configure()\n\
<ButtonPress>:ButtonPress()\n\
<KeyUp>:KeyUp()";

void X11_Get_Shift(mask,shift,size)
ULONG mask,*shift,*size;
{
  LONG i,j;

  i=0;
  while( (i < 32) && !(mask & 0x01) ) 
  {
    mask >>= 1;
    i++;
  }
  if (i >= 32)
  {
    fprintf(stderr,"X11_Get_Shift: wierd mask value %lx\n",mask);
    i = 0;
  }
  *shift = i;
  j=0;
  while( (i < 32) && (mask & 0x01) ) 
  {
    mask >>= 1;
    i++;
    j++;
  }
  *size = j;
}

ULONG X11_Get_True_Color(r,g,b,bits)
register ULONG r,g,b,bits;
{
  register ULONG temp,temp_color;

  temp = (x11_red_bits >= bits)?(r << (x11_red_bits - bits))
                               :(r >> (bits - x11_red_bits));
  temp_color  = (temp << x11_red_shift) & x11_red_mask;

  temp = (x11_green_bits >= bits)?(g << (x11_green_bits - bits))
                                 :(g >> (bits - x11_green_bits));
  temp_color |= (temp << x11_green_shift) & x11_green_mask;

  temp = (x11_blue_bits >= bits)?(b << (x11_blue_bits - bits))
                                :(b >> (bits - x11_blue_bits));
  temp_color |= (temp << x11_blue_shift) & x11_blue_mask;

  return(temp_color);
}

/****************************************************
 *
 */
void X11_Pre_Setup(argcp, argv,xa_user_visual,xa_user_class)
int *argcp;
char *argv[];
LONG xa_user_visual;
LONG xa_user_class;
{
  LONG i,vis_num,vis_i;
  XVisualInfo *vis;

  vis_i = xa_user_visual;
 
  XtToolkitInitialize();
  theContext = XtCreateApplicationContext();
  XtAppAddActions(theContext, actionTable, ACTIONTABLE_SIZE);

  i = 0;
  theDisp = XtOpenDisplay(theContext, NULL, "xanim", "XAnim",NULL,0,argcp,argv);
  if (theDisp == NULL) 
  {
    TheEnd1("Unable to open display\n"); 
  }

  if (xa_user_class >= 0) /* only attempt to use select visuals */
  {
    XVisualInfo vis_template;
    vis_template.class = xa_user_class;
    vis = XGetVisualInfo (theDisp, VisualClassMask, &vis_template, &vis_num);
    if ((vis == NULL) || (vis_num == 0) )
	TheEnd1("X11: Couldn't get any Visuals of the desired class.\n");
  }
  else  /* look at them all */
  {
    vis = XGetVisualInfo (theDisp, VisualNoMask, NULL, &vis_num);
    if ((vis == NULL) || (vis_num == 0) )
			TheEnd1("X11: Couldn't get any Visuals\n");
  }

  if (vis_i >= vis_num) TheEnd1("X11: Coudn't get request Visual\n");

  if (vis_i < 0)
  {
    LONG max_csize,max_depth,max_class;

    max_class = -1;
    max_depth = 0;
    max_csize = 0;

    /* look through visuals a choose a good one */
    for(i=0;i<vis_num;i++)
    {
      if (vis[i].depth > max_depth)
      {
	max_depth = vis[i].depth;
	max_class = vis[i].class;
	max_csize = vis[i].colormap_size;
	vis_i = i;
      }
      else if (vis[i].depth == max_depth)
      {
	if (vis[i].class > max_class) 
	{
	  if (   (vis[i].class < 4)	/* pseudo or less */
	      || (vis[i].depth > 8) )
	  {
	    max_class = vis[i].class;
	    max_csize = vis[i].colormap_size;
	    vis_i = i;
	  }
	}
	else if (vis[i].class == max_class)
	{
	  if (vis[i].colormap_size > max_csize)
	  {
	    max_csize = vis[i].colormap_size;
	    vis_i = i;
	  } 
	} /* end same class */
      } /* end same depth */
    } /* end of vis loop */
  } /* no valid user visuals */

  /* setup up X11 variables */

  theScreen = vis[vis_i].screen;
  theVisual = vis[vis_i].visual;
  x11_depth = vis[vis_i].depth;
  x11_class = vis[vis_i].class;
  x11_cmap_size   = vis[vis_i].colormap_size;
  /* POD - For testing purposes only */
  if ( (pod_max_colors > 0) && (pod_max_colors < x11_cmap_size) )
		x11_cmap_size = pod_max_colors;
  theGC  = 0; /* DefaultGC(theDisp,theScreen); */

  /* Make sure x11_cmap_size is power of two */
  { 
    ULONG size;
    size = 0x01; x11_disp_bits = 0;
    while(size <= x11_cmap_size) { size <<= 1; x11_disp_bits++; }
    size >>=1; x11_disp_bits--;
    x11_cmap_size = 0x01 << x11_disp_bits;
  }

  x11_bit_order   = BitmapBitOrder(theDisp);
  if (x11_bit_order == MSBFirst) x11_bit_order = X11_MSB;
  else x11_bit_order = X11_LSB;
  x11_bitmap_unit = BitmapUnit(theDisp);
  x11_depth_mask = (0x01 << x11_depth) - 1;
  x11_cmap_type = 0;

  XFree( (void *)vis);  

  if (x11_depth == 1)
  {
    x11_display_type = XA_MONOCHROME;
    x11_bytes_pixel = 1; x11_bitmap_pad = x11_bitmap_unit; 
    x11_cmap_flag = FALSE;
    x11_black = BlackPixel(theDisp,DefaultScreen(theDisp));
    x11_white = WhitePixel(theDisp,DefaultScreen(theDisp));
    x11_bits_per_pixel = 1;
    x11_byte_order = x11_bit_order;
  }
  else 
  {
    if (x11_depth > 16)
        { x11_bytes_pixel = 4; x11_bitmap_pad = 32; }
    else if (x11_depth > 8)
        { x11_bytes_pixel = 2; x11_bitmap_pad = 16; }
    else { x11_bytes_pixel = 1; x11_bitmap_pad = 8; }


    theImage = XCreateImage(theDisp,theVisual,
			x11_depth,ZPixmap,0,0,7,7,
			x11_bitmap_pad,0);
    if (theImage != 0)
    {
      x11_bits_per_pixel = theImage->bits_per_pixel;
      x11_byte_order = theImage->byte_order;
      if (x11_byte_order == MSBFirst) x11_byte_order = X11_MSB;
      else x11_byte_order = X11_LSB;
      if (x11_verbose_flag == TRUE)
      {
	fprintf(stderr,"bpp=%ld   bpl=%ld   byteo=%ld  bito=%ld\n",
		x11_bits_per_pixel,theImage->bytes_per_line,
		x11_byte_order,theImage->bitmap_bit_order);
      }
      XDestroyImage(theImage);
    } else x11_bits_per_pixel = x11_depth;

    switch(x11_class)
    {

      case StaticGray:
	x11_display_type = XA_STATICGRAY;
	x11_cmap_flag = FALSE;
	break;
      case GrayScale:
	x11_display_type = XA_GRAYSCALE;
	x11_cmap_flag = TRUE;
	break;
      case StaticColor:
	x11_display_type = XA_STATICCOLOR;
	x11_cmap_flag = FALSE;
	break;
      case PseudoColor:
	x11_display_type = XA_PSEUDOCOLOR;
	x11_cmap_flag = TRUE;
	break;
      case TrueColor:
	x11_display_type = XA_TRUECOLOR;
	x11_cmap_flag = FALSE;
	break;
      case DirectColor:
	x11_display_type = XA_DIRECTCOLOR;
	x11_cmap_flag = FALSE;
	break;
      default:
	fprintf(stderr,"Unkown x11_class %lx\n",x11_class);
	TheEnd();
    }
  }

  if (x11_display_type & XA_X11_TRUE)
  {
    x11_red_mask = theVisual->red_mask;
    x11_green_mask = theVisual->green_mask;
    x11_blue_mask = theVisual->blue_mask;
    X11_Get_Shift(x11_red_mask  , &x11_red_shift  , &x11_red_bits  );
    X11_Get_Shift(x11_green_mask, &x11_green_shift, &x11_green_bits);
    X11_Get_Shift(x11_blue_mask , &x11_blue_shift , &x11_blue_bits );
  }
  else if ( (x11_depth == 24) && (x11_cmap_size <= 256) ) x11_cmap_type = 1;

  xa_cmap = (ColorReg *) malloc( x11_cmap_size * sizeof(ColorReg) );
  if (xa_cmap==0) fprintf(stderr,"X11 CMAP: couldn't malloc\n");

  if (x11_verbose_flag == TRUE)
  {
    fprintf(stderr,"Selected Visual:  ");
    X11_OutPut_Visual_Class(x11_class);
    fprintf(stderr," (%lx) \n",x11_display_type);
    fprintf(stderr,"  depth= %ld  class= %ld  cmap size=%ld(%ld) bytes_pixel=%ld\n",
        x11_depth, x11_class, x11_cmap_size, x11_disp_bits, x11_bytes_pixel );
    if (x11_display_type & XA_X11_TRUE)
    {
      fprintf(stderr,"  X11 Color Masks =%lx %lx %lx\n",
                  x11_red_mask,x11_green_mask ,x11_blue_mask);
      fprintf(stderr,"  X11 Color Shifts=%ld %ld %ld\n",
                  x11_red_shift, x11_green_shift, x11_blue_shift );
      fprintf(stderr,"  X11 Color Sizes =%ld %ld %ld\n",
                  x11_red_bits,x11_green_bits ,x11_blue_bits);
    }
    else if (x11_display_type == XA_MONOCHROME)
    {
      fprintf(stderr,"  Bit Order = %lx  bitmapunit = %lx bitmappad = %lx\n",
                x11_bit_order,x11_bitmap_unit,BitmapPad(theDisp) );
    }
    fprintf(stderr,"\n");
  }

  if (   (theVisual != DefaultVisual(theDisp,theScreen))
      || (x11_display_type & XA_X11_TRUE) ) xa_allow_nice = FALSE;
  else xa_allow_nice = TRUE;

  /* kludges */
  if (   (!(x11_display_type & XA_X11_TRUE))
      && (x11_depth == 24) && (x11_cmap_size <= 256) ) x11_kludge_1 = TRUE;
  XSync(theDisp,False);
}

/*
 * Setup X11 Display, Window and Toolkit
 */
void X11_Setup_Window(max_imagex,max_imagey,startx,starty)
LONG max_imagex,max_imagey;
LONG startx,starty;
{
  LONG i;
  Widget wg;
  LONG n;
  Arg arglist[20];
  XWMHints xwm_hints;

  if (   (   (theVisual == DefaultVisual(theDisp,theScreen))
          && (cmap_play_nice == TRUE) ) 
      || (x11_display_type == XA_MONOCHROME)
     )
  {
    DEBUG_LEVEL1 fprintf(stderr,"using default cmap\n");
    theCmap = DefaultColormap(theDisp,theScreen);
    x11_cmap_flag = FALSE; /* if nice */
  }
  else
  {
    DEBUG_LEVEL1 fprintf(stderr,"creating new cmap\n");
    if (x11_display_type & XA_X11_STATIC)
    {
       theCmap = XCreateColormap(theDisp,RootWindow(theDisp,theScreen),
							theVisual, AllocNone);
    }
    else if (   (x11_display_type == XA_DIRECTCOLOR)
             && (theVisual != DefaultVisual(theDisp,theScreen))  )
    {     /* Fake Direct Color, usually on top of a PseudoColor */
      ULONG i,r_scale,g_scale,b_scale;
      ULONG rmsk,gmsk,bmsk;

      theCmap = XCreateColormap(theDisp,RootWindow(theDisp,theScreen),
							theVisual, AllocAll);
      r_scale = cmap_scale[x11_red_bits];
      g_scale = cmap_scale[x11_green_bits];
      b_scale = cmap_scale[x11_blue_bits];
      rmsk = (0x01 << x11_red_bits)   - 1;
      gmsk = (0x01 << x11_green_bits) - 1;
      bmsk = (0x01 << x11_blue_bits)  - 1;
      for(i=0; i < x11_cmap_size; i++)
      {
        defs[i].pixel  =  (i << x11_red_shift)   & x11_red_mask;
        defs[i].pixel |=  (i << x11_green_shift) & x11_green_mask;
        defs[i].pixel |=  (i << x11_blue_shift)  & x11_blue_mask;
        defs[i].red   = (i & rmsk) * r_scale;
        defs[i].green = (i & gmsk) * g_scale;
        defs[i].blue  = (i & bmsk) * b_scale;
        defs[i].flags = DoRed | DoGreen | DoBlue;
      }
      XStoreColors(theDisp,theCmap,defs,x11_cmap_size);
    }
    else 
    {
       theCmap = XCreateColormap(theDisp,RootWindow(theDisp,theScreen),
							theVisual, AllocAll);
    }
    if (theCmap == 0) TheEnd1("X11_Setup_Window: create cmap err");
  }

  n = 0;
#ifdef XtNvisual
  XtSetArg(arglist[n], XtNvisual, theVisual); n++;
#endif
  XtSetArg(arglist[n], XtNcolormap, theCmap); n++;
  XtSetArg(arglist[n], XtNdepth, x11_depth); n++;
  XtSetArg(arglist[n], XtNforeground, WhitePixel(theDisp,theScreen)); n++;
  XtSetArg(arglist[n], XtNbackground, BlackPixel(theDisp,theScreen)); n++;
  XtSetArg(arglist[n], XtNborderColor, WhitePixel(theDisp,theScreen)); n++;
  XtSetArg(arglist[n], XtNwidth, startx); n++;
  XtSetArg(arglist[n], XtNheight, starty); n++;
  if (xa_allow_resizing==TRUE)
  {
    XtSetArg(arglist[n], XtNallowShellResize, True); n++;
  }
  else
  {
    XtSetArg(arglist[n], XtNmaxWidth, max_imagex); n++;
    XtSetArg(arglist[n], XtNmaxHeight, max_imagey); n++;
  }
  XtSetArg(arglist[n], XtNtranslations, 
			XtParseTranslationTable(Translation)); n++;
  wg = XtAppCreateShell("xanim", "XAnim", applicationShellWidgetClass, 
                         theDisp, arglist, n);

  XtGetApplicationResources (wg, &resource, application_resources,
                             XtNumber(application_resources), NULL, 0);

  XtRealizeWidget(wg);

  mainW = XtWindow(wg);

  /* Need to Create New GC for Visuals that have a different depth than
   * the default GC
   */
  {
    ULONG gc_mask;
    XGCValues gc_init;
 
    gc_mask = 0;
    gc_init.function = GXcopy;                          gc_mask |= GCFunction;
    gc_init.foreground = WhitePixel(theDisp,theScreen); gc_mask |= GCForeground;
    gc_init.background = BlackPixel(theDisp,theScreen); gc_mask |= GCBackground;
    gc_init.graphics_exposures = False;         gc_mask |= GCGraphicsExposures;
    theGC  = XCreateGC(theDisp,mainW,gc_mask,&gc_init);
  }

  if (x11_display_type == XA_MONOCHROME)
  { ULONG line_size;
    line_size = X11_Get_Line_Size(max_imagex);
    theImage = XCreateImage(theDisp,theVisual,
			x11_depth,XYPixmap,0,0,max_imagex,max_imagey,
			x11_bitmap_pad,line_size);
    if (theImage == 0)
    {
      fprintf(stderr,"X11 Setup: create XY image failed\n");
      TheEnd();
    }
  }
  else
  { ULONG line_size;
    line_size = X11_Get_Line_Size(x11_bytes_pixel * max_imagex);
    if (x11_bits_per_pixel==2) line_size = (line_size + 3) / 4;
    else if (x11_bits_per_pixel==4) line_size = (line_size + 1) / 2;

    theImage = XCreateImage(theDisp,theVisual,
			x11_depth,ZPixmap,0,0,max_imagex,max_imagey,
			x11_bitmap_pad,line_size);
    if (theImage == 0)
    {
      fprintf(stderr,"X11 Setup: create Z image failed\n");
      TheEnd();
    }
  }

  xwm_hints.flags = InputHint;
  XSetWMHints(theDisp,mainW,&xwm_hints);
  XMapWindow(theDisp,mainW);

  if (x11_cmap_flag == FALSE) /* static or monochrome displays */
  {
    ULONG i;
    for(i=0;i<x11_cmap_size;i++)
        { defs[i].pixel = i; defs[i].flags = DoRed | DoGreen | DoBlue; }
    XQueryColors(theDisp,theCmap,defs,x11_cmap_size);
    for(i=0;i<x11_cmap_size;i++)
    {
      ULONG r,g,b;
      r = xa_cmap[i].red   = defs[i].red;
      g = xa_cmap[i].green = defs[i].green;
      b = xa_cmap[i].blue  = defs[i].blue;
      xa_cmap[i].gray = (USHORT)( ( (r * 11) + (g * 16) + (b * 5) ) >> 5 );
    }
  }
  else /* Copy Default Colormap into new one */
  {
    ULONG i,csize;

    csize = CellsOfScreen(DefaultScreenOfDisplay(theDisp));
    if (csize > x11_cmap_size) csize = x11_cmap_size;
    for(i=0; i<csize; i++)
       { defs[i].pixel = i; defs[i].flags = DoRed | DoGreen | DoBlue; }
    XQueryColors(theDisp,DefaultColormap(theDisp,theScreen),defs,csize);
    for(i=0; i<csize; i++)
    {
      ULONG r,g,b;
      r = xa_cmap[i].red   = defs[i].red;
      g = xa_cmap[i].green = defs[i].green;
      b = xa_cmap[i].blue  = defs[i].blue;
      xa_cmap[i].gray = (USHORT)( ( (r * 11) + (g * 16) + (b * 5) ) >> 5 );
      if (x11_display_type & XA_X11_GRAY)
      {
        defs[i].red   = xa_cmap[i].gray;
        defs[i].green = xa_cmap[i].gray;
        defs[i].blue  = xa_cmap[i].gray;
      }
      defs[i].pixel = i; /* probably redundant */
      defs[i].flags = DoRed | DoGreen | DoBlue;
    }
    XStoreColors(theDisp,theCmap,defs,csize);
  }
  XSetWindowColormap(theDisp, mainW, theCmap);
#ifndef NO_INSTALL_CMAP
  XInstallColormap(theDisp,theCmap);
#endif
}

void xanim_resize(wg, event, str, np)
        Widget          wg;
        XConfigureEvent   *event;
        String         *str;
        int            *np;
{
  if (event->window == mainW)
  {
    x11_window_x = event->width;
    x11_window_y = event->height;
    DEBUG_LEVEL1 
	fprintf(stderr,"X11 RESIZE %ldx%ld\n",x11_window_x,x11_window_y);
  }
}

void xanim_expose(wg, event, str, np)
        Widget          wg;
        XExposeEvent   *event;
        String         *str;
        int            *np;
{
 if (xa_anim_status == XA_UNSTARTED) 
 {
  xa_anim_status = XA_RUN_NEXT;
  xa_anim_holdoff = TRUE;
  XtAppAddTimeOut(theContext, 1, ShowAction, XA_SHOW_NORM);
 }
}

void xanim_button(wg, event, str, np)
Widget		wg;
XButtonEvent	*event;
String		*str;
int		*np;
{
 switch (event->button)
 {
  case Button1:
	if (xa_anim_status & XA_STOP_MASK) /* if stopped */
	{
	  xa_anim_status = XA_STEP_PREV;
	  if (xa_anim_holdoff == TRUE) return;
	  xa_anim_holdoff = TRUE;
	  XtAppAddTimeOut(theContext, 1, ShowAction, XA_SHOW_NORM);
	}
	else xa_anim_status = XA_STOP_PREV;
	break;
  case Button2:
	switch(xa_anim_status)
	{
	  case XA_RUN_PREV:  /* if running, then stop */ 
	  case XA_RUN_NEXT:   
		xa_anim_status &= XA_CLEAR_MASK;
		xa_anim_status |= XA_STOP_MASK; 
		xa_anim_flags &= ~(ANIM_CYCLE);
		break;
	  case XA_STOP_PREV: /* if stopped, then run */
	  case XA_STOP_NEXT:  
		xa_anim_status &= XA_CLEAR_MASK;
		xa_anim_status |= XA_RUN_MASK; 
		if (xa_anim_holdoff == TRUE) return;
		xa_anim_holdoff = TRUE;
		XtAppAddTimeOut(theContext, 1, ShowAction, XA_SHOW_NORM);
		break;
	  case XA_STEP_PREV: /* if single stepping then run */  
	  case XA_STEP_NEXT:  
	  case XA_ISTP_PREV:  
	  case XA_ISTP_NEXT:  
	  case XA_FILE_PREV:  
	  case XA_FILE_NEXT:  
		xa_anim_status &= XA_CLEAR_MASK;
		xa_anim_status |= XA_RUN_MASK; 
		break;
	  default:
		xa_anim_status = XA_STOP_NEXT; 
		break;
	}
        if (xa_title_flag == XA_TITLE_FILE)
        {
          if (xa_anim_status & XA_RUN_MASK)
          {
	    sprintf(xa_title,"XAnim: %s",cur_file->name);
            XStoreName(theDisp,mainW,xa_title);
          }
        }
	break;
  case Button3:
	if (xa_anim_status & XA_STOP_MASK) /* if stopped */
	{
	  xa_anim_status = XA_STEP_NEXT;
	  if (xa_anim_holdoff == TRUE) return;
	  xa_anim_holdoff = TRUE;
	  XtAppAddTimeOut(theContext, 1, ShowAction, XA_SHOW_NORM);
	}
	else xa_anim_status = XA_STOP_NEXT;
	break;
  } /* end of switch */
}


void xanim_key(wg, event, str, np)
Widget		wg;
XKeyEvent	*event;
String		*str;
int		*np;
{
  char            buff[16];
  KeySym          ks;
  XComposeStatus  st;
  ULONG		  length;
  length = XLookupString(event, buff, 16, &ks, &st);
  if (length != 1) return;
  switch(buff[0])
  {
    case '2':
	XA_Read_Pixel_Value();
	break;
    case 'q':
    case 'Q':
	TheEnd();
	break;
    case 'w':
	if ( (xa_buff_x != 0) && (xa_buff_y != 0) )
		XResizeWindow(theDisp,mainW,xa_buff_x,xa_buff_y);
	break;
    case 'F':
  	XInstallColormap(theDisp,theCmap);
	break;
    case 'g':
	xa_anim_flags &= ~(ANIM_CYCLE);
	break;
    case 'r':
	if (xa_chdr_now != 0) XA_Install_CMAP(xa_chdr_now);
	break;
    case '-': /* decrease speed scale, but not to zero */
	xa_speed_scale /= 2; if (xa_speed_scale == 0) xa_speed_scale = 1;
	break;
    case '=': /* increase speed scale, but not more than 1000 */
	xa_speed_scale *= 2;
	if (xa_speed_scale >= (6400 * 1024) ) xa_speed_scale = (6400 * 1024);
	break;
    case '0': /* set to unity */
	xa_speed_scale = 0x01 << 16;
	break;
    case '.': 
	if (xa_anim_status & XA_STOP_MASK) /* if stopped */
	{
	  xa_anim_status = XA_STEP_NEXT;
	  if (xa_anim_holdoff == TRUE) return;
	  xa_anim_holdoff = TRUE;
	  XtAppAddTimeOut(theContext, 1, ShowAction, XA_SHOW_NORM);
	}
	else xa_anim_status = XA_STOP_NEXT;
	break;
    case ',': 
	if (xa_anim_status & XA_STOP_MASK) /* if stopped */
	{
	  xa_anim_status = XA_STEP_PREV;
	  if (xa_anim_holdoff == TRUE) return;
	  xa_anim_holdoff = TRUE;
	  XtAppAddTimeOut(theContext, 1, ShowAction, XA_SHOW_NORM);
	}
	else xa_anim_status = XA_STOP_PREV;
	break;
    case '>':  /* single step across anims */
	if (xa_anim_status & XA_STOP_MASK) /* if stopped */
	{
	  xa_anim_status = XA_FILE_NEXT;
	  if (xa_anim_holdoff == TRUE) return;
	  xa_anim_holdoff = TRUE;
	  XtAppAddTimeOut(theContext, 1, ShowAction, XA_SHOW_NORM);
	}
	else xa_anim_status = XA_FILE_NEXT;
	break;
    case '<':  /* single step across anims */
	if (xa_anim_status & XA_STOP_MASK) /* if stopped */
	{
	  xa_anim_status = XA_FILE_PREV;
	  if (xa_anim_holdoff == TRUE) return;
	  xa_anim_holdoff = TRUE;
	  XtAppAddTimeOut(theContext, 1, ShowAction, XA_SHOW_NORM);
	}
	else xa_anim_status = XA_FILE_PREV;
	break;
    case '/':  /* single step within anim */
	if (xa_anim_status & XA_STOP_MASK) /* if stopped */
	{
	  xa_anim_status = XA_ISTP_NEXT;
	  if (xa_anim_holdoff == TRUE) return;
	  xa_anim_holdoff = TRUE;
	  XtAppAddTimeOut(theContext, 1, ShowAction, XA_SHOW_NORM);
	}
	else xa_anim_status = XA_STOP_NEXT;
	break;
    case 'm':  /* single step within anim */
	if (xa_anim_status & XA_STOP_MASK) /* if stopped */
	{
	  xa_anim_status = XA_ISTP_PREV;
	  if (xa_anim_holdoff == TRUE) return;
	  xa_anim_holdoff = TRUE;
	  XtAppAddTimeOut(theContext, 1, ShowAction, XA_SHOW_NORM);
	}
	else xa_anim_status = XA_STOP_PREV;
	break;
    case ' ': 
	switch(xa_anim_status)
	{
	  case XA_RUN_PREV:  /* if running, then stop */ 
	  case XA_RUN_NEXT:   
		xa_anim_status &= XA_CLEAR_MASK;
		xa_anim_status |= XA_STOP_MASK; 
		xa_anim_flags &= ~(ANIM_CYCLE);
		break;
	  case XA_STOP_PREV: /* if stopped, then run */
	  case XA_STOP_NEXT:  
		xa_anim_status &= XA_CLEAR_MASK;
		xa_anim_status |= XA_RUN_MASK; 
		if (xa_anim_holdoff == TRUE) return;
		xa_anim_holdoff = TRUE;
		XtAppAddTimeOut(theContext, 1, ShowAction, XA_SHOW_NORM);
		break;
	  case XA_STEP_PREV: /* if single stepping then run */  
	  case XA_STEP_NEXT:  
	  case XA_ISTP_PREV:  
	  case XA_ISTP_NEXT:  
	  case XA_FILE_PREV:  
	  case XA_FILE_NEXT:  
		xa_anim_status &= XA_CLEAR_MASK;
		xa_anim_status |= XA_RUN_MASK; 
		break;
	  default:
		xa_anim_status = XA_STOP_NEXT; 
		break;
	}
        if (xa_title_flag == XA_TITLE_FILE)
        {
          if (xa_anim_status & XA_RUN_MASK)
          {
	    sprintf(xa_title,"XAnim: %s",cur_file->name);
            XStoreName(theDisp,mainW,xa_title);
          }
        }
    break;
  }
}

void xanim_events()
{
 XtAppMainLoop(theContext);
}

/* PODNOTE:
 * macro this 
 */
ULONG X11_Get_Line_Size(xsize)
ULONG xsize;
{
  ULONG line_size;

  if (x11_display_type == XA_MONOCHROME)
       line_size = X11_Get_Bitmap_Width(xsize) / 8;
  else line_size = xsize * x11_bytes_pixel;
  return(line_size);
}


  /*
   * What's this!? Direct access to X11 structures. tsch tsch.
   */
void X11_Init_Image_Struct(image,xsize,ysize)
XImage *image;
ULONG xsize,ysize;
{
  ULONG line_size;
  line_size = X11_Get_Line_Size(xsize);
  /*PACK*/
  if (x11_bits_per_pixel==2) line_size = (line_size + 3) / 4;
  else if (x11_bits_per_pixel==4) line_size = (line_size + 1) / 2;
  image->width = xsize;
  image->height = ysize;
  image->bytes_per_line = line_size;
}

void X11_OutPut_Visual_Class(vis_class)
ULONG vis_class;
{
  switch(vis_class)
  {
   case StaticGray:  fprintf(stderr,"StaticGray"); break;
   case GrayScale:   fprintf(stderr,"GrayScale"); break;
   case StaticColor: fprintf(stderr,"StaticColor"); break;
   case PseudoColor: fprintf(stderr,"PseudoColor"); break;
   case TrueColor:   fprintf(stderr,"TrueColor"); break;
   case DirectColor: fprintf(stderr,"DirectColor"); break;
  }
}

void X11_Show_Visuals()
{
  LONG i,vis_num;
  XVisualInfo *vis;

  vis = XGetVisualInfo (theDisp, VisualNoMask, NULL, &vis_num);
  if ((vis == NULL) || (vis_num == 0) )
  {
    fprintf(stderr,"X11: Couldn't get any Visuals\n");
    return;
  }
  else
  {
    for(i=0;i<vis_num;i++)
    {
      fprintf(stderr,"  visual %ld) depth= %ld  class= %ld  cmap size=%ld  ",
                       i, vis[i].depth, vis[i].class, vis[i].colormap_size );
      X11_OutPut_Visual_Class(vis[i].class);
      fprintf(stderr,"\n");
    }
  }
}

void X11_Get_Colormap(chdr)
XA_CHDR *chdr;
{
  ColorReg *cmap;
  ULONG i,*map;

  /* grab the current cmap and lay it down */
  for(i=0;i<x11_cmap_size;i++)
  {
    if (x11_display_type & XA_X11_TRUE)
    {
      ULONG d;
      d  =  (i << x11_red_shift)   & x11_red_mask;
      d |=  (i << x11_green_shift) & x11_green_mask;
      d |=  (i << x11_blue_shift)  & x11_blue_mask;
      defs[i].pixel =  d;
    }
    else defs[i].pixel = i;
    defs[i].flags = DoRed | DoGreen | DoBlue;
  }
  XQueryColors(theDisp,theCmap,defs,x11_cmap_size);
  
  cmap = chdr->cmap;
  map = chdr->map;
  if (cmap == 0) TheEnd1("X11_Get_Colormap: cmap = 0");
  if (map == 0) TheEnd1("X11_Get_Colormap: map = 0");
DEBUG_LEVEL2 fprintf(stderr,"X11_Get_Colormap:\n");
  for(i=0;i<x11_cmap_size;i++)
  {
    ULONG r,g,b;
    r = cmap[i].red   = (USHORT)defs[i].red; 
    g = cmap[i].green = (USHORT)defs[i].green; 
    b = cmap[i].blue  = (USHORT)defs[i].blue; 
    cmap[i].gray =  (USHORT)( ((r * 11) + (g * 16) + (b * 5)) >> 5 ); 
    map[i] = i;
    DEBUG_LEVEL2 fprintf(stderr,"   %ld) <%lx %lx %lx> %lx\n",i,r,g,b,chdr->cmap[i].gray);
  }
}

void X11_Make_Nice_CHDR(chdr)
XA_CHDR *chdr;
{
  ColorReg *old_cmap,*new_cmap;
  ULONG i,*old_map,*new_map;
  ULONG old_csize,old_msize;

  if ( !(x11_display_type & XA_X11_CMAP)) return;
  
  old_cmap = chdr->cmap;
  old_map  = chdr->map;
  old_csize = chdr->csize;
  old_msize = chdr->msize;

  /* try allocating colors */
  for(i=0;i<old_csize;i++)
  {
    if (x11_display_type & XA_X11_GRAY)
    {
      defs[i].red = defs[i].green = defs[i].blue = old_cmap[i].gray;
    }
    else
    {
      defs[i].red   = old_cmap[i].red;
      defs[i].green = old_cmap[i].green;
      defs[i].blue  = old_cmap[i].blue;
    }
    defs[i].flags = DoRed | DoGreen | DoBlue;
    XAllocColor(theDisp,theCmap,&defs[i]);
  }
  
  /* Query the cmap */
  for(i=0;i<x11_cmap_size;i++)
  {
    if (x11_display_type & XA_X11_TRUE)
    {
      ULONG d;
      d  =  (i << x11_red_shift)   & x11_red_mask;
      d |=  (i << x11_green_shift) & x11_green_mask;
      d |=  (i << x11_blue_shift)  & x11_blue_mask;
      defs[i].pixel =  d;
    }
    else defs[i].pixel = i;
    defs[i].flags = DoRed | DoGreen | DoBlue;
  }
  XQueryColors(theDisp,theCmap, defs,x11_cmap_size);

  if (old_csize != x11_cmap_size)
  {
    new_cmap = (ColorReg *)malloc(x11_cmap_size * sizeof(ColorReg) );
    if (new_cmap == 0) TheEnd1("X11_Make_Nice_CHDR: cmap malloc err");
    FREE(old_cmap,0x400); old_cmap=0;
    chdr->csize = x11_cmap_size;
    chdr->cmap = new_cmap;
  }

  if (old_msize != x11_cmap_size)
  {
    new_map = (ULONG *)malloc(x11_cmap_size * sizeof(ULONG) );
    if (new_map == 0) TheEnd1("X11_Make_Nice_CHDR: map malloc err");
    FREE(old_map,0x401); old_cmap=0;
    chdr->msize = x11_cmap_size;
    chdr->map = new_map;
  }
  
  DEBUG_LEVEL2 fprintf(stderr,"X11_Make_Nice_CHDR: \n");
  chdr->moff = chdr->coff = 0;
  for(i=0;i<x11_cmap_size;i++)
  {
    ULONG r,g,b;
    r = chdr->cmap[i].red   = defs[i].red; 
    g = chdr->cmap[i].green = defs[i].green; 
    b = chdr->cmap[i].blue  = defs[i].blue; 
    chdr->cmap[i].gray = (USHORT)( ( (r * 11) + (g * 16) + (b * 5) ) >> 5 );
    chdr->map[i] = i;
    DEBUG_LEVEL2 fprintf(stderr," %ld) <%lx %lx %lx> %lx\n",i,r,g,b,chdr->cmap[i].gray);
  }
}

