From http://www.jwz.org/xscreensaver/xscreensaver-5.30.tar.gz
[xscreensaver] / hacks / xlyap.c
index 350888d0c379a45f6e3fab3acb65c6bb7070f247..2d36cb9dde02a4b0fde963cc452c4e0648694660 100644 (file)
  * non-negative exponent are colored differently.
  *
  * The algorithm was taken from the September 1991 Scientific American article
- * by A. K. Dewdney who gives credit to Mario Markus of the Max Planck Institute
- * for its creation. Additional information and ideas were gleaned from the
- * discussion on alt.fractals involving Stephen Hall, Ed Kubaitis, Dave Platt
- * and Baback Moghaddam. Assistance with colormaps and spinning color wheels
- * and X was gleaned from Hiram Clawson. Rubber banding code was adapted from
- * an existing Mandelbrot program written by Stacey Campbell.
+ * by A. K. Dewdney who gives credit to Mario Markus of the Max Planck
+ * Institute for its creation. Additional information and ideas were gleaned
+ * from the discussion on alt.fractals involving Stephen Hall, Ed Kubaitis,
+ * Dave Platt and Baback Moghaddam. Assistance with colormaps and spinning
+ * color wheels and X was gleaned from Hiram Clawson. Rubber banding code was
+ * adapted from an existing Mandelbrot program written by Stacey Campbell.
  */
 
 #define LYAP_PATCHLEVEL 4
 #include "screenhack.h"
 #include "yarandom.h"
 #include "hsv.h"
-#include "vroot.h"
-
-#include <X11/cursorfont.h> 
-#include <X11/Xutil.h> 
-
-char *progclass = "XLyap";
-
-char *defaults [] = {
-  "XLyap.background:   black",         /* to placate SGI */
-  "*randomize:         false",
-  "*builtin:           -1",
-  "*minColor:          1",
-  "*maxColor:          256",
-  "*dwell:             50",
-  "*useLog:            false",
-  "*colorExponent:     1.0",
-  "*colorOffset:       0",
-  "*randomForce:       ",              /* 0.5 */
-  "*settle:            50",
-  "*minA:              2.0",
-  "*minB:              2.0",
-  "*wheels:            7",
-  "*function:          10101010",
-  "*forcingFunction:   abbabaab",
-  "*bRange:            ",              /* 2.0 */
-  "*startX:            0.65",
-  "*mapIndex:          ",              /* 0 */
-  "*outputFile:                ",
-  "*beNegative:                false",
-  "*rgbMax:            65000",
-  "*spinLength:                256",
-  "*show:              false",
-  "*aRange:            ",              /* 2.0 */
+
+#undef countof
+#define countof(x) (sizeof((x))/sizeof((*x)))
+
+#ifndef HAVE_COCOA
+# include <X11/cursorfont.h> 
+#endif
+
+static const char *xlyap_defaults [] = {
+  ".background:         black",
+  ".foreground:         white",
+  "*fpsSolid:          true",
+  "*randomize:          true",
+  "*builtin:            -1",
+  "*minColor:           1",
+  "*maxColor:           256",
+  "*dwell:              50",
+  "*useLog:             false",
+  "*colorExponent:      1.0",
+  "*colorOffset:        0",
+  "*randomForce:        ",              /* 0.5 */
+  "*settle:             50",
+  "*minA:               2.0",
+  "*minB:               2.0",
+  "*wheels:             7",
+  "*function:           10101010",
+  "*forcingFunction:    abbabaab",
+  "*bRange:             ",              /* 2.0 */
+  "*startX:             0.65",
+  "*mapIndex:           ",              /* 0 */
+  "*outputFile:         ",
+  "*beNegative:         false",
+  "*rgbMax:             65000",
+  "*spinLength:         256",
+  "*show:               false",
+  "*aRange:             ",              /* 2.0 */
+  "*delay:              10000",
+  "*linger:             5",
+  "*colors:             200",
+#ifdef USE_IPHONE
+  "*ignoreRotation:     True",
+#endif
   0
 };
 
-XrmOptionDescRec options [] = {
-  { "-randomize", ".randomize",        XrmoptionNoArg, "true" },
-  { "-builtin",   ".builtin",  XrmoptionSepArg, 0 },
-  { "-C", ".minColor",         XrmoptionSepArg, 0 },   /* n */
-  { "-D", ".dwell",            XrmoptionSepArg, 0 },   /* n */
-  { "-L", ".useLog",           XrmoptionNoArg, "true" },
-  { "-M", ".colorExponent",    XrmoptionSepArg, 0 },   /* r */
-  { "-O", ".colorOffset",      XrmoptionSepArg, 0 },   /* n */
-  { "-R", ".randomForce",      XrmoptionSepArg, 0 },   /* p */
-  { "-S", ".settle",           XrmoptionSepArg, 0 },   /* n */
-  { "-a", ".minA",             XrmoptionSepArg, 0 },   /* r */
-  { "-b", ".minB",             XrmoptionSepArg, 0 },   /* n */
-  { "-c", ".wheels",           XrmoptionSepArg, 0 },   /* n */
-  { "-F", ".function",         XrmoptionSepArg, 0 },   /* 10101010 */
-  { "-f", ".forcingFunction",  XrmoptionSepArg, 0 },   /* abbabaab */
-  { "-h", ".bRange",           XrmoptionSepArg, 0 },   /* r */
-  { "-i", ".startX",           XrmoptionSepArg, 0 },   /* r */
-  { "-m", ".mapIndex",         XrmoptionSepArg, 0 },   /* n */
-  { "-o", ".outputFile",       XrmoptionSepArg, 0 },   /* filename */
-  { "-p", ".beNegative",       XrmoptionNoArg, "true" },
-  { "-r", ".rgbMax",           XrmoptionSepArg, 0 },   /* n */
-  { "-s", ".spinLength",       XrmoptionSepArg, 0 },   /* n */
-  { "-v", ".show",             XrmoptionNoArg, "true" },
-  { "-w", ".aRange",           XrmoptionSepArg, 0 },   /* r */
+static XrmOptionDescRec xlyap_options [] = {
+  { "-randomize", ".randomize", XrmoptionNoArg, "true" },
+  { "-builtin",   ".builtin",   XrmoptionSepArg, 0 },
+  { "-C", ".minColor",          XrmoptionSepArg, 0 },   /* n */
+  { "-D", ".dwell",             XrmoptionSepArg, 0 },   /* n */
+  { "-L", ".useLog",            XrmoptionNoArg, "true" },
+  { "-M", ".colorExponent",     XrmoptionSepArg, 0 },   /* r */
+  { "-O", ".colorOffset",       XrmoptionSepArg, 0 },   /* n */
+  { "-R", ".randomForce",       XrmoptionSepArg, 0 },   /* p */
+  { "-S", ".settle",            XrmoptionSepArg, 0 },   /* n */
+  { "-a", ".minA",              XrmoptionSepArg, 0 },   /* r */
+  { "-b", ".minB",              XrmoptionSepArg, 0 },   /* n */
+  { "-c", ".wheels",            XrmoptionSepArg, 0 },   /* n */
+  { "-F", ".function",          XrmoptionSepArg, 0 },   /* 10101010 */
+  { "-f", ".forcingFunction",   XrmoptionSepArg, 0 },   /* abbabaab */
+  { "-h", ".bRange",            XrmoptionSepArg, 0 },   /* r */
+  { "-i", ".startX",            XrmoptionSepArg, 0 },   /* r */
+  { "-m", ".mapIndex",          XrmoptionSepArg, 0 },   /* n */
+  { "-o", ".outputFile",        XrmoptionSepArg, 0 },   /* filename */
+  { "-p", ".beNegative",        XrmoptionNoArg, "true" },
+  { "-r", ".rgbMax",            XrmoptionSepArg, 0 },   /* n */
+  { "-s", ".spinLength",        XrmoptionSepArg, 0 },   /* n */
+  { "-v", ".show",              XrmoptionNoArg, "true" },
+  { "-w", ".aRange",            XrmoptionSepArg, 0 },   /* r */
+  { "-delay", ".delay",         XrmoptionSepArg, 0 },   /* delay */
+  { "-linger", ".linger",       XrmoptionSepArg, 0 },   /* linger */
   { 0, 0, 0, 0 }
 };
 
 
-#define ABS(a) (((a)<0) ? (0-(a)) : (a) )
+#define ABS(a)  (((a)<0) ? (0-(a)) : (a) )
 #define Min(x,y) ((x < y)?x:y)
 #define Max(x,y) ((x > y)?x:y)
 
 #ifdef SIXTEEN_COLORS
-#define MAXPOINTS  128
-#define MAXFRAMES 4
-#define MAXCOLOR 16
-static int maxcolor=16, startcolor=0, color_offset=0, mincolindex=1;
-static int dwell=50, settle=25;
-static int width=128, height=128, xposition=128, yposition=128;
-#else
-#define MAXPOINTS  256
-#define MAXFRAMES 8
-#define MAXCOLOR 256
-static int maxcolor=256, startcolor=17, color_offset=96, mincolindex=33;
-static int dwell=100, settle=50;
-static int width=256, height=256;
-#endif
+# define MAXPOINTS  128
+# ifdef BIGMEM
+#  define MAXFRAMES 4
+# else  /* !BIGMEM */
+#  define MAXFRAMES 2
+# endif /* !BIGMEM */
+# define MAXCOLOR 16
+#else  /* !SIXTEEN_COLORS */
+# define MAXPOINTS  256
+# ifdef BIGMEM
+#  define MAXFRAMES 8
+# else  /* !BIGMEM */
+#  define MAXFRAMES 2
+# endif /* !BIGMEM */
+# define MAXCOLOR 256
+#endif /* !SIXTEEN_COLORS */
 
-#ifndef TRUE
-#define TRUE 1
-#define FALSE 0
-#endif
 
-static int screen;
-static Display*        dpy;
-static Visual *visual;
+#define MAXINDEX 64
+#define FUNCMAXINDEX 16
+#define MAXWHEELS 7
+#define NUMMAPS 5
+#define NBUILTINS 22
 
-static unsigned long foreground, background;
+#ifndef TRUE
+# define TRUE 1
+# define FALSE 0
+#endif
 
-static Window canvas;
 
 typedef struct {
-       int x, y;
+  int x, y;
 } xy_t;
 
+#if 0
 typedef struct {
-       int start_x, start_y;
-       int last_x, last_y;
-       } rubber_band_data_t;
+  int start_x, start_y;
+  int last_x, last_y;
+} rubber_band_data_t;
+#endif
 
 typedef struct {
-       Cursor band_cursor;
-       double p_min, p_max, q_min, q_max;
-       rubber_band_data_t rubber_band;
-       } image_data_t;
+# ifndef HAVE_COCOA
+  Cursor band_cursor;
+# endif
+  double p_min, p_max, q_min, q_max;
+/*  rubber_band_data_t rubber_band;*/
+} image_data_t;
 
 typedef struct points_t {
-       XPoint data[MAXCOLOR][MAXPOINTS];
-       int npoints[MAXCOLOR];
-       } points_t;
+  XPoint data[MAXCOLOR][MAXPOINTS];
+  int npoints[MAXCOLOR];
+} points_t;
 
-static points_t Points;
-static image_data_t rubber_data;
 
-#ifndef TRUE
-#define TRUE 1
-#define FALSE 0
+typedef double (*PFD)(double,double);
+
+/* #### What was this for?  Everything was drawn twice, to the window and 
+   to this, and this was never displayed! */
+/*#define BACKING_PIXMAP*/
+
+struct state {
+  Display *dpy;
+  Screen *screen;
+  Visual *visual;
+  Colormap cmap;
+
+  unsigned long foreground, background;
+
+  Window canvas;
+  int delay, linger;
+
+  unsigned int maxcolor, startcolor, mincolindex;
+  int color_offset;
+  int dwell, settle;
+  int width, height, xposition, yposition;
+
+  points_t Points;
+/*  image_data_t rubber_data;*/
+
+  GC Data_GC[MAXCOLOR]/*, RubberGC*/;
+  PFD map, deriv;
+
+  int aflag, bflag, wflag, hflag, Rflag;
+
+  int   maxindex;
+  int   funcmaxindex;
+  double  min_a, min_b, a_range, b_range, minlyap;
+  double  max_a, max_b;
+  double  start_x, lyapunov, a_inc, b_inc, a, b;
+  int   numcolors, numfreecols, lowrange;
+  xy_t  point;
+#ifdef BACKING_PIXMAP
+  Pixmap  pixmap;
 #endif
+/*  XColor  Colors[MAXCOLOR];*/
+  double  *exponents[MAXFRAMES];
+  double  a_minimums[MAXFRAMES], b_minimums[MAXFRAMES];
+  double  a_maximums[MAXFRAMES], b_maximums[MAXFRAMES];
+  double  minexp, maxexp, prob;
+  int     expind[MAXFRAMES], resized[MAXFRAMES];
+  int     numwheels, force, Force, negative;
+  int     rgb_max, nostart, stripe_interval;
+  int     save, show, useprod, spinlength;
+  int     maxframe, frame, dorecalc, mapindex, run;
+  char    *outname;
+
+  int sendpoint_index;
+
+  int   forcing[MAXINDEX];
+  int   Forcing[FUNCMAXINDEX];
+
+  int reset_countdown;
+
+  int ncolors;
+  XColor colors[MAXCOLOR];
+};
 
-static GC Data_GC[MAXCOLOR], RubberGC;
 
-#define MAXINDEX 64
-#define FUNCMAXINDEX 16
-#define MAXWHEELS 7
-#define NUMMAPS 5
+static const double pmins[NUMMAPS] = { 2.0, 0.0, 0.0, 0.0, 0.0 };
+static const double pmaxs[NUMMAPS] = { 4.0, 1.0, 6.75, 6.75, 16.0 };
+static const double amins[NUMMAPS] = { 2.0, 0.0, 0.0, 0.0, 0.0 };
+static const double aranges[NUMMAPS] = { 2.0, 1.0, 6.75, 6.75, 16.0 };
+static const double bmins[NUMMAPS] = { 2.0, 0.0, 0.0, 0.0, 0.0 };
+static const double branges[NUMMAPS] = { 2.0, 1.0, 6.75, 6.75, 16.0 };
 
-typedef double (*PFD)(double,double);
+/****************************************************************************/
 
-static double logistic(double,double), circle(double,double), leftlog(double,double), rightlog(double,double), doublelog(double,double);
-static double dlogistic(double,double), dcircle(double,double), dleftlog(double,double), drightlog(double,double), ddoublelog(double,double);
-static PFD map, deriv;
-static PFD Maps[NUMMAPS] = { logistic, circle, leftlog, rightlog, doublelog };
-static PFD Derivs[NUMMAPS] = { dlogistic, dcircle, dleftlog, drightlog, ddoublelog };
-
-static int aflag=0, bflag=0, wflag=0, hflag=0, Rflag=0;
-static double pmins[NUMMAPS] = { 2.0, 0.0, 0.0, 0.0, 0.0 };
-static double pmaxs[NUMMAPS] = { 4.0, 1.0, 6.75, 6.75, 16.0 };
-static double amins[NUMMAPS] = { 2.0, 0.0, 0.0, 0.0, 0.0 };
-static double aranges[NUMMAPS] = { 2.0, 1.0, 6.75, 6.75, 16.0 };
-static double bmins[NUMMAPS] = { 2.0, 0.0, 0.0, 0.0, 0.0 };
-static double branges[NUMMAPS] = { 2.0, 1.0, 6.75, 6.75, 16.0 };
-
-static int   forcing[MAXINDEX] = { 0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,
-                       0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,
-                       0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1 };
-static int   Forcing[FUNCMAXINDEX] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
-
-static int   maxindex = MAXINDEX;
-static int   funcmaxindex = FUNCMAXINDEX;
-static double  min_a=2.0, min_b=2.0, a_range=2.0, b_range=2.0, minlyap=1.0;
-static double  max_a=4.0, max_b=4.0;
-static double  start_x=0.65, lyapunov, a_inc, b_inc, a, b;
-static int     numcolors=16, numfreecols, displayplanes, lowrange;
-static xy_t    point;
-static Pixmap  pixmap;
-static Colormap cmap;
-static XColor  Colors[MAXCOLOR];
-static double  *exponents[MAXFRAMES];
-static double  a_minimums[MAXFRAMES], b_minimums[MAXFRAMES];
-static double  a_maximums[MAXFRAMES], b_maximums[MAXFRAMES];
-static double  minexp, maxexp, prob=0.5;
-static int     expind[MAXFRAMES]={0}, resized[MAXFRAMES]={0};
-static int     numwheels=MAXWHEELS, force=0, Force=0, negative=1;
-static int     rgb_max=65000, nostart=1, stripe_interval=7;
-static int     save=1, show=0, useprod=1, spinlength=256, savefile=0;
-static int     maxframe=0, frame=0, dorecalc=0, mapindex=0, run=1;
-static char    *outname="lyap.out";
-
-
-const char * const version = LYAP_VERSION;
-
-static void resize(void);
-static void redisplay(Window w, XExposeEvent *event);
-static void Spin(Window w);
-static void show_defaults(void);
-static void StartRubberBand(Window w, image_data_t *data, XEvent *event);
-static void TrackRubberBand(Window w, image_data_t *data, XEvent *event);
-static void EndRubberBand(Window w, image_data_t *data, XEvent *event);
-static void CreateXorGC(void);
-static void InitBuffer(void);
-static void BufferPoint(Display *display, Window window, int color,
-                       int x, int y);
-static void FlushBuffer(void);
-static void init_canvas(void);
-static void init_data(void);
-static void init_color(void);
-static void parseargs(void);
-static void Clear(void);
-static void setupmem(void);
-static void main_event(void);
-static int complyap(void);
-static void Getkey(XKeyEvent *event);
-static int sendpoint(double expo);
-static void save_to_file(void);
-static void setforcing(void);
-static void check_params(int mapnum, int parnum);
-static void usage(void);
-static void Destroy_frame(void);
-static void freemem(void);
-static void Redraw(void);
-static void redraw(double *exparray, int index, int cont);
-static void recalc(void);
-static void SetupCorners(XPoint *corners, image_data_t *data);
-static void set_new_params(Window w, image_data_t *data);
-static void go_down(void);
-static void go_back(void);
-static void go_init(void);
-static void jumpwin(void);
-static void print_help(void);
-static void print_values(void);
-
-
-void
-screenhack (Display *d, Window window)
-{
-  XWindowAttributes xgwa;
-  int builtin = -1;
-  dpy = d;
-  XGetWindowAttributes (dpy, window, &xgwa);
-  width = xgwa.width;
-  height = xgwa.height;
-  visual = xgwa.visual;
-  cmap = xgwa.colormap;
+/* callback function declarations
+ */
 
-  parseargs();
+static double logistic(double,double);
+static double circle(double,double);
+static double leftlog(double,double);
+static double rightlog(double,double);
+static double doublelog(double,double);
+static double dlogistic(double,double);
+static double dcircle(double,double);
+static double dleftlog(double,double);
+static double drightlog(double,double);
+static double ddoublelog(double,double);
 
-  if (get_boolean_resource("randomize", "Boolean"))
-    builtin = random() % 22;
-  else {
-    char *s = get_string_resource("builtin", "Integer");
-    if (s && *s)
-      builtin = atoi(s);
-    if (s) free (s);
-  }
-    
-  if (builtin >= 0)
-    {
-      char *ff = 0;
-      switch (builtin) {
-      case 0:
-       min_a = 3.75; aflag++;
-       min_b = 3.299999; bflag++;
-       a_range = 0.05; wflag++;
-       b_range = 0.05; hflag++;
-       dwell = 200;
-       settle = 100;
-       ff = "abaabbaaabbb";
-       break;
-
-      case 1:
-       min_a = 3.8; aflag++;
-       min_b = 3.2; bflag++;
-       b_range = .05; hflag++;
-       a_range = .05; wflag++;
-       ff = "bbbbbaaaaa";
-       break;
-
-      case 2:
-       min_a =  3.4; aflag++;
-       min_b =  3.04; bflag++;
-       a_range =  .5; wflag++;
-       b_range =  .5; hflag++;
-       ff = "abbbbbbbbb";
-       settle = 500;
-       dwell = 1000;
-       break;
-
-      case 3:
-       min_a = 3.5; aflag++;
-       min_b = 3.0; bflag++;
-       a_range = 0.2; wflag++;
-       b_range = 0.2; hflag++;
-       dwell = 600;
-       settle = 300;
-       ff = "aaabbbab";
-       break;
-
-      case 4:
-       min_a = 3.55667; aflag++;
-       min_b = 3.2; bflag++;
-       b_range = .05; hflag++;
-       a_range = .05; wflag++;
-       ff = "bbbbbaaaaa";
-       break;
-
-      case 5:
-       min_a = 3.79; aflag++;
-       min_b = 3.22; bflag++;
-       b_range = .02999; hflag++;
-       a_range = .02999; wflag++;
-       ff = "bbbbbaaaaa";
-       break;
-
-      case 6:
-       min_a = 3.7999; aflag++;
-       min_b = 3.299999; bflag++;
-       a_range = 0.2; wflag++;
-       b_range = 0.2; hflag++;
-       dwell = 300;
-       settle = 150;
-       ff = "abaabbaaabbb";
-       break;
-
-      case 7:
-       min_a = 3.89; aflag++;
-       min_b = 3.22; bflag++;
-       b_range = .028; hflag++;
-       a_range = .02999; wflag++;
-       ff = "bbbbbaaaaa";
-       settle = 600;
-       dwell = 1000;
-       break;
-
-      case 8:
-       min_a = 3.2; aflag++;
-       min_b = 3.7; bflag++;
-       a_range = 0.05; wflag++;
-       b_range = .005; hflag++;
-       ff = "abbbbaa";
-       break;
-
-      case 9:
-       ff = "aaaaaabbbbbb";
-       mapindex = 1;
-       dwell =  400;
-       settle =  200;
-       minlyap = maxexp = ABS(-0.85);
-       minexp = -1.0 * minlyap;
-       break;
-
-      case 10:
-       ff = "aaaaaabbbbbb";
-       mapindex = 1;
-       dwell =  400;
-       settle = 200;
-       minlyap = maxexp = ABS(-0.85);
-       minexp = -1.0 * minlyap;
-       break;
-
-      case 11:
-       mapindex = 1;
-       dwell =  400;
-       settle = 200;
-       minlyap = maxexp = ABS(-0.85);
-       minexp = -1.0 * minlyap;
-       break;
-
-      case 12:
-       ff = "abbb";
-       mapindex = 1;
-       dwell =  400;
-       settle = 200;
-       minlyap = maxexp = ABS(-0.85);
-       minexp = -1.0 * minlyap;
-       break;
-
-      case 13:
-       ff = "abbabaab";
-       mapindex = 1;
-       dwell =  400;
-       settle = 200;
-       minlyap = maxexp = ABS(-0.85);
-       minexp = -1.0 * minlyap;
-       break;
-
-      case 14:
-       ff = "abbabaab";
-       dwell =  800;
-       settle = 200;
-       minlyap = maxexp = ABS(-0.85);
-       minexp = -1.0 * minlyap;
-       /* ####  -x 0.05 */
-       min_a = 3.91; aflag++;
-       a_range =  0.0899999999; wflag++;
-       min_b =  3.28; bflag++;
-       b_range =  0.35; hflag++;
-       break;
-
-      case 15:
-       ff = "aaaaaabbbbbb";
-       dwell =  400;
-       settle = 200;
-       minlyap = maxexp = ABS(-0.85);
-       minexp = -1.0 * minlyap;
-       break;
-
-      case 16:
-       dwell =  400;
-       settle = 200;
-       minlyap = maxexp = ABS(-0.85);
-       minexp = -1.0 * minlyap;
-       break;
-
-      case 17:
-       ff = "abbb";
-       dwell =  400;
-       settle = 200;
-       minlyap = maxexp = ABS(-0.85);
-       minexp = -1.0 * minlyap;
-       break;
-
-      case 18:
-       ff = "abbabaab";
-       dwell =  400;
-       settle = 200;
-       minlyap = maxexp = ABS(-0.85);
-       minexp = -1.0 * minlyap;
-       break;
-
-      case 19:
-       mapindex = 2;
-       ff = "aaaaaabbbbbb";
-       dwell =  400;
-       settle = 200;
-       minlyap = maxexp = ABS(-0.85);
-       minexp = -1.0 * minlyap;
-       break;
-
-      case 20:
-       mapindex = 2;
-       dwell =  400;
-       settle = 200;
-       minlyap = maxexp = ABS(-0.85);
-       minexp = -1.0 * minlyap;
-       break;
-
-      case 21:
-       mapindex = 2;
-       ff = "abbb";
-       dwell =  400;
-       settle = 200;
-       minlyap = maxexp = ABS(-0.85);
-       minexp = -1.0 * minlyap;
-       break;
-
-      case 22:
-       mapindex = 2;
-       ff = "abbabaab";
-       dwell =  400;
-       settle = 200;
-       minlyap = maxexp = ABS(-0.85);
-       minexp = -1.0 * minlyap;
-       break;
-      }
+static const PFD Maps[NUMMAPS] = { logistic, circle, leftlog, rightlog, 
+                                   doublelog };
+static const PFD Derivs[NUMMAPS] = { dlogistic, dcircle, dleftlog, 
+                                     drightlog, ddoublelog };
 
-      if (ff) {
-       char *ch;
-       int bindex = 0;
-       maxindex = strlen(ff);
-       if (maxindex > MAXINDEX)
-         usage();
-       ch = ff;
-       force++;
-       while (bindex < maxindex) {
-         if (*ch == 'a')
-           forcing[bindex++] = 0;
-         else if (*ch == 'b')
-           forcing[bindex++] = 1;
-         else
-           usage();
-         ch++;
-       }
-      }
-    }
 
-  screen = DefaultScreen(dpy);
-  background = BlackPixel(dpy, screen);
-  setupmem();
-  init_data();
-  if (displayplanes > 1)
-    foreground = startcolor;
-  else
-    foreground = WhitePixel(dpy, screen);
+/****************************************************************************/
 
-  /*
-  * Create the window to display the Lyapunov exponents
-  */
-  canvas = window;
-  init_canvas();
-
-  if (window != DefaultRootWindow(dpy))
-    XSelectInput(dpy,canvas,KeyPressMask|ButtonPressMask|ButtonMotionMask|
-                ButtonReleaseMask|ExposureMask|StructureNotifyMask);
-  if (displayplanes > 1) {
-    init_color();
-  } else {
-    XQueryColors(dpy, DefaultColormap(dpy, DefaultScreen(dpy)),
-       Colors, numcolors);
-  }
-  pixmap = XCreatePixmap(dpy, DefaultRootWindow(dpy),
-                        width, height, DefaultDepth(dpy, screen));
-  rubber_data.band_cursor = XCreateFontCursor(dpy, XC_hand2);
-  CreateXorGC();
-  Clear();
-  for(;;)
-      main_event();
-}
+/* other function declarations
+ */
+
+static void resize(struct state *);
+/*static void Spin(struct state *);*/
+static void show_defaults(struct state *);
+/*static void StartRubberBand(struct state *, image_data_t *, XEvent *);
+static void TrackRubberBand(struct state *, image_data_t *, XEvent *);
+static void EndRubberBand(struct state *, image_data_t *, XEvent *);*/
+/*static void CreateXorGC(struct state *);*/
+static void InitBuffer(struct state *);
+static void BufferPoint(struct state *, int color, int x, int y);
+static void FlushBuffer(struct state *);
+static void init_data(struct state *);
+static void init_color(struct state *);
+static void parseargs(struct state *);
+static void Clear(struct state *);
+static void setupmem(struct state *);
+static int complyap(struct state *);
+static Bool Getkey(struct state *, XKeyEvent *);
+static int sendpoint(struct state *, double expo);
+/*static void save_to_file(struct state *);*/
+static void setforcing(struct state *);
+static void check_params(struct state *, int mapnum, int parnum);
+static void usage(struct state *);
+static void Destroy_frame(struct state *);
+static void freemem(struct state *);
+static void Redraw(struct state *);
+static void redraw(struct state *, double *exparray, int index, int cont);
+static void recalc(struct state *);
+/*static void SetupCorners(XPoint *, image_data_t *);
+static void set_new_params(struct state *, image_data_t *);*/
+static void go_down(struct state *);
+static void go_back(struct state *);
+static void go_init(struct state *);
+static void jumpwin(struct state *);
+static void print_help(struct state *);
+static void print_values(struct state *);
+
+
+/****************************************************************************/
 
-static void
-main_event(void)
-{
-  int n;
-  XEvent event;
-
-  if (complyap() == TRUE)
-      run=0;
-  n = XEventsQueued(dpy, QueuedAfterFlush);
-  while (n--) {
-         XNextEvent(dpy, &event);
-           switch(event.type)
-           {
-           case KeyPress:
-    Getkey(&event.xkey);
-    break;
-           case Expose:
-    redisplay(canvas, &event.xexpose);
-         break;
-           case ConfigureNotify:
-    resize();
-         break;
-           case ButtonPress:
-    StartRubberBand(canvas, &rubber_data, &event);
-         break;
-           case MotionNotify:
-    TrackRubberBand(canvas, &rubber_data, &event);
-         break;
-           case ButtonRelease:
-    EndRubberBand(canvas, &rubber_data, &event);
-         break;
-           }
-       }
-}
 
 /* complyap() is the guts of the program. This is where the Lyapunov exponent
  * is calculated. For each iteration (past some large number of iterations)
@@ -585,135 +319,154 @@ main_event(void)
  * speed up is achieved by utilizing the fact that log(a*b) = log(a) + log(b).
  */
 static int
-complyap(void)
+complyap(struct state *st)
 {
-  register i, bindex;
-  double total, prod, x, r;
+  int i, bindex;
+  double total, prod, x, dx, r;
+
+  if (st->maxcolor > MAXCOLOR)
+    abort();
 
-  if (!run)
+  if (!st->run)
     return TRUE;
-  a += a_inc;
-  if (a >= max_a)
-    if (sendpoint(lyapunov) == TRUE)
+  st->a += st->a_inc;
+  if (st->a >= st->max_a) {
+    if (sendpoint(st, st->lyapunov) == TRUE)
       return FALSE;
     else {
-      FlushBuffer();
-      if (savefile)
-       save_to_file();
+      FlushBuffer(st);
+      /*      if (savefile)
+              save_to_file(); */
       return TRUE;
     }
-  if (b >= max_b) {
-    FlushBuffer();
-    if (savefile)
-      save_to_file();
+  }
+  if (st->b >= st->max_b) {
+    FlushBuffer(st);
+    /*    if (savefile)
+          save_to_file();*/
     return TRUE;
   }
   prod = 1.0;
   total = 0.0;
   bindex = 0;
-  x = start_x;
-  r = (forcing[bindex]) ? b : a;
+  x = st->start_x;
+  r = (st->forcing[bindex]) ? st->b : st->a;
 #ifdef MAPS
   findex = 0;
-  map = Maps[Forcing[findex]];
+  map = Maps[st->Forcing[findex]];
 #endif
-  for (i=0;i<settle;i++) {     /* Here's where we let the thing */
-    x = (*map)(x, r);   /* "settle down". There is usually */
-    if (++bindex >= maxindex) { /* some initial "noise" in the */
+  for (i=0;i<st->settle;i++) {     /* Here's where we let the thing */
+    x = st->map (x, r);  /* "settle down". There is usually */
+    if (++bindex >= st->maxindex) { /* some initial "noise" in the */
       bindex = 0;    /* iterations. How can we optimize */
-      if (Rflag)      /* the value of settle ??? */
-         setforcing();
+      if (st->Rflag)      /* the value of settle ??? */
+        setforcing(st);
     }
-    r = (forcing[bindex]) ? b : a;
+    r = (st->forcing[bindex]) ? st->b : st->a;
 #ifdef MAPS
     if (++findex >= funcmaxindex)
       findex = 0;
-    map = Maps[Forcing[findex]];
+    map = Maps[st->Forcing[findex]];
 #endif
   }
 #ifdef MAPS
-  deriv = Derivs[Forcing[findex]];
+  deriv = Derivs[st->Forcing[findex]];
 #endif
-  if (useprod) {      /* using log(a*b) */
-    for (i=0;i<dwell;i++) {
-      x = (*map)(x, r);
-      prod *= ABS((*deriv)(x, r));
+  if (st->useprod) {      /* using log(a*b) */
+    for (i=0;i<st->dwell;i++) {
+      x = st->map (x, r);
+      dx = st->deriv (x, r); /* ABS is a macro, so don't be fancy */
+      dx = ABS(dx);
+      if (dx == 0.0) /* log(0) is nasty so break out. */
+        {
+          i++;
+          break;
+        }
+      prod *= dx;
       /* we need to prevent overflow and underflow */
       if ((prod > 1.0e12) || (prod < 1.0e-12)) {
-       total += log(prod);
-       prod = 1.0;
+        total += log(prod);
+        prod = 1.0;
       }
-      if (++bindex >= maxindex) {
-       bindex = 0;
-       if (Rflag)
-         setforcing();
+      if (++bindex >= st->maxindex) {
+        bindex = 0;
+        if (st->Rflag)
+          setforcing(st);
       }
-      r = (forcing[bindex]) ? b : a;
+      r = (st->forcing[bindex]) ? st->b : st->a;
 #ifdef MAPS
       if (++findex >= funcmaxindex)
-       findex = 0;
-      map = Maps[Forcing[findex]];
-      deriv = Derivs[Forcing[findex]];
+        findex = 0;
+      map = Maps[st->Forcing[findex]];
+      deriv = Derivs[st->Forcing[findex]];
 #endif
     }
     total += log(prod);
-    lyapunov = (total * M_LOG2E) / (double)dwell;
+    st->lyapunov = (total * M_LOG2E) / (double)i;   
   }
-  else {       /* use log(a) + log(b) */
-    for (i=0;i<dwell;i++) {
-      x = (*map)(x, r);
-      total += log(ABS((*deriv)(x, r)));
-      if (++bindex >= maxindex) {
-       bindex = 0;
-       if (Rflag)
-         setforcing();
+  else {        /* use log(a) + log(b) */
+    for (i=0;i<st->dwell;i++) {
+      x = st->map (x, r);
+      dx = st->deriv (x, r); /* ABS is a macro, so don't be fancy */
+      dx = ABS(dx);
+      if (x == 0.0)  /* log(0) check */
+        {
+          i++;
+          break;
+        }
+      total += log(dx);
+      if (++bindex >= st->maxindex) {
+        bindex = 0;
+        if (st->Rflag)
+          setforcing(st);
       }
-      r = (forcing[bindex]) ? b : a;
+      r = (st->forcing[bindex]) ? st->b : st->a;
 #ifdef MAPS
       if (++findex >= funcmaxindex)
-       findex = 0;
-      map = Maps[Forcing[findex]];
-      deriv = Derivs[Forcing[findex]];
+        findex = 0;
+      map = Maps[st->Forcing[findex]];
+      deriv = Derivs[st->Forcing[findex]];
 #endif
     }
-    lyapunov = (total * M_LOG2E) / (double)dwell;
+    st->lyapunov = (total * M_LOG2E) / (double)i;
   }
-  if (sendpoint(lyapunov) == TRUE)
+
+  if (sendpoint(st, st->lyapunov) == TRUE)
     return FALSE;
   else {
-    FlushBuffer();
-    if (savefile)
-      save_to_file();
+    FlushBuffer(st);
+    /*    if (savefile)
+          save_to_file();*/
     return TRUE;
   }
 }
 
 static double
-logistic(double x, double r)       /* the familiar logistic map */
+logistic(double x, double r)        /* the familiar logistic map */
 {
   return(r * x * (1.0 - x));
 }
 
 static double
-dlogistic(double x, double r)      /* the derivative of logistic map */
+dlogistic(double x, double r)       /* the derivative of logistic map */
 {
   return(r - (2.0 * r * x));
 }
 
 static double
-circle(double x, double r)       /* sin() hump or sorta like the circle map */
+circle(double x, double r)        /* sin() hump or sorta like the circle map */
 {
   return(r * sin(M_PI * x));
 }
 
 static double
-dcircle(double x, double r)      /* derivative of the "sin() hump" */
+dcircle(double x, double r)       /* derivative of the "sin() hump" */
 {
   return(r * M_PI * cos(M_PI * x));
 }
 
 static double
-leftlog(double x, double r)      /* left skewed logistic */
+leftlog(double x, double r)       /* left skewed logistic */
 {
   double d;
 
@@ -758,60 +511,38 @@ ddoublelog(double x, double r)   /* derivative of the double logistic */
 }
 
 static void
-init_data(void)
+init_data(struct state *st)
 {
-  numcolors = XDisplayCells(dpy, XDefaultScreen(dpy));
-  displayplanes = DisplayPlanes(dpy, XDefaultScreen(dpy));
-  if (numcolors > maxcolor)
-    numcolors = maxcolor;
-  numfreecols = numcolors - mincolindex;
-  lowrange = mincolindex - startcolor;
-  a_inc = a_range / (double)width;
-  b_inc = b_range / (double)height;
-  point.x = -1;
-  point.y = 0;
-  a = rubber_data.p_min = min_a;
-  b = rubber_data.q_min = min_b;
-  rubber_data.p_max = max_a;
-  rubber_data.q_max = max_b;
-  if (show)
-    show_defaults();
-  InitBuffer();
-  ya_rand_init(0);
-}
-
-static void
-init_canvas(void)
-{
-  static int i;
-
-  /*
-  * create default, writable, graphics contexts for the canvas.
-  */
-       for (i=0; i<maxcolor; i++) {
-           Data_GC[i] = XCreateGC(dpy, DefaultRootWindow(dpy),
-               (unsigned long) NULL, (XGCValues *) NULL);
-           /* set the background to black */
-           XSetBackground(dpy,Data_GC[i],BlackPixel(dpy,XDefaultScreen(dpy)));
-           /* set the foreground of the ith context to i */
-           XSetForeground(dpy, Data_GC[i], i);
-       }
-       if (displayplanes == 1) {
-           XSetForeground(dpy,Data_GC[0],BlackPixel(dpy,XDefaultScreen(dpy)));
-           XSetForeground(dpy,Data_GC[1],WhitePixel(dpy,XDefaultScreen(dpy)));
-       }
+  st->numcolors = get_integer_resource (st->dpy, "colors", "Integer");
+  if (st->numcolors < 2)
+    st->numcolors = 2;
+  if (st->numcolors > st->maxcolor)
+    st->numcolors = st->maxcolor;
+  st->numfreecols = st->numcolors - st->mincolindex;
+  st->lowrange = st->mincolindex - st->startcolor;
+  st->a_inc = st->a_range / (double)st->width;
+  st->b_inc = st->b_range / (double)st->height;
+  st->point.x = -1;
+  st->point.y = 0;
+  st->a = /*st->rubber_data.p_min = */st->min_a;
+  st->b = /*st->rubber_data.q_min = */st->min_b;
+/*  st->rubber_data.p_max = st->max_a;
+  st->rubber_data.q_max = st->max_b;*/
+  if (st->show)
+    show_defaults(st);
+  InitBuffer(st);
 }
 
 #if 0
 static void
 hls2rgb(int hue_light_sat[3],
-       int rgb[3])             /*      Each in range [0..65535]        */
+        int rgb[3])             /*      Each in range [0..65535]        */
 {
   unsigned short r, g, b;
-  hsv_to_rgb((int) (hue_light_sat[0] / 10),            /* 0-3600 -> 0-360 */
-            (int) ((hue_light_sat[2]/1000.0) * 64435), /* 0-1000 -> 0-65535 */
-            (int) ((hue_light_sat[1]/1000.0) * 64435), /* 0-1000 -> 0-65535 */
-            &r, &g, &b);
+  hsv_to_rgb((int) (hue_light_sat[0] / 10),             /* 0-3600 -> 0-360 */
+             (int) ((hue_light_sat[2]/1000.0) * 64435), /* 0-1000 -> 0-65535 */
+             (int) ((hue_light_sat[1]/1000.0) * 64435), /* 0-1000 -> 0-65535 */
+             &r, &g, &b);
   rgb[0] = r;
   rgb[1] = g;
   rgb[2] = b;
@@ -820,629 +551,480 @@ hls2rgb(int hue_light_sat[3],
 
 
 static void
-init_color(void)
+init_color(struct state *st)
 {
-#if 1
-
   int i;
-  XColor colors[256];
-  int ncolors = maxcolor;
-  Bool writable = False;
-  make_smooth_colormap(dpy, visual, cmap,
-                       colors, &ncolors, True, &writable, True);
-
-  for (i = 0; i < maxcolor; i++)
-    XSetForeground(dpy, Data_GC[i],
-                  colors[((int) ((i / ((float)maxcolor)) * ncolors))].pixel);
-
-#else
-  static int i, j, colgap, leg, step;
-  static Visual *visual;
-  Colormap def_cmap;
-  int hls[3], rgb[3];
-
-  def_cmap = DefaultColormap(dpy, DefaultScreen(dpy));
-  for (i=0; i<numcolors; i++) {
-    Colors[i].pixel = i;
-    Colors[i].flags = DoRed|DoGreen|DoBlue;
-  }
-
-  /* Try to write into a new color map */
-  visual = DefaultVisual(dpy, DefaultScreen(dpy));
-  cmap = XCreateColormap(dpy, canvas, visual, AllocAll);
-  XQueryColors(dpy, def_cmap, Colors, numcolors);
-  if (mincolindex)
-    colgap = rgb_max / mincolindex;
-  else
-    colgap = rgb_max;
-  hls[0] = 50; /* Hue in low range */
-  hls[2] = 1000;  /* Fully saturated */
-  for (i=startcolor; i<lowrange + startcolor; i++) {
-    hls[1] = 1000L * (i-startcolor) / lowrange;
-    hls2rgb(hls, rgb);
-    Colors[i].red = rgb[0];
-    Colors[i].green = rgb[1];
-    Colors[i].blue = rgb[2];
-  }
-  colgap = rgb_max / numcolors;
-  if (numwheels == 0)
-    XQueryColors(dpy, def_cmap, Colors, numcolors);
-  else if (numwheels == 1) {
-    colgap = 2*rgb_max/(numcolors - color_offset);
-    for (i=mincolindex; i<(numcolors/2); i++) {
-      Colors[i].blue = 0;
-      Colors[i].green=((i+color_offset)*colgap);
-      Colors[i].red=((i+color_offset)*colgap);
-    }
-    for (i=(numcolors/2); i<(numcolors); i++) {
-      Colors[i].blue = 0;
-      Colors[i].green=(((numcolors-i)+color_offset)*colgap);
-      Colors[i].red=(((numcolors-i)+color_offset)*colgap);
-    }
-  }
-  else if (numwheels == 2) {
-         hls[0] = 800; /* Hue in mid range */
-         hls[2] = 1000;  /* Fully saturated */
-         for (i=startcolor; i<lowrange + startcolor; i++) {
-      hls[1] = 1000L * (i-startcolor) / lowrange;
-      hls2rgb(hls, rgb);
-      Colors[i].red = rgb[0];
-      Colors[i].green = rgb[1];
-      Colors[i].blue = rgb[2];
-         }
-    for (i=mincolindex; i<(numcolors/2); i++) {
-      Colors[i].blue = rgb_max;
-      Colors[i].green = 0;
-      Colors[i].red=(i*2*rgb_max/numcolors);
-    }
-    for (i=(numcolors/2); i<numcolors; i++) {
-      Colors[i].blue = rgb_max;
-      Colors[i].green = 0;
-      Colors[i].red=((numcolors - i)*2*rgb_max/numcolors);
+  if (st->ncolors)
+    free_colors (st->screen, st->cmap, st->colors, st->ncolors);
+  st->ncolors = st->maxcolor;
+  make_smooth_colormap(st->screen, st->visual, st->cmap,
+                       st->colors, &st->ncolors, True, NULL, True);
+
+  for (i = 0; i < st->maxcolor; i++) {
+    if (! st->Data_GC[i]) {
+      XGCValues gcv;
+      gcv.background = BlackPixelOfScreen(st->screen);
+      st->Data_GC[i] = XCreateGC(st->dpy, st->canvas, GCBackground, &gcv);
     }
+    XSetForeground(st->dpy, st->Data_GC[i],
+                   st->colors[((int) ((i / ((float)st->maxcolor)) *
+                                      st->ncolors))].pixel);
   }
-  else if (numwheels == 3) {
-         hls[0] = 800; /* Hue in mid range */
-         hls[2] = 1000;  /* Fully saturated */
-         for (i=startcolor; i<lowrange + startcolor; i++) {
-      hls[1] = 1000L * (i-startcolor) / lowrange;
-      hls2rgb(hls, rgb);
-      Colors[i].red = rgb[0];
-      Colors[i].green = rgb[1];
-      Colors[i].blue = rgb[2];
-         }
-    colgap = 4*rgb_max/numcolors;
-    for (i=mincolindex; i<(numcolors/4); i++) {
-      Colors[i].blue = rgb_max;
-      Colors[i].green = 0;
-      Colors[i].red=(i*colgap);
-    }
-    for (i=(numcolors/4); i<(numcolors/2); i++) {
-      Colors[i].red = rgb_max;
-      Colors[i].green = 0;
-      Colors[i].blue=((numcolors/2) - i) * colgap;
-    }
-    for (i=(numcolors/2); i<(0.75*numcolors); i++) {
-      Colors[i].red = rgb_max;
-      Colors[i].blue=(i * colgap);
-      Colors[i].green = 0;
-    }
-    for (i=(0.75*numcolors); i<numcolors; i++) {
-      Colors[i].blue = rgb_max;
-      Colors[i].green = 0;
-      Colors[i].red=(numcolors-i)*colgap;
-    }
-  }
-  else if (numwheels == 4) {
-         hls[0] = 800; /* Hue in mid range */
-         hls[2] = 1000;  /* Fully saturated */
-         for (i=startcolor; i<lowrange + startcolor; i++) {
-      hls[1] = 1000L * (i-startcolor) / lowrange;
-      hls2rgb(hls, rgb);
-      Colors[i].red = rgb[0];
-      Colors[i].green = rgb[1];
-      Colors[i].blue = rgb[2];
-         }
-    colgap = numwheels * rgb_max / numcolors;
-    for (i=mincolindex; i<(numcolors/numwheels); i++) {
-      Colors[i].blue = rgb_max;
-      Colors[i].green = 0;
-      Colors[i].red=(i*colgap);
-    }
-    for (i=(numcolors/numwheels); i<(2*numcolors/numwheels); i++) {
-      Colors[i].red = rgb_max;
-      Colors[i].green = 0;
-      Colors[i].blue=((2*numcolors/numwheels) - i) * colgap;
-    }
-    for (i=(2*numcolors/numwheels); i<numcolors; i++) {
-      Colors[i].red = rgb_max;
-      Colors[i].green=(i - (2*numcolors/numwheels)) * colgap;
-      Colors[i].blue = 0;
-    }
-  }
-  else if (numwheels == 5) {
-    hls[1] = 700; /* Lightness in midrange */
-    hls[2] = 1000;  /* Fully saturated */
-    for (i=mincolindex; i<numcolors; i++) {
-      hls[0] = 3600L * i / numcolors;
-      hls2rgb(hls, rgb);
-      Colors[i].red = rgb[0];
-      Colors[i].green = rgb[1];
-      Colors[i].blue = rgb[2];
-    }
-    for (i=mincolindex; i<numcolors; i+=stripe_interval) {
-      hls[0] = 3600L * i / numcolors;
-      hls2rgb(hls, rgb);
-      Colors[i].red = rgb[0] / 2;
-      Colors[i].green = rgb[1] / 2;
-      Colors[i].blue = rgb[2] / 2;
-    }
-  }
-  else if (numwheels == 6) {
-      hls[0] = 800; /* Hue in mid range */
-      hls[2] = 1000;  /* Fully saturated */
-      for (i=startcolor; i<lowrange + startcolor; i++) {
-    hls[1] = 1000L * (i-startcolor) / lowrange;
-    hls2rgb(hls, rgb);
-    Colors[i].red = rgb[0];
-    Colors[i].green = rgb[1];
-    Colors[i].blue = rgb[2];
-      }
-      step = numfreecols / 3;
-      leg = step+mincolindex;
-      for (i = mincolindex; i < leg; ++i)
-      {
-    Colors[i].pixel = i;
-    Colors[i].red = fabs(65535 - (double)i / step * 65535.0);
-    Colors[i].blue = (double)i / step * 65535.0;
-    Colors[i].green = 0;
-    Colors[i].flags = DoRed | DoGreen | DoBlue;
-      }
-      for (j = 0, i = leg, leg += step; i < leg; ++i, ++j)
-      {
-    Colors[i].pixel = i;
-    Colors[i].red = (double)j / step * 65535.0;
-    Colors[i].blue = 65535;
-    Colors[i].green = Colors[i].red;
-    Colors[i].flags = DoRed | DoGreen | DoBlue;
-      }
-      for (j = 0, i = leg, leg += step; i < leg; ++i, ++j)
-      {
-    Colors[i].pixel = i;
-    Colors[i].red = 65535;
-    Colors[i].blue = fabs(65535 - (double)j / step * 65535.0);
-    Colors[i].green = Colors[i].blue;
-    Colors[i].flags = DoRed | DoGreen | DoBlue;
-      }
-  }
-  else if (numwheels == MAXWHEELS) {  /* rainbow palette */
-    hls[1] = 500; /* Lightness in midrange */
-    hls[2] = 1000;  /* Fully saturated */
-    for (i=mincolindex; i<numcolors; i++) {
-      hls[0] = 3600L * i / numcolors;
-      hls2rgb(hls, rgb);
-      Colors[i].red = rgb[0];
-      Colors[i].green = rgb[1];
-      Colors[i].blue = rgb[2];
-    }
-  }
-  XStoreColors(dpy, cmap, Colors, numcolors);
-
-  XSetWindowColormap(dpy, canvas, cmap);
-#endif
 }
 
+
 static void
-parseargs()
+parseargs(struct state *st)
 {
-  static int i;
+  int i;
   int bindex=0, findex;
   char *s, *ch;
 
-  map = Maps[0];
-  deriv = Derivs[0];
-  maxexp=minlyap; minexp= -1.0 * minlyap;
+  st->map = Maps[0];
+  st->deriv = Derivs[0];
+  st->maxexp=st->minlyap; st->minexp= -1.0 * st->minlyap;
 
-  mincolindex = get_integer_resource("minColor", "Integer");
-  dwell = get_integer_resource("dwell", "Integer");
+  st->mincolindex = get_integer_resource(st->dpy, "minColor", "Integer");
+  st->dwell = get_integer_resource(st->dpy, "dwell", "Integer");
 #ifdef MAPS
   {
-    char *optarg = get_string_resource("function", "String");
+    char *optarg = get_string_resource(st->dpy, "function", "String");
     funcmaxindex = strlen(optarg);
     if (funcmaxindex > FUNCMAXINDEX)
       usage();
     ch = optarg;
-    Force++;
+    st->Force++;
     for (findex=0;findex<funcmaxindex;findex++) {
-      Forcing[findex] = (int)(*ch++ - '0');;
-      if (Forcing[findex] >= NUMMAPS)
-       usage();
+      st->Forcing[findex] = (int)(*ch++ - '0');;
+      if (st->Forcing[findex] >= NUMMAPS)
+        usage();
     }
   }
 #endif
-  if (get_boolean_resource("useLog", "Boolean"))
-    useprod=0;
-
-  minlyap=ABS(get_float_resource("colorExponent", "Float"));
-  maxexp=minlyap;
-  minexp= -1.0 * minlyap;
-
-  color_offset = get_integer_resource("colorOffset", "Integer");
-
-  maxcolor=ABS(get_integer_resource("maxColor", "Integer"));
-  if ((maxcolor - startcolor) <= 0)
-    startcolor = 0;
-  if ((maxcolor - mincolindex) <= 0) {
-    mincolindex = 1;
-    color_offset = 0;
+  if (get_boolean_resource(st->dpy, "useLog", "Boolean"))
+    st->useprod=0;
+
+  st->minlyap=ABS(get_float_resource(st->dpy, "colorExponent", "Float"));
+  st->maxexp=st->minlyap;
+  st->minexp= -1.0 * st->minlyap;
+
+  st->color_offset = get_integer_resource(st->dpy, "colorOffset", "Integer");
+
+  st->maxcolor=ABS(get_integer_resource(st->dpy, "maxColor", "Integer"));
+  if ((st->maxcolor - st->startcolor) <= 0)
+    st->startcolor = get_pixel_resource(st->dpy, st->cmap,
+                                        "background", "Background");
+  if ((st->maxcolor - st->mincolindex) <= 0) {
+    st->mincolindex = 1;
+    st->color_offset = 0;
   }
 
-  s = get_string_resource("randomForce", "Float");
+  s = get_string_resource(st->dpy, "randomForce", "Float");
   if (s && *s) {
-    prob=atof(s); Rflag++; setforcing();
+    st->prob=atof(s); st->Rflag++; setforcing(st);
   }
 
-  settle = get_integer_resource("settle", "Integer");
+  st->settle = get_integer_resource(st->dpy, "settle", "Integer");
 
-  s = get_string_resource("minA", "Float");
+#if 0
+  s = get_string_resource(st->dpy, "minA", "Float");
   if (s && *s) {
-    min_a = atof(s);
-    aflag++;
+    st->min_a = atof(s);
+    st->aflag++;
   }
   
-  s = get_string_resource("minB", "Float");
+  s = get_string_resource(st->dpy, "minB", "Float");
   if (s && *s) {
-    min_b=atof(s); bflag++;
+    st->min_b=atof(s); st->bflag++;
   }
+#else
+  st->min_a = get_float_resource (st->dpy, "minA", "Float");
+  st->aflag++;
+  st->min_b = get_float_resource (st->dpy, "minB", "Float");
+  st->bflag++;
+#endif
+
   
-  numwheels = get_integer_resource("wheels", "Integer");
+  st->numwheels = get_integer_resource(st->dpy, "wheels", "Integer");
 
-  s = get_string_resource("forcingFunction", "String");
+  s = get_string_resource(st->dpy, "forcingFunction", "String");
   if (s && *s) {
-    maxindex = strlen(s);
-    if (maxindex > MAXINDEX)
-      usage();
+    st->maxindex = strlen(s);
+    if (st->maxindex > MAXINDEX)
+      usage(st);
     ch = s;
-    force++;
-    while (bindex < maxindex) {
+    st->force++;
+    while (bindex < st->maxindex) {
       if (*ch == 'a')
-       forcing[bindex++] = 0;
+        st->forcing[bindex++] = 0;
       else if (*ch == 'b')
-       forcing[bindex++] = 1;
+        st->forcing[bindex++] = 1;
       else
-       usage();
+        usage(st);
       ch++;
     }
   }
 
-  s = get_string_resource("bRange", "Float");
+  s = get_string_resource(st->dpy, "bRange", "Float");
   if (s && *s) {
-    b_range = atof(s);
-    hflag++;
+    st->b_range = atof(s);
+    st->hflag++;
   }
 
-  start_x = get_float_resource("startX", "Float");
+  st->start_x = get_float_resource(st->dpy, "startX", "Float");
 
-  s = get_string_resource("mapIndex", "Integer");
+  s = get_string_resource(st->dpy, "mapIndex", "Integer");
   if (s && *s) {
-    mapindex=atoi(s);
-    if ((mapindex >= NUMMAPS) || (mapindex < 0))
-      usage();
-    map = Maps[mapindex];
-    deriv = Derivs[mapindex];
-    if (!aflag)
-      min_a = amins[mapindex];
-    if (!wflag)
-      a_range = aranges[mapindex];
-    if (!bflag)
-      min_b = bmins[mapindex];
-    if (!hflag)
-      b_range = branges[mapindex];
-    if (!Force)
+    st->mapindex=atoi(s);
+    if ((st->mapindex >= NUMMAPS) || (st->mapindex < 0))
+      usage(st);
+    st->map = Maps[st->mapindex];
+    st->deriv = Derivs[st->mapindex];
+    if (!st->aflag)
+      st->min_a = amins[st->mapindex];
+    if (!st->wflag)
+      st->a_range = aranges[st->mapindex];
+    if (!st->bflag)
+      st->min_b = bmins[st->mapindex];
+    if (!st->hflag)
+      st->b_range = branges[st->mapindex];
+    if (!st->Force)
       for (i=0;i<FUNCMAXINDEX;i++)
-       Forcing[i] = mapindex;
+        st->Forcing[i] = st->mapindex;
   }
 
-  outname = get_string_resource("outputFile", "Integer");
+  st->outname = get_string_resource(st->dpy, "outputFile", "Integer");
 
-  if (get_boolean_resource("beNegative", "Boolean"))
-    negative--;
+  if (get_boolean_resource(st->dpy, "beNegative", "Boolean"))
+    st->negative--;
 
-  rgb_max = get_integer_resource("rgbMax", "Integer");
-  spinlength = get_integer_resource("spinLength", "Integer");
-  show = get_boolean_resource("show", "Boolean");
+  st->rgb_max = get_integer_resource(st->dpy, "rgbMax", "Integer");
+  st->spinlength = get_integer_resource(st->dpy, "spinLength", "Integer");
+  st->show = get_boolean_resource(st->dpy, "show", "Boolean");
 
-  s = get_string_resource("aRange", "Float");
+  s = get_string_resource(st->dpy, "aRange", "Float");
   if (s && *s) {
-    a_range = atof(s); wflag++;
+    st->a_range = atof(s); st->wflag++;
   }
 
-  max_a = min_a + a_range;
-  max_b = min_b + b_range;
+  st->max_a = st->min_a + st->a_range;
+  st->max_b = st->min_b + st->b_range;
 
-  a_minimums[0] = min_a; b_minimums[0] = min_b;
-  a_maximums[0] = max_a; b_maximums[0] = max_b;
+  st->a_minimums[0] = st->min_a; st->b_minimums[0] = st->min_b;
+  st->a_maximums[0] = st->max_a; st->b_maximums[0] = st->max_b;
 
-  if (Force)
-    if (maxindex == funcmaxindex)
-      for (findex=0;findex<funcmaxindex;findex++)
-       check_params(Forcing[findex],forcing[findex]);
+  if (st->Force)
+    if (st->maxindex == st->funcmaxindex)
+      for (findex=0;findex<st->funcmaxindex;findex++)
+        check_params(st, st->Forcing[findex],st->forcing[findex]);
     else
       fprintf(stderr, "Warning! Unable to check parameters\n");
   else
-    check_params(mapindex,2);
+    check_params(st, st->mapindex,2);
 }
 
 static void
-check_params(int mapnum, int parnum)
+check_params(struct state *st, int mapnum, int parnum)
 {
 
   if (parnum != 1) {
-      if ((max_a > pmaxs[mapnum]) || (min_a < pmins[mapnum])) {
-    fprintf(stderr, "Warning! Parameter 'a' out of range.\n");
-    fprintf(stderr, "You have requested a range of (%f,%f).\n",
-      min_a,max_a);
-    fprintf(stderr, "Valid range is (%f,%f).\n",
-      pmins[mapnum],pmaxs[mapnum]);
-      }
+    if ((st->max_a > pmaxs[mapnum]) || (st->min_a < pmins[mapnum])) {
+      fprintf(stderr, "Warning! Parameter 'a' out of range.\n");
+      fprintf(stderr, "You have requested a range of (%f,%f).\n",
+              st->min_a,st->max_a);
+      fprintf(stderr, "Valid range is (%f,%f).\n",
+              pmins[mapnum],pmaxs[mapnum]);
+    }
   }
   if (parnum != 0) {
-      if ((max_b > pmaxs[mapnum]) || (min_b < pmins[mapnum])) {
-    fprintf(stderr, "Warning! Parameter 'b' out of range.\n");
-    fprintf(stderr, "You have requested a range of (%f,%f).\n",
-      min_b,max_b);
-    fprintf(stderr, "Valid range is (%f,%f).\n",
-      pmins[mapnum],pmaxs[mapnum]);
-      }
+    if ((st->max_b > pmaxs[mapnum]) || (st->min_b < pmins[mapnum])) {
+      fprintf(stderr, "Warning! Parameter 'b' out of range.\n");
+      fprintf(stderr, "You have requested a range of (%f,%f).\n",
+              st->min_b,st->max_b);
+      fprintf(stderr, "Valid range is (%f,%f).\n",
+              pmins[mapnum],pmaxs[mapnum]);
+    }
   }
 }
 
 static void
-usage(void)
+usage(struct state *st)
 {
-    fprintf(stderr,"lyap [-BLs][-W#][-H#][-a#][-b#][-w#][-h#][-x xstart]\n");
-    fprintf(stderr,"\t[-M#][-S#][-D#][-f string][-r#][-O#][-C#][-c#][-m#]\n");
+  fprintf(stderr,"lyap [-BLs][-W#][-H#][-a#][-b#][-w#][-h#][-x xstart]\n");
+  fprintf(stderr,"\t[-M#][-S#][-D#][-f string][-r#][-O#][-C#][-c#][-m#]\n");
 #ifdef MAPS
-    fprintf(stderr,"\t[-F string]\n");
+  fprintf(stderr,"\t[-F string]\n");
 #endif
-    fprintf(stderr,"\tWhere: -C# specifies the minimum color index\n");
-    fprintf(stderr,"\t      -r# specifies the maxzimum rgb value\n");
-    fprintf(stderr,"\t      -u displays this message\n");
-    fprintf(stderr,"\t      -a# specifies the minimum horizontal parameter\n");
-    fprintf(stderr,"\t      -b# specifies the minimum vertical parameter\n");
-    fprintf(stderr,"\t      -w# specifies the horizontal parameter range\n");
-    fprintf(stderr,"\t      -h# specifies the vertical parameter range\n");
-    fprintf(stderr,"\t      -D# specifies the dwell\n");
-    fprintf(stderr,"\t      -S# specifies the settle\n");
-    fprintf(stderr,"\t      -H# specifies the initial window height\n");
-    fprintf(stderr,"\t      -W# specifies the initial window width\n");
-    fprintf(stderr,"\t      -O# specifies the color offset\n");
-    fprintf(stderr,"\t      -c# specifies the desired color wheel\n");
-    fprintf(stderr,"\t      -m# specifies the desired map (0-4)\n");
-    fprintf(stderr,"\t      -f aabbb specifies a forcing function of 00111\n");
+  fprintf(stderr,"\tWhere: -C# specifies the minimum color index\n");
+  fprintf(stderr,"\t       -r# specifies the maxzimum rgb value\n");
+  fprintf(stderr,"\t       -u displays this message\n");
+  fprintf(stderr,"\t       -a# specifies the minimum horizontal parameter\n");
+  fprintf(stderr,"\t       -b# specifies the minimum vertical parameter\n");
+  fprintf(stderr,"\t       -w# specifies the horizontal parameter range\n");
+  fprintf(stderr,"\t       -h# specifies the vertical parameter range\n");
+  fprintf(stderr,"\t       -D# specifies the dwell\n");
+  fprintf(stderr,"\t       -S# specifies the settle\n");
+  fprintf(stderr,"\t       -H# specifies the initial window height\n");
+  fprintf(stderr,"\t       -W# specifies the initial window width\n");
+  fprintf(stderr,"\t       -O# specifies the color offset\n");
+  fprintf(stderr,"\t       -c# specifies the desired color wheel\n");
+  fprintf(stderr,"\t       -m# specifies the desired map (0-4)\n");
+  fprintf(stderr,"\t       -f aabbb specifies a forcing function of 00111\n");
 #ifdef MAPS
-    fprintf(stderr,"\t      -F 00111 specifies the function forcing function\n");
+  fprintf(stderr,"\t       -F 00111 specifies the function forcing function\n");
 #endif
-    fprintf(stderr,"\t      -L indicates use log(x)+log(y) rather than log(xy)\n");
-    fprintf(stderr,"\tDuring display :\n");
-    fprintf(stderr,"\t    Use the mouse to zoom in on an area\n");
-    fprintf(stderr,"\t    e or E recalculates color indices\n");
-    fprintf(stderr,"\t    f or F saves exponents to a file\n");
-    fprintf(stderr,"\t    KJmn increase/decrease minimum negative exponent\n");
-    fprintf(stderr,"\t    r or R redraws\n");
-    fprintf(stderr,"\t    s or S spins the colorwheel\n");
-    fprintf(stderr,"\t    w or W changes the color wheel\n");
-    fprintf(stderr,"\t    x or X clears the window\n");
-    fprintf(stderr,"\t    q or Q exits\n");
-    exit(1);
+  fprintf(stderr,"\t       -L indicates use log(x)+log(y) rather than log(xy)\n");
+  fprintf(stderr,"\tDuring display :\n");
+  fprintf(stderr,"\t       Use the mouse to zoom in on an area\n");
+  fprintf(stderr,"\t       e or E recalculates color indices\n");
+  fprintf(stderr,"\t       f or F saves exponents to a file\n");
+  fprintf(stderr,"\t       KJmn increase/decrease minimum negative exponent\n");
+  fprintf(stderr,"\t       r or R redraws\n");
+  fprintf(stderr,"\t       s or S spins the colorwheel\n");
+  fprintf(stderr,"\t       w or W changes the color wheel\n");
+  fprintf(stderr,"\t       x or X clears the window\n");
+  fprintf(stderr,"\t       q or Q exits\n");
+  exit(1);
 }
 
 static void
-Cycle_frames(void)
+Cycle_frames(struct state *st)
 {
-  static int i;
-  for (i=0;i<=maxframe;i++)
-    redraw(exponents[i], expind[i], 1);
+  int i;
+  for (i=0;i<=st->maxframe;i++)
+    redraw(st, st->exponents[i], st->expind[i], 1);
 }
 
+#if 0
 static void
-Spin(Window w)
+Spin(struct state *st)
 {
-  static int i, j;
+  int i, j;
   long tmpxcolor;
 
-  if (displayplanes > 1) {
-    for (j=0;j<spinlength;j++) {
-      tmpxcolor = Colors[mincolindex].pixel;
-      for (i=mincolindex;i<numcolors-1;i++)
-       Colors[i].pixel = Colors[i+1].pixel;
-      Colors[numcolors-1].pixel = tmpxcolor;
-      XStoreColors(dpy, cmap, Colors, numcolors);
+  if (!mono_p) {
+    for (j=0;j<st->spinlength;j++) {
+      tmpxcolor = st->Colors[st->mincolindex].pixel;
+      for (i=st->mincolindex;i<st->numcolors-1;i++)
+        st->Colors[i].pixel = st->Colors[i+1].pixel;
+      st->Colors[st->numcolors-1].pixel = tmpxcolor;
+      XStoreColors(st->dpy, st->cmap, st->Colors, st->numcolors);
     }
-    for (j=0;j<spinlength;j++) {
-      tmpxcolor = Colors[numcolors-1].pixel;
-      for (i=numcolors-1;i>mincolindex;i--)
-       Colors[i].pixel = Colors[i-1].pixel;
-      Colors[mincolindex].pixel = tmpxcolor;
-      XStoreColors(dpy, cmap, Colors, numcolors);
+    for (j=0;j<st->spinlength;j++) {
+      tmpxcolor = st->Colors[st->numcolors-1].pixel;
+      for (i=st->numcolors-1;i>st->mincolindex;i--)
+        st->Colors[i].pixel = st->Colors[i-1].pixel;
+      st->Colors[st->mincolindex].pixel = tmpxcolor;
+      XStoreColors(st->dpy, st->cmap, st->Colors, st->numcolors);
     }
   }
 }
+#endif
 
-static void
-Getkey(XKeyEvent *event)
+static Bool
+Getkey(struct state *st, XKeyEvent *event)
 {
   unsigned char key;
-  static int i;
+  int i;
   if (XLookupString(event, (char *)&key, sizeof(key), (KeySym *)0,
-           (XComposeStatus *) 0) > 0)
+                    (XComposeStatus *) 0) > 0)
+
+    if (st->reset_countdown)
+      st->reset_countdown = st->linger;
+
     switch (key) {
-  case '<': dwell /= 2; if (dwell < 1) dwell = 1; break;
-  case '>': dwell *= 2; break;
-  case '[': settle /= 2; if (settle < 1) settle = 1; break;
-  case ']': settle *= 2; break;
-  case 'd': go_down(); break;
-  case 'D': FlushBuffer(); break;
-  case 'e':
-  case 'E': FlushBuffer();
-      dorecalc = (!dorecalc);
-      if (dorecalc)
-      recalc();
+    case '<': st->dwell /= 2; if (st->dwell < 1) st->dwell = 1; return True;
+    case '>': st->dwell *= 2; return True;
+    case '[': st->settle /= 2; if (st->settle < 1) st->settle = 1; return True;
+    case ']': st->settle *= 2; return True;
+    case 'd': go_down(st); return True;
+    case 'D': FlushBuffer(st); return True;
+    case 'e':
+    case 'E': FlushBuffer(st);
+      st->dorecalc = (!st->dorecalc);
+      if (st->dorecalc)
+        recalc(st);
       else {
-      maxexp = minlyap; minexp = -1.0 * minlyap;
+        st->maxexp = st->minlyap; st->minexp = -1.0 * st->minlyap;
       }
-      redraw(exponents[frame], expind[frame], 1);
-      break;
-  case 'f':
-  case 'F': save_to_file(); break;
-  case 'i': if (stripe_interval > 0) {
-      stripe_interval--;
-       if (displayplanes > 1) {
-           init_color();
-       }
+      redraw(st, st->exponents[st->frame], st->expind[st->frame], 1);
+      return True;
+    case 'f':
+      /*  case 'F': save_to_file(); return True;*/
+    case 'i': if (st->stripe_interval > 0) {
+        st->stripe_interval--;
+        if (!mono_p) {
+          init_color(st);
+        }
       }
-      break;
-  case 'I': stripe_interval++;
-      if (displayplanes > 1) {
-       init_color();
+      return True;
+    case 'I': st->stripe_interval++;
+      if (!mono_p) {
+        init_color(st);
       }
-      break;
-  case 'K': if (minlyap > 0.05)
-      minlyap -= 0.05;
-       break;
-  case 'J': minlyap += 0.05;
-       break;
-  case 'm': mapindex++;
-                 if (mapindex >= NUMMAPS)
-                       mapindex=0;
-                 map = Maps[mapindex];
-                 deriv = Derivs[mapindex];
-      if (!aflag)
-                       min_a = amins[mapindex];
-                 if (!wflag)
-                       a_range = aranges[mapindex];
-                 if (!bflag)
-                       min_b = bmins[mapindex];
-                 if (!hflag)
-                       b_range = branges[mapindex];
-                 if (!Force)
-                       for (i=0;i<FUNCMAXINDEX;i++)
-                            Forcing[i] = mapindex;
-           max_a = min_a + a_range;
-           max_b = min_b + b_range;
-           a_minimums[0] = min_a; b_minimums[0] = min_b;
-           a_maximums[0] = max_a; b_maximums[0] = max_b;
-           a_inc = a_range / (double)width;
-           b_inc = b_range / (double)height;
-           point.x = -1;
-           point.y = 0;
-           a = rubber_data.p_min = min_a;
-           b = rubber_data.q_min = min_b;
-           rubber_data.p_max = max_a;
-           rubber_data.q_max = max_b;
-                 Clear();
-                 break;
-  case 'M': if (minlyap > 0.005)
-      minlyap -= 0.005;
-       break;
-  case 'N': minlyap += 0.005;
-       break;
-  case 'p':
-  case 'P': negative = (!negative);
-      FlushBuffer(); redraw(exponents[frame], expind[frame], 1);
-      break;
-  case 'r': FlushBuffer(); redraw(exponents[frame], expind[frame], 1);
-      break;
-  case 'R': FlushBuffer(); Redraw(); break;
-  case 's':
-       spinlength=spinlength/2;
-  case 'S': if (displayplanes > 1)
-      Spin(canvas);
-       spinlength=spinlength*2; break;
-  case 'u': go_back(); break;
-  case 'U': go_init(); break;
-  case 'v':
-  case 'V': print_values(); break;
-  case 'W': if (numwheels < MAXWHEELS)
-      numwheels++;
-       else
-      numwheels = 0;
-       if (displayplanes > 1) {
-       init_color();
-       }
-       break;
-  case 'w': if (numwheels > 0)
-      numwheels--;
-       else
-      numwheels = MAXWHEELS;
-       if (displayplanes > 1) {
-       init_color();
-       }
-       break;
-  case 'x': Clear(); break;
-  case 'X': Destroy_frame(); break;
-  case 'z': Cycle_frames(); redraw(exponents[frame], expind[frame], 1);
-      break;
-  case 'Z': while (!XPending(dpy)) Cycle_frames();
-      redraw(exponents[frame], expind[frame], 1); break;
-  case 'q':
-  case 'Q': exit(0); break;
-  case '?':
-  case 'h':
-  case 'H': print_help(); break;
-  default:  break;
-  }
+      return True;
+    case 'K': if (st->minlyap > 0.05)
+        st->minlyap -= 0.05;
+      return True;
+    case 'J': st->minlyap += 0.05;
+      return True;
+    case 'm': st->mapindex++;
+      if (st->mapindex >= NUMMAPS)
+        st->mapindex=0;
+      st->map = Maps[st->mapindex];
+      st->deriv = Derivs[st->mapindex];
+      if (!st->aflag)
+        st->min_a = amins[st->mapindex];
+      if (!st->wflag)
+        st->a_range = aranges[st->mapindex];
+      if (!st->bflag)
+        st->min_b = bmins[st->mapindex];
+      if (!st->hflag)
+        st->b_range = branges[st->mapindex];
+      if (!st->Force)
+        for (i=0;i<FUNCMAXINDEX;i++)
+          st->Forcing[i] = st->mapindex;
+      st->max_a = st->min_a + st->a_range;
+      st->max_b = st->min_b + st->b_range;
+      st->a_minimums[0] = st->min_a; st->b_minimums[0] = st->min_b;
+      st->a_maximums[0] = st->max_a; st->b_maximums[0] = st->max_b;
+      st->a_inc = st->a_range / (double)st->width;
+      st->b_inc = st->b_range / (double)st->height;
+      st->point.x = -1;
+      st->point.y = 0;
+      st->a = /*st->rubber_data.p_min = */st->min_a;
+      st->b = /*st->rubber_data.q_min = */st->min_b;
+/*      st->rubber_data.p_max = st->max_a;
+      st->rubber_data.q_max = st->max_b;*/
+      Clear(st);
+      return True;
+    case 'M': if (st->minlyap > 0.005)
+        st->minlyap -= 0.005;
+      return True;
+    case 'N': st->minlyap += 0.005;
+      return True;
+    case 'p':
+    case 'P': st->negative = (!st->negative);
+      FlushBuffer(st); redraw(st, st->exponents[st->frame], 
+                              st->expind[st->frame], 1);
+      return True;
+    case 'r': FlushBuffer(st); redraw(st, st->exponents[st->frame], 
+                                      st->expind[st->frame], 1);
+      return True;
+    case 'R': FlushBuffer(st); Redraw(st); return True;
+    case 's':
+      st->spinlength=st->spinlength/2;
+#if 0
+    case 'S': if (!mono_p)
+        Spin(st);
+      st->spinlength=st->spinlength*2; return True;
+#endif
+    case 'u': go_back(st); return True;
+    case 'U': go_init(st); return True;
+    case 'v':
+    case 'V': print_values(st); return True;
+    case 'W': if (st->numwheels < MAXWHEELS)
+        st->numwheels++;
+      else
+        st->numwheels = 0;
+      if (!mono_p) {
+        init_color(st);
+      }
+      return True;
+    case 'w': if (st->numwheels > 0)
+        st->numwheels--;
+      else
+        st->numwheels = MAXWHEELS;
+      if (!mono_p) {
+        init_color(st);
+      }
+      return True;
+    case 'x': Clear(st); return True;
+    case 'X': Destroy_frame(st); return True;
+    case 'z': Cycle_frames(st); redraw(st, st->exponents[st->frame], 
+                                       st->expind[st->frame], 1);
+      return True;
+#if 0
+    case 'Z': while (!XPending(st->dpy)) Cycle_frames(st);
+      redraw(st, st->exponents[st->frame], st->expind[st->frame], 1); 
+      return True;
+#endif
+    case 'q':
+    case 'Q': exit(0); return True;
+    case '?':
+    case 'h':
+    case 'H': print_help(st); return True;
+    default:  return False;
+    }
+
+  return False;
 }
 
 /* Here's where we index into a color map. After the Lyapunov exponent is
- * calculated, it is used to determine what color to use for that point.
- * I suppose there are a lot of ways to do this. I used the following :
- * if it's non-negative then there's a reserved area at the lower range
- * of the color map that i index into. The ratio of some "minimum exponent
- * value" and the calculated value is used as a ratio of how high to index
- * into this reserved range. Usually these colors are dark red (see init_color).
- * If the exponent is negative, the same ratio (expo/minlyap) is used to index
- * into the remaining portion of the colormap (which is usually some light
- * shades of color or a rainbow wheel). The coloring scheme can actually make
- * a great deal of difference in the quality of the picture. Different colormaps
- * bring out different details of the dynamics while different indexing
- * algorithms also greatly effect what details are seen. Play around with this.
+ * calculated, it is used to determine what color to use for that point.  I
+ * suppose there are a lot of ways to do this. I used the following : if it's
+ * non-negative then there's a reserved area at the lower range of the color
+ * map that i index into. The ratio of some "minimum exponent value" and the
+ * calculated value is used as a ratio of how high to index into this reserved
+ * range. Usually these colors are dark red (see init_color).  If the exponent
+ * is negative, the same ratio (expo/minlyap) is used to index into the
+ * remaining portion of the colormap (which is usually some light shades of
+ * color or a rainbow wheel). The coloring scheme can actually make a great
+ * deal of difference in the quality of the picture. Different colormaps bring
+ * out different details of the dynamics while different indexing algorithms
+ * also greatly effect what details are seen. Play around with this.
  */
 static int
-sendpoint(double expo)
+sendpoint(struct state *st, double expo)
 {
-  static int index;
-  static double tmpexpo;
+  double tmpexpo;
 
-  point.x++;
-  tmpexpo = (negative) ? expo : -1.0 * expo;
+  if (st->maxcolor > MAXCOLOR)
+    abort();
+
+#if 0
+  /* The relationship st->minexp <= expo <= maxexp should always be true. This
+     test enforces that. But maybe not enforcing it makes better pictures. */
+  if (expo < st->minexp)
+    expo = st->minexp;
+  else if (expo > maxexp)
+    expo = maxexp;
+#endif
+
+  st->point.x++;
+  tmpexpo = (st->negative) ? expo : -1.0 * expo;
   if (tmpexpo > 0) {
-    if (displayplanes >1) {
-       index = (int)(tmpexpo*lowrange/maxexp);
-       index = (index % lowrange) + startcolor;
+    if (!mono_p) {
+      st->sendpoint_index = (int)(tmpexpo*st->lowrange/st->maxexp);
+      st->sendpoint_index = ((st->sendpoint_index % st->lowrange) + 
+                             st->startcolor);
     }
     else
-       index = 0;
+      st->sendpoint_index = 0;
   }
   else {
-    if (displayplanes >1) {
-       index = (int)(tmpexpo*numfreecols/minexp);
-       index = (index % numfreecols) + mincolindex;
+    if (!mono_p) {
+      st->sendpoint_index = (int)(tmpexpo*st->numfreecols/st->minexp);
+      st->sendpoint_index = ((st->sendpoint_index % st->numfreecols)
+                             + st->mincolindex);
     }
     else
-       index = 1;
+      st->sendpoint_index = 1;
+  }
+  BufferPoint(st, st->sendpoint_index, st->point.x, st->point.y);
+  if (st->save) {
+    if (st->frame > MAXFRAMES)
+      abort();
+    st->exponents[st->frame][st->expind[st->frame]++] = expo;
   }
-    BufferPoint(dpy, canvas, index, point.x, point.y);
-  if (save)
-    exponents[frame][expind[frame]++] = expo;
-  if (point.x >= width) {
-    point.y++;
-    point.x = 0;
-    if (save) {
-      b += b_inc;
-      a = min_a;
+  if (st->point.x >= st->width) {
+    st->point.y++;
+    st->point.x = 0;
+    if (st->save) {
+      st->b += st->b_inc;
+      st->a = st->min_a;
     }
-    if (point.y >= height)
+    if (st->point.y >= st->height)
       return FALSE;
     else
       return TRUE;
@@ -1450,229 +1032,144 @@ sendpoint(double expo)
   return TRUE;
 }
 
-static void
-redisplay (Window w, XExposeEvent *event)
-{
-  /*
-  * Extract the exposed area from the event and copy
-  * from the saved pixmap to the window.
-  */
-  XCopyArea(dpy, pixmap, canvas, Data_GC[0],
-          event->x, event->y, event->width, event->height,
-          event->x, event->y);
-}
 
 static void
-resize(void)
+resize(struct state *st)
 {
   Window r;
   int n, x, y;
   unsigned int bw, d, new_w, new_h;
 
-  XGetGeometry(dpy,canvas,&r,&x,&y,&new_w,&new_h,&bw,&d);
-  if ((new_w == width) && (new_h == height))
+  XGetGeometry(st->dpy,st->canvas,&r,&x,&y,&new_w,&new_h,&bw,&d);
+  if ((new_w == st->width) && (new_h == st->height))
     return;
-  width = new_w; height = new_h;
-  XClearWindow(dpy, canvas);
-  if (pixmap)
-    XFreePixmap(dpy, pixmap);
-  pixmap = XCreatePixmap(dpy, DefaultRootWindow(dpy),
-      width, height, DefaultDepth(dpy, screen));
-  a_inc = a_range / (double)width;
-  b_inc = b_range / (double)height;
-  point.x = -1;
-  point.y = 0;
-  run = 1;
-  a = rubber_data.p_min = min_a;
-  b = rubber_data.q_min = min_b;
-  rubber_data.p_max = max_a;
-  rubber_data.q_max = max_b;
-  freemem();
-  setupmem();
-       for (n=0;n<MAXFRAMES;n++)
-    if ((n <= maxframe) && (n != frame))
-       resized[n] = 1;
-  InitBuffer();
-  Clear();
-  Redraw();
+  st->width = new_w; st->height = new_h;
+  XClearWindow(st->dpy, st->canvas);
+#ifdef BACKING_PIXMAP
+  if (st->pixmap)
+    XFreePixmap(st->dpy, st->pixmap);
+  st->pixmap = XCreatePixmap(st->dpy, st->canvas, st->width, st->height, d);
+#endif
+  st->a_inc = st->a_range / (double)st->width;
+  st->b_inc = st->b_range / (double)st->height;
+  st->point.x = -1;
+  st->point.y = 0;
+  st->run = 1;
+  st->a = /*st->rubber_data.p_min = */st->min_a;
+  st->b = /*st->rubber_data.q_min = */st->min_b;
+/*  st->rubber_data.p_max = st->max_a;
+  st->rubber_data.q_max = st->max_b;*/
+  freemem(st);
+  setupmem(st);
+  for (n=0;n<MAXFRAMES;n++)
+    if ((n <= st->maxframe) && (n != st->frame))
+      st->resized[n] = 1;
+  InitBuffer(st);
+  Clear(st);
+  Redraw(st);
 }
 
 static void
-redraw(double *exparray, int index, int cont)
+redraw(struct state *st, double *exparray, int index, int cont)
 {
-  static int i;
-  static int x_sav, y_sav;
+  int i, x_sav, y_sav;
 
-  x_sav = point.x;
-  y_sav = point.y;
+  x_sav = st->point.x;
+  y_sav = st->point.y;
 
-  point.x = -1;
-  point.y = 0;
+  st->point.x = -1;
+  st->point.y = 0;
 
-  save=0;
+  st->save=0;
   for (i=0;i<index;i++)
-    sendpoint(exparray[i]);
-  save=1;
+    sendpoint(st, exparray[i]);
+  st->save=1;
 
   if (cont) {
-    point.x = x_sav;
-    point.y = y_sav;
+    st->point.x = x_sav;
+    st->point.y = y_sav;
   }
   else {
-    a = point.x * a_inc + min_a;
-    b = point.y * b_inc + min_b;
+    st->a = st->point.x * st->a_inc + st->min_a;
+    st->b = st->point.y * st->b_inc + st->min_b;
   }
-  FlushBuffer();
+  FlushBuffer(st);
 }
 
 static void
-Redraw(void)
+Redraw(struct state *st)
 {
-  FlushBuffer();
-       point.x = -1;
-       point.y = 0;
-  run = 1;
-       a = min_a;
-       b = min_b;
-  expind[frame] = 0;
-  resized[frame] = 0;
+  FlushBuffer(st);
+  st->point.x = -1;
+  st->point.y = 0;
+  st->run = 1;
+  st->a = st->min_a;
+  st->b = st->min_b;
+  st->expind[st->frame] = 0;
+  st->resized[st->frame] = 0;
 }
 
-/* Store color pics in PPM format and monochrome in PGM */
 static void
-save_to_file(void)
+recalc(struct state *st)
 {
-  FILE *outfile;
-  unsigned char c;
-  XImage *ximage;
-  static int i,j;
-  struct Colormap {
-    unsigned char red;
-    unsigned char green;
-    unsigned char blue;
-  };
-  struct Colormap *colormap=NULL;
-
-  if (colormap)
-    free(colormap);
-  if ((colormap=
-    (struct Colormap *)malloc(sizeof(struct Colormap)*maxcolor))
-      == NULL) {
-    fprintf(stderr,"Error malloc'ing colormap array\n");
-    exit(-1);
-  }
-  outfile = fopen(outname,"w");
-  if(!outfile) {
-    perror(outname);
-    exit(-1);
-  }
-
-  ximage=XGetImage(dpy, pixmap, 0, 0, width, height, AllPlanes, XYPixmap);
-
-  if (displayplanes > 1) {
-    for (i=0;i<maxcolor;i++) {
-      colormap[i].red=(unsigned char)(Colors[i].red >> 8);
-      colormap[i].green=(unsigned char)(Colors[i].green >> 8);
-      colormap[i].blue =(unsigned char)(Colors[i].blue >> 8);
-    }
-    fprintf(outfile,"P%d %d %d\n",6,width,height);
-  }
-  else
-    fprintf(outfile,"P%d %d %d\n",5,width,height);
-  fprintf(outfile,"# settle=%d dwell=%d start_x=%f\n",settle,dwell,
-       start_x);
-  fprintf(outfile,"# min_a=%f  a_rng=%f         max_a=%f\n",min_a,a_range,max_a);
-  fprintf(outfile,"# min_b=%f  b_rng=%f         max_b=%f\n",min_b,b_range,max_b);
-  if (Rflag)
-    fprintf(outfile,"# pseudo-random forcing\n");
-  else if (force) {
-    fprintf(outfile,"# periodic forcing=");
-    for (i=0;i<maxindex;i++) {
-      fprintf(outfile,"%d",forcing[i]);
-    }
-    fprintf(outfile,"\n");
-  }
-  else
-    fprintf(outfile,"# periodic forcing=01\n");
-  if (Force) {
-    fprintf(outfile,"# function forcing=");
-    for (i=0;i<funcmaxindex;i++) {
-      fprintf(outfile,"%d",Forcing[i]);
-    }
-    fprintf(outfile,"\n");
-  }
-  fprintf(outfile,"%d\n",numcolors-1);
-
-  for (j=0;j<height;j++)
-      for (i=0;i<width;i++) {
-    c = (unsigned char)XGetPixel(ximage,i,j);
-    if (displayplanes > 1)
-       fwrite((char *)&colormap[c],sizeof colormap[0],1,outfile);
-    else
-       fwrite((char *)&c,sizeof c,1,outfile);
-      }
-  fclose(outfile);
-}
+  int i;
 
-static void
-recalc(void)
-{
-  static int i, x, y;
-
-  minexp = maxexp = 0.0;
-  x = y = 0;
-  for (i=0;i<expind[frame];i++) {
-    if (exponents[frame][i] < minexp)
-      minexp = exponents[frame][i];
-    if (exponents[frame][i] > maxexp)
-      maxexp = exponents[frame][i];
+  st->minexp = st->maxexp = 0.0;
+  for (i=0;i<st->expind[st->frame];i++) {
+    if (st->exponents[st->frame][i] < st->minexp)
+      st->minexp = st->exponents[st->frame][i];
+    if (st->exponents[st->frame][i] > st->maxexp)
+      st->maxexp = st->exponents[st->frame][i];
   }
 }
 
 static void
-Clear(void)
+Clear(struct state *st)
 {
-      XClearWindow(dpy, canvas);
-  XCopyArea(dpy, canvas, pixmap, Data_GC[0],
-           0, 0, width, height, 0, 0);
-  InitBuffer();
+  XClearWindow(st->dpy, st->canvas);
+#ifdef BACKING_PIXMAP
+  XCopyArea(st->dpy, st->canvas, st->pixmap, st->Data_GC[0],
+            0, 0, st->width, st->height, 0, 0);
+#endif
+  InitBuffer(st);
 }
 
 static void
-show_defaults(void)
+show_defaults(struct state *st)
 {
 
-  printf("Width=%d  Height=%d  numcolors=%d  settle=%d dwell=%d\n",
-    width,height,numcolors,settle,dwell);
-  printf("min_a=%f  a_range=%f max_a=%f\n", min_a,a_range,max_a);
-  printf("min_b=%f  b_range=%f max_b=%f\n", min_b,b_range,max_b);
-  printf("minlyap=%f  minexp=%f         maxexp=%f\n", minlyap,minexp,maxexp);
+  printf("Width=%d  Height=%d  numcolors=%d  settle=%d  dwell=%d\n",
+         st->width,st->height,st->numcolors,st->settle,st->dwell);
+  printf("min_a=%f  a_range=%f  max_a=%f\n", st->min_a,st->a_range,st->max_a);
+  printf("min_b=%f  b_range=%f  max_b=%f\n", st->min_b,st->b_range,st->max_b);
+  printf("minlyap=%f  minexp=%f  maxexp=%f\n", st->minlyap,st->minexp,
+         st->maxexp);
   exit(0);
 }
 
+#if 0
 static void
-CreateXorGC(void)
+CreateXorGC(struct state *st)
 {
   XGCValues values;
 
-  values.foreground = foreground;
-  values.line_style = LineSolid;
+  values.foreground = st->foreground;
   values.function = GXxor;
-  RubberGC = XCreateGC(dpy, DefaultRootWindow(dpy),
-       GCForeground | GCBackground | GCFunction | GCLineStyle, &values);
+  st->RubberGC = XCreateGC(st->dpy, st->canvas,
+                           GCForeground | GCFunction, &values);
 }
 
 static void
-StartRubberBand(Window w, image_data_t *data, XEvent *event)
+StartRubberBand(struct state *st, image_data_t *data, XEvent *event)
 {
   XPoint corners[5];
 
-  nostart = 0;
+  st->nostart = 0;
   data->rubber_band.last_x = data->rubber_band.start_x = event->xbutton.x;
   data->rubber_band.last_y = data->rubber_band.start_y = event->xbutton.y;
   SetupCorners(corners, data);
-  XDrawLines(dpy, canvas, RubberGC,
-      corners, sizeof(corners) / sizeof(corners[0]), CoordModeOrigin);
+  XDrawLines(st->dpy, st->canvas, st->RubberGC,
+             corners, sizeof(corners) / sizeof(corners[0]), CoordModeOrigin);
 }
 
 static void
@@ -1690,42 +1187,42 @@ SetupCorners(XPoint *corners, image_data_t *data)
 }
 
 static void
-TrackRubberBand(Window w, image_data_t *data, XEvent *event)
+TrackRubberBand(struct state *st, image_data_t *data, XEvent *event)
 {
   XPoint corners[5];
   int xdiff, ydiff;
 
-  if (nostart)
+  if (st->nostart)
     return;
   SetupCorners(corners, data);
-  XDrawLines(dpy, canvas, RubberGC,
-      corners, sizeof(corners) / sizeof(corners[0]), CoordModeOrigin);
+  XDrawLines(st->dpy, st->canvas, st->RubberGC,
+             corners, sizeof(corners) / sizeof(corners[0]), CoordModeOrigin);
   ydiff = event->xbutton.y - data->rubber_band.start_y;
   xdiff = event->xbutton.x - data->rubber_band.start_x;
   data->rubber_band.last_x = data->rubber_band.start_x + xdiff;
   data->rubber_band.last_y = data->rubber_band.start_y + ydiff;
   if (data->rubber_band.last_y < data->rubber_band.start_y ||
       data->rubber_band.last_x < data->rubber_band.start_x)
-  {
-    data->rubber_band.last_y = data->rubber_band.start_y;
-    data->rubber_band.last_x = data->rubber_band.start_x;
-  }
+    {
+      data->rubber_band.last_y = data->rubber_band.start_y;
+      data->rubber_band.last_x = data->rubber_band.start_x;
+    }
   SetupCorners(corners, data);
-  XDrawLines(dpy, canvas, RubberGC,
-      corners, sizeof(corners) / sizeof(corners[0]), CoordModeOrigin);
+  XDrawLines(st->dpy, st->canvas, st->RubberGC,
+             corners, sizeof(corners) / sizeof(corners[0]), CoordModeOrigin);
 }
 
 static void
-EndRubberBand(Window w, image_data_t *data, XEvent *event)
+EndRubberBand(struct state *st, image_data_t *data, XEvent *event)
 {
   XPoint corners[5];
   XPoint top, bot;
   double delta, diff;
 
-  nostart = 1;
+  st->nostart = 1;
   SetupCorners(corners, data);
-  XDrawLines(dpy, canvas, RubberGC,
-      corners, sizeof(corners) / sizeof(corners[0]), CoordModeOrigin);
+  XDrawLines(st->dpy, st->canvas, st->RubberGC,
+             corners, sizeof(corners) / sizeof(corners[0]), CoordModeOrigin);
   if (data->rubber_band.start_x >= data->rubber_band.last_x ||
       data->rubber_band.start_y >= data->rubber_band.last_y)
     return;
@@ -1734,232 +1231,700 @@ EndRubberBand(Window w, image_data_t *data, XEvent *event)
   top.y = data->rubber_band.start_y;
   bot.y = data->rubber_band.last_y;
   diff = data->q_max - data->q_min;
-  delta = (double)top.y / (double)height;
+  delta = (double)top.y / (double)st->height;
   data->q_min += diff * delta;
-  delta = (double)(height - bot.y) / (double)height;
+  delta = (double)(st->height - bot.y) / (double)st->height;
   data->q_max -= diff * delta;
   diff = data->p_max - data->p_min;
-  delta = (double)top.x / (double)width;
+  delta = (double)top.x / (double)st->width;
   data->p_min += diff * delta;
-  delta = (double)(width - bot.x) / (double)width;
+  delta = (double)(st->width - bot.x) / (double)st->width;
   data->p_max -= diff * delta;
-  fflush(stdout);
-  set_new_params(w, data);
+  set_new_params(st, data);
 }
 
 static void
-set_new_params(Window w, image_data_t *data)
+set_new_params(struct state *st, image_data_t *data)
 {
-  frame = (maxframe + 1) % MAXFRAMES;
-  if (frame > maxframe)
-    maxframe = frame;
-  a_range = data->p_max - data->p_min;
-  b_range = data->q_max - data->q_min;
-       a_minimums[frame] = min_a = data->p_min;
-       b_minimums[frame] = min_b = data->q_min;
-       a_inc = a_range / (double)width;
-       b_inc = b_range / (double)height;
-       point.x = -1;
-       point.y = 0;
-  run = 1;
-       a = min_a;
-       b = min_b;
-       a_maximums[frame] = max_a = data->p_max;
-       b_maximums[frame] = max_b = data->q_max;
-  expind[frame] = 0;;
-  Clear();
+  st->frame = (st->maxframe + 1) % MAXFRAMES;
+  if (st->frame > st->maxframe)
+    st->maxframe = st->frame;
+  st->a_range = data->p_max - data->p_min;
+  st->b_range = data->q_max - data->q_min;
+  st->a_minimums[st->frame] = st->min_a = data->p_min;
+  st->b_minimums[st->frame] = st->min_b = data->q_min;
+  st->a_inc = st->a_range / (double)st->width;
+  st->b_inc = st->b_range / (double)st->height;
+  st->point.x = -1;
+  st->point.y = 0;
+  st->run = 1;
+  st->a = st->min_a;
+  st->b = st->min_b;
+  st->a_maximums[st->frame] = st->max_a = data->p_max;
+  st->b_maximums[st->frame] = st->max_b = data->q_max;
+  st->expind[st->frame] = 0;
+  Clear(st);
 }
+#endif
 
 static void
-go_down(void)
+go_down(struct state *st)
 {
-  frame++;
-  if (frame > maxframe)
-    frame = 0;
-  jumpwin();
+  st->frame++;
+  if (st->frame > st->maxframe)
+    st->frame = 0;
+  jumpwin(st);
 }
 
 static void
-go_back(void)
+go_back(struct state *st)
 {
-  frame--;
-  if (frame < 0)
-    frame = maxframe;
-  jumpwin();
+  st->frame--;
+  if (st->frame < 0)
+    st->frame = st->maxframe;
+  jumpwin(st);
 }
 
 static void
-jumpwin(void)
+jumpwin(struct state *st)
 {
-  rubber_data.p_min = min_a = a_minimums[frame];
-  rubber_data.q_min = min_b = b_minimums[frame];
-  rubber_data.p_max = max_a = a_maximums[frame];
-  rubber_data.q_max = max_b = b_maximums[frame];
-  a_range = max_a - min_a;
-  b_range = max_b - min_b;
-       a_inc = a_range / (double)width;
-       b_inc = b_range / (double)height;
-       point.x = -1;
-       point.y = 0;
-       a = min_a;
-       b = min_b;
-  Clear();
-  if (resized[frame])
-    Redraw();
+  /*st->rubber_data.p_min =*/ st->min_a = st->a_minimums[st->frame];
+  /*st->rubber_data.q_min =*/ st->min_b = st->b_minimums[st->frame];
+  /*st->rubber_data.p_max =*/ st->max_a = st->a_maximums[st->frame];
+  /*st->rubber_data.q_max =*/ st->max_b = st->b_maximums[st->frame];
+  st->a_range = st->max_a - st->min_a;
+  st->b_range = st->max_b - st->min_b;
+  st->a_inc = st->a_range / (double)st->width;
+  st->b_inc = st->b_range / (double)st->height;
+  st->point.x = -1;
+  st->point.y = 0;
+  st->a = st->min_a;
+  st->b = st->min_b;
+  Clear(st);
+  if (st->resized[st->frame])
+    Redraw(st);
   else
-    redraw(exponents[frame], expind[frame], 0);
+    redraw(st, st->exponents[st->frame], st->expind[st->frame], 0);
 }
 
 static void
-go_init(void)
+go_init(struct state *st)
 {
-  frame = 0;
-  jumpwin();
+  st->frame = 0;
+  jumpwin(st);
 }
 
 static void
-Destroy_frame(void)
+Destroy_frame(struct state *st)
 {
-  static int i;
-
-  for (i=frame; i<maxframe; i++) {
-    exponents[frame] = exponents[frame+1];
-    expind[frame] = expind[frame+1];
-    a_minimums[frame] = a_minimums[frame+1];
-    b_minimums[frame] = b_minimums[frame+1];
-    a_maximums[frame] = a_maximums[frame+1];
-    b_maximums[frame] = b_maximums[frame+1];
+  int i;
+
+  for (i=st->frame; i<st->maxframe; i++) {
+    st->exponents[st->frame] = st->exponents[st->frame+1];
+    st->expind[st->frame] = st->expind[st->frame+1];
+    st->a_minimums[st->frame] = st->a_minimums[st->frame+1];
+    st->b_minimums[st->frame] = st->b_minimums[st->frame+1];
+    st->a_maximums[st->frame] = st->a_maximums[st->frame+1];
+    st->b_maximums[st->frame] = st->b_maximums[st->frame+1];
   }
-  maxframe--;
-  go_back();
+  st->maxframe--;
+  go_back(st);
 }
 
 static void
-InitBuffer(void)
+InitBuffer(struct state *st)
 {
   int i;
 
-  for (i = 0 ; i < maxcolor; ++i)
-    Points.npoints[i] = 0;
+  for (i = 0 ; i < st->maxcolor; ++i)
+    st->Points.npoints[i] = 0;
 }
 
 static void
-BufferPoint(Display *display, Window window, int color, int x, int y)
+BufferPoint(struct state *st, int color, int x, int y)
 {
-  if (Points.npoints[color] == MAXPOINTS)
-  {
-    XDrawPoints(display, window, Data_GC[color],
-       Points.data[color], Points.npoints[color], CoordModeOrigin);
-    XDrawPoints(display, pixmap, Data_GC[color],
-       Points.data[color], Points.npoints[color], CoordModeOrigin);
-    Points.npoints[color] = 0;
-  }
-  Points.data[color][Points.npoints[color]].x = x;
-  Points.data[color][Points.npoints[color]].y = y;
-  ++Points.npoints[color];
+  if (st->maxcolor > MAXCOLOR)
+    abort();
+
+  /* Guard against bogus color values. Shouldn't be necessary but paranoia
+     is good. */
+  if (color < 0)
+    color = 0;
+  else if (color >= st->maxcolor)
+    color = st->maxcolor - 1;
+
+  if (st->Points.npoints[color] == MAXPOINTS)
+    {
+      XDrawPoints(st->dpy, st->canvas, st->Data_GC[color],
+                  st->Points.data[color], st->Points.npoints[color], 
+                  CoordModeOrigin);
+#ifdef BACKING_PIXMAP
+      XDrawPoints(st->dpy, st->pixmap, st->Data_GC[color],
+                  st->Points.data[color], st->Points.npoints[color], 
+                  CoordModeOrigin);
+#endif
+      st->Points.npoints[color] = 0;
+    }
+  st->Points.data[color][st->Points.npoints[color]].x = x;
+  st->Points.data[color][st->Points.npoints[color]].y = y;
+  ++st->Points.npoints[color];
 }
 
 static void
-FlushBuffer(void)
+FlushBuffer(struct state *st)
 {
   int color;
 
-  for (color = 0; color < maxcolor; ++color)
-    if (Points.npoints[color])
-    {
-       XDrawPoints(dpy, canvas, Data_GC[color],
-         Points.data[color], Points.npoints[color],
-         CoordModeOrigin);
-       XDrawPoints(dpy, pixmap, Data_GC[color],
-         Points.data[color], Points.npoints[color],
-         CoordModeOrigin);
-       Points.npoints[color] = 0;
-    }
+  for (color = 0; color < st->maxcolor; ++color)
+    if (st->Points.npoints[color])
+      {
+        XDrawPoints(st->dpy, st->canvas, st->Data_GC[color],
+                    st->Points.data[color], st->Points.npoints[color],
+                    CoordModeOrigin);
+#ifdef BACKING_PIXMAP
+        XDrawPoints(st->dpy, st->pixmap, st->Data_GC[color],
+                    st->Points.data[color], st->Points.npoints[color],
+                    CoordModeOrigin);
+#endif
+        st->Points.npoints[color] = 0;
+      }
 }
 
 static void
-print_help(void)
+print_help(struct state *st)
 {
-    printf("During run-time, interactive control can be exerted via : \n");
-    printf("Mouse buttons allow rubber-banding of a zoom box\n");
-    printf("< halves the 'dwell', > doubles the 'dwell'\n");
-    printf("[ halves the 'settle', ] doubles the 'settle'\n");
-    printf("D flushes the drawing buffer\n");
-    printf("e or E recalculates color indices\n");
-    printf("f or F saves exponents to a file\n");
-    printf("h or H or ? displays this message\n");
-    printf("i decrements, I increments the stripe interval\n");
-    printf("KJMN increase/decrease minimum negative exponent\n");
-    printf("m increments the map index, changing maps\n");
-    printf("p or P reverses the colormap for negative/positive exponents\n");
-    printf("r redraws without recalculating\n");
-    printf("R redraws, recalculating with new dwell and settle values\n");
-    printf("s or S spins the colorwheel\n");
-    printf("u pops back up to the last zoom\n");
-    printf("U pops back up to the first picture\n");
-    printf("v or V displays the values of various settings\n");
-    printf("w decrements, W increments the color wheel index\n");
-    printf("x or X clears the window\n");
-    printf("q or Q exits\n");
+  printf("During run-time, interactive control can be exerted via : \n");
+  printf("Mouse buttons allow rubber-banding of a zoom box\n");
+  printf("< halves the 'dwell', > doubles the 'dwell'\n");
+  printf("[ halves the 'settle', ] doubles the 'settle'\n");
+  printf("D flushes the drawing buffer\n");
+  printf("e or E recalculates color indices\n");
+  printf("f or F saves exponents to a file\n");
+  printf("h or H or ? displays this message\n");
+  printf("i decrements, I increments the stripe interval\n");
+  printf("KJMN increase/decrease minimum negative exponent\n");
+  printf("m increments the map index, changing maps\n");
+  printf("p or P reverses the colormap for negative/positive exponents\n");
+  printf("r redraws without recalculating\n");
+  printf("R redraws, recalculating with new dwell and settle values\n");
+  printf("s or S spins the colorwheel\n");
+  printf("u pops back up to the last zoom\n");
+  printf("U pops back up to the first picture\n");
+  printf("v or V displays the values of various settings\n");
+  printf("w decrements, W increments the color wheel index\n");
+  printf("x or X clears the window\n");
+  printf("q or Q exits\n");
 }
 
 static void
-print_values(void)
+print_values(struct state *st)
 {
-    static int i;
-
-    printf("\nminlyap=%f minexp=%f maxexp=%f\n",minlyap,minexp,maxexp);
-    printf("width=%d height=%d\n",width,height);
-    printf("settle=%d  dwell=%d start_x=%f\n",settle,dwell, start_x);
-    printf("min_a=%f  a_rng=%f max_a=%f\n",min_a,a_range,max_a);
-    printf("min_b=%f  b_rng=%f max_b=%f\n",min_b,b_range,max_b);
-    if (Rflag)
-  printf("pseudo-random forcing\n");
-    else if (force) {
-  printf("periodic forcing=");
-  for (i=0;i<maxindex;i++)
-    printf("%d",forcing[i]);
-  printf("\n");
+  int i;
+  printf("\nminlyap=%f minexp=%f maxexp=%f\n",
+         st->minlyap,st->minexp, st->maxexp);
+  printf("width=%d height=%d\n",st->width,st->height);
+  printf("settle=%d  dwell=%d st->start_x=%f\n",
+         st->settle,st->dwell, st->start_x);
+  printf("min_a=%f  a_rng=%f        max_a=%f\n",
+         st->min_a,st->a_range,st->max_a);
+  printf("min_b=%f  b_rng=%f        max_b=%f\n",
+         st->min_b,st->b_range,st->max_b);
+  if (st->Rflag)
+    printf("pseudo-random forcing\n");
+  else if (st->force) {
+    printf("periodic forcing=");
+    for (i=0;i<st->maxindex;i++)
+      printf("%d",st->forcing[i]);
+    printf("\n");
+  }
+  else
+    printf("periodic forcing=01\n");
+  if (st->Force) {
+    printf("function forcing=");
+    for (i=0;i<st->funcmaxindex;i++) {
+      printf("%d",st->Forcing[i]);
     }
-    else
-  printf("periodic forcing=01\n");
-    if (Force) {
-  printf("function forcing=");
-  for (i=0;i<funcmaxindex;i++) {
-    printf("%d",Forcing[i]);
+    printf("\n");
   }
-  printf("\n");
+  printf("numcolors=%d\n",st->numcolors-1);
+}
+
+static void
+freemem(struct state *st)
+{
+  int i;
+  for (i=0;i<MAXFRAMES;i++)
+    free(st->exponents[i]);
+}
+
+static void
+setupmem(struct state *st)
+{
+  int i;
+  for (i=0;i<MAXFRAMES;i++) {
+    if((st->exponents[i]=
+        (double *)malloc(sizeof(double)*st->width*(st->height+1)))==NULL){
+      fprintf(stderr,"Error malloc'ing exponent array.\n");
+      exit(-1);
     }
-    printf("numcolors=%d\n",numcolors-1);
+  }
 }
 
 static void
-freemem(void)
+setforcing(struct state *st)
+{
+  int i;
+  for (i=0;i<MAXINDEX;i++)
+    st->forcing[i] = (random() > st->prob) ? 0 : 1;
+}
+
+/****************************************************************************/
+
+static void
+do_defaults (struct state *st)
+{
+  int i;
+
+  memset (st->expind,  0, sizeof(st->expind));
+  memset (st->resized, 0, sizeof(st->resized));
+
+  st->aflag = 0;
+  st->bflag = 0;
+  st->hflag = 0;
+  st->wflag = 0;
+  st->minexp = 0;
+  st->mapindex = 0;
+
+# ifdef SIXTEEN_COLORS
+  st->maxcolor=16;
+  st->startcolor=0;
+  st->color_offset=0;
+  st->mincolindex=1;
+  st->dwell=50;
+  st->settle=25;
+  st->xposition=128;
+  st->yposition=128;
+# else  /* !SIXTEEN_COLORS */
+  st->maxcolor=256;
+  st->startcolor=17;
+  st->color_offset=96;
+  st->mincolindex=33;
+  st->dwell=100;
+  st->settle=50;
+# endif /* !SIXTEEN_COLORS */
+
+  st->maxindex = MAXINDEX;
+  st->funcmaxindex = FUNCMAXINDEX;
+  st->min_a=2.0;
+  st->min_b=2.0;
+  st->a_range=2.0;
+  st->b_range=2.0;
+  st->minlyap=1.0;
+  st->max_a=4.0;
+  st->max_b=4.0;
+  st->numcolors=16;
+  st->prob=0.5;
+  st->numwheels=MAXWHEELS;
+  st->negative=1;
+  st->rgb_max=65000;
+  st->nostart=1;
+  st->stripe_interval=7;
+  st->save=1;
+  st->useprod=1;
+  st->spinlength=256;
+  st->run=1;
+
+  for (i = 0; i < countof(st->forcing); i++)
+    st->forcing[i] = (i & 1) ? 1 : 0;
+}
+
+static void
+do_preset (struct state *st, int builtin)
+{
+  char *ff = 0;
+  switch (builtin) {
+  case 0:
+    st->min_a = 3.75; st->aflag++;
+    st->min_b = 3.299999; st->bflag++;
+    st->a_range = 0.05; st->wflag++;
+    st->b_range = 0.05; st->hflag++;
+    st->dwell = 200;
+    st->settle = 100;
+    ff = "abaabbaaabbb";
+    break;
+
+  case 1:
+    st->min_a = 3.8; st->aflag++;
+    st->min_b = 3.2; st->bflag++;
+    st->b_range = .05; st->hflag++;
+    st->a_range = .05; st->wflag++;
+    ff = "bbbbbaaaaa";
+    break;
+
+  case 2:
+    st->min_a =  3.4; st->aflag++;
+    st->min_b =  3.04; st->bflag++;
+    st->a_range =  .5; st->wflag++;
+    st->b_range =  .5; st->hflag++;
+    ff = "abbbbbbbbb";
+    st->settle = 500;
+    st->dwell = 1000;
+    break;
+
+  case 3:
+    st->min_a = 3.5; st->aflag++;
+    st->min_b = 3.0; st->bflag++;
+    st->a_range = 0.2; st->wflag++;
+    st->b_range = 0.2; st->hflag++;
+    st->dwell = 600;
+    st->settle = 300;
+    ff = "aaabbbab";
+    break;
+
+  case 4:
+    st->min_a = 3.55667; st->aflag++;
+    st->min_b = 3.2; st->bflag++;
+    st->b_range = .05; st->hflag++;
+    st->a_range = .05; st->wflag++;
+    ff = "bbbbbaaaaa";
+    break;
+
+  case 5:
+    st->min_a = 3.79; st->aflag++;
+    st->min_b = 3.22; st->bflag++;
+    st->b_range = .02999; st->hflag++;
+    st->a_range = .02999; st->wflag++;
+    ff = "bbbbbaaaaa";
+    break;
+
+  case 6:
+    st->min_a = 3.7999; st->aflag++;
+    st->min_b = 3.299999; st->bflag++;
+    st->a_range = 0.2; st->wflag++;
+    st->b_range = 0.2; st->hflag++;
+    st->dwell = 300;
+    st->settle = 150;
+    ff = "abaabbaaabbb";
+    break;
+
+  case 7:
+    st->min_a = 3.89; st->aflag++;
+    st->min_b = 3.22; st->bflag++;
+    st->b_range = .028; st->hflag++;
+    st->a_range = .02999; st->wflag++;
+    ff = "bbbbbaaaaa";
+    st->settle = 600;
+    st->dwell = 1000;
+    break;
+
+  case 8:
+    st->min_a = 3.2; st->aflag++;
+    st->min_b = 3.7; st->bflag++;
+    st->a_range = 0.05; st->wflag++;
+    st->b_range = .005; st->hflag++;
+    ff = "abbbbaa";
+    break;
+
+  case 9:
+    ff = "aaaaaabbbbbb";
+    st->mapindex = 1;
+    st->dwell =  400;
+    st->settle =  200;
+    st->minlyap = st->maxexp = ABS(-0.85);
+    st->minexp = -1.0 * st->minlyap;
+    break;
+
+  case 10:
+    ff = "aaaaaabbbbbb";
+    st->mapindex = 1;
+    st->dwell =  400;
+    st->settle = 200;
+    st->minlyap = st->maxexp = ABS(-0.85);
+    st->minexp = -1.0 * st->minlyap;
+    break;
+
+  case 11:
+    st->mapindex = 1;
+    st->dwell =  400;
+    st->settle = 200;
+    st->minlyap = st->maxexp = ABS(-0.85);
+    st->minexp = -1.0 * st->minlyap;
+    break;
+
+  case 12:
+    ff = "abbb";
+    st->mapindex = 1;
+    st->dwell =  400;
+    st->settle = 200;
+    st->minlyap = st->maxexp = ABS(-0.85);
+    st->minexp = -1.0 * st->minlyap;
+    break;
+
+  case 13:
+    ff = "abbabaab";
+    st->mapindex = 1;
+    st->dwell =  400;
+    st->settle = 200;
+    st->minlyap = st->maxexp = ABS(-0.85);
+    st->minexp = -1.0 * st->minlyap;
+    break;
+
+  case 14:
+    ff = "abbabaab";
+    st->dwell =  800;
+    st->settle = 200;
+    st->minlyap = st->maxexp = ABS(-0.85);
+    st->minexp = -1.0 * st->minlyap;
+    /* ####  -x 0.05 */
+    st->min_a = 3.91; st->aflag++;
+    st->a_range =  0.0899999999; st->wflag++;
+    st->min_b =  3.28; st->bflag++;
+    st->b_range =  0.35; st->hflag++;
+    break;
+
+  case 15:
+    ff = "aaaaaabbbbbb";
+    st->dwell =  400;
+    st->settle = 200;
+    st->minlyap = st->maxexp = ABS(-0.85);
+    st->minexp = -1.0 * st->minlyap;
+    break;
+
+  case 16:
+    st->dwell =  400;
+    st->settle = 200;
+    st->minlyap = st->maxexp = ABS(-0.85);
+    st->minexp = -1.0 * st->minlyap;
+    break;
+
+  case 17:
+    ff = "abbb";
+    st->dwell =  400;
+    st->settle = 200;
+    st->minlyap = st->maxexp = ABS(-0.85);
+    st->minexp = -1.0 * st->minlyap;
+    break;
+
+  case 18:
+    ff = "abbabaab";
+    st->dwell =  400;
+    st->settle = 200;
+    st->minlyap = st->maxexp = ABS(-0.85);
+    st->minexp = -1.0 * st->minlyap;
+    break;
+
+  case 19:
+    st->mapindex = 2;
+    ff = "aaaaaabbbbbb";
+    st->dwell =  400;
+    st->settle = 200;
+    st->minlyap = st->maxexp = ABS(-0.85);
+    st->minexp = -1.0 * st->minlyap;
+    break;
+
+  case 20:
+    st->mapindex = 2;
+    st->dwell =  400;
+    st->settle = 200;
+    st->minlyap = st->maxexp = ABS(-0.85);
+    st->minexp = -1.0 * st->minlyap;
+    break;
+
+  case 21:
+    st->mapindex = 2;
+    ff = "abbb";
+    st->dwell =  400;
+    st->settle = 200;
+    st->minlyap = st->maxexp = ABS(-0.85);
+    st->minexp = -1.0 * st->minlyap;
+    break;
+
+  case 22:
+    st->mapindex = 2;
+    ff = "abbabaab";
+    st->dwell =  400;
+    st->settle = 200;
+    st->minlyap = st->maxexp = ABS(-0.85);
+    st->minexp = -1.0 * st->minlyap;
+    break;
+
+  default: 
+    abort();
+    break;
+  }
+
+  if (ff) {
+    char *ch;
+    int bindex = 0;
+    st->maxindex = strlen(ff);
+    if (st->maxindex > MAXINDEX)
+      usage(st);
+    ch = ff;
+    st->force++;
+    while (bindex < st->maxindex) {
+      if (*ch == 'a')
+        st->forcing[bindex++] = 0;
+      else if (*ch == 'b')
+        st->forcing[bindex++] = 1;
+      else
+        usage(st);
+      ch++;
+    }
+  }
+}
+
+
+static void *
+xlyap_init (Display *d, Window window)
+{
+  struct state *st = (struct state *) calloc (1, sizeof(*st));
+  XWindowAttributes xgwa;
+  int builtin = -1;
+  XGetWindowAttributes (d, window, &xgwa);
+  st->dpy = d;
+  st->width = xgwa.width;
+  st->height = xgwa.height;
+  st->visual = xgwa.visual;
+  st->screen = xgwa.screen;
+  st->cmap = xgwa.colormap;
+
+  do_defaults(st);
+  parseargs(st);
+
+  if (get_boolean_resource(st->dpy, "randomize", "Boolean"))
+    builtin = random() % NBUILTINS;
+  else {
+    char *s = get_string_resource(st->dpy, "builtin", "Integer");
+    if (s && *s)
+      builtin = atoi(s);
+    if (s) free (s);
+  }
+    
+  if (builtin >= 0)
+    do_preset (st, builtin);
+
+  st->background = BlackPixelOfScreen(st->screen);
+  setupmem(st);
+  init_data(st);
+  if (!mono_p)
+    st->foreground = st->startcolor;
+  else
+    st->foreground = WhitePixelOfScreen(st->screen);
+
+  /*
+   * Create the window to display the Lyapunov exponents
+   */
+  st->canvas = window;
+  init_color(st);
+
+#ifdef BACKING_PIXMAP
+  st->pixmap = XCreatePixmap(st->dpy, window, st->width, st->height, 
+                             xgwa.depth);
+#endif
+/*  st->rubber_data.band_cursor = XCreateFontCursor(st->dpy, XC_hand2);*/
+/*  CreateXorGC(st);*/
+  Clear(st);
+
+  st->delay  = get_integer_resource(st->dpy, "delay", "Delay");
+  st->linger = get_integer_resource(st->dpy, "linger", "Linger");
+  if (st->linger < 1) st->linger = 1;
+
+  return st;
+}
+
+
+static unsigned long
+xlyap_draw (Display *dpy, Window window, void *closure)
 {
-  static int i;
+  struct state *st = (struct state *) closure;
+  int i;
+
+  if (!st->run && st->reset_countdown) {
+    st->reset_countdown--;
+    if (st->reset_countdown)
+      return 1000000;
+    else {
+      do_defaults (st);
+      do_preset (st, (random() % NBUILTINS));
+      Clear (st);
+      init_data(st);
+      init_color(st);
+      resize (st);
+      st->frame = 0;
+      st->run = 1;
+    }
+  }
 
-       for (i=0;i<MAXFRAMES;i++)
-               free(exponents[i]);
+  for (i = 0; i < 1000; i++)
+    if (complyap(st) == TRUE)
+      {
+        st->run = 0;
+        st->reset_countdown = st->linger;
+        break;
+      }
+  return st->delay;
 }
 
 static void
-setupmem(void)
+xlyap_reshape (Display *dpy, Window window, void *closure, 
+                 unsigned int w, unsigned int h)
 {
-  static int i;
-
-       for (i=0;i<MAXFRAMES;i++) {
-               if((exponents[i]=
-                   (double *)malloc(sizeof(double)*width*height))==NULL){
-                   fprintf(stderr,"Error malloc'ing exponent array.\n");
-                   exit(-1);
-               }
-       }
+  struct state *st = (struct state *) closure;
+  resize(st);
+}
+
+static Bool
+xlyap_event (Display *dpy, Window window, void *closure, XEvent *event)
+{
+  struct state *st = (struct state *) closure;
+
+  switch(event->type)
+    {
+    case KeyPress:
+      if (Getkey(st, &event->xkey))
+        return True;
+      break;
+#if 0
+    case ButtonPress:
+      StartRubberBand(st, &st->rubber_data, event);
+      return True;
+    case MotionNotify:
+      TrackRubberBand(st, &st->rubber_data, event);
+      return True;
+    case ButtonRelease:
+      EndRubberBand(st, &st->rubber_data, event);
+      return True;
+#endif
+    default: 
+      break;
+    }
+
+  if (screenhack_event_helper (dpy, window, event))
+    {
+      Clear(st);
+      return True;
+    }
+
+  return False;
 }
 
 static void
-setforcing(void)
+xlyap_free (Display *dpy, Window window, void *closure)
 {
-  static int i;
-  for (i=0;i<MAXINDEX;i++)
-    forcing[i] = (ya_random() > prob) ? 0 : 1;
+  int i;
+  struct state *st = (struct state *) closure;
+
+  freemem (st);
+
+#ifdef BACKING_PIXMAP
+  XFreePixmap (st->dpy, st->pixmap);
+#endif
+/*  XFreeGC (st->dpy, st->RubberGC);*/
+  for (i = 0; i < st->maxcolor; i++)
+    XFreeGC (st->dpy, st->Data_GC[i]);
+
+  free (st);
 }
+
+
+XSCREENSAVER_MODULE ("XLyap", xlyap)