http://www.tienza.es/crux/src/www.jwz.org/xscreensaver/xscreensaver-5.05.tar.gz
[xscreensaver] / hacks / imsmap.c
index d8b1c088c51a2ac4ecdfcd0a9d7296fcfa676d79..6e1f31dded435a8f7bbc437cc2dead2c62546155 100644 (file)
@@ -1,4 +1,4 @@
-/* imsmap, Copyright (c) 1992 Juergen Nickelsen <nickel@cs.tu-berlin.de>
+/* imsmap, Copyright (c) 1992-2008 Juergen Nickelsen and Jamie Zawinski.
  * Derived from code by Markus Schirmer, TU Berlin.
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation.  No representations are made about the suitability of this
  * software for any purpose.  It is provided "as is" without express or 
  * implied warranty.
+ *
+ * Revision History:
+ * 24-aug-92: jwz: hacked.
+ * 17-May-97: jwz: hacked more.
  */
 
-#include "screenhack.h"
 #include <stdio.h>
-#include <X11/Xutil.h>
+#include <math.h>
+
+#include "screenhack.h"
 
 #define NSTEPS 7
 #define COUNT (1 << NSTEPS)
-#define CELL(c, r) cell[((unsigned int)(c)) + ((unsigned int) (r)) * xmax]
-
-static enum mode_t { MODE_H, MODE_S, MODE_V, MODE_RANDOM } mode;
-
-static GC gc, gc2;
-static Display *disp;
-static Window wind;
-static XWindowAttributes wattrs;
+#define CELL(c, r) st->cell[((unsigned int)(c)) + ((unsigned int) (r)) * st->xmax]
 
 #if defined(sun) && !__STDC__  /* sun cc doesn't know "signed char" */
 #define signed /**/
 #endif
 
-static unsigned long *pixels = 0, fg_pixel, bg_pixel;
-static int npixels = 0;
-static Colormap cmap;
-static int timeout, cycle_delay;
-static int cycle_p;
-static signed char *cell = NULL;
-static int xmax, ymax;
-static int iterations;
+struct state {
+  Display *dpy;
+  Window window;
+  Colormap cmap;
+  int ncolors;
+  XColor *colors;
+  Bool extra_krinkly_p;
 
-static void
-initwin (dsp, win)
-     Display *dsp;
-     Window win;
-{
-  int fg_h, bg_h;
-  double fg_s, fg_v, bg_s, bg_v;
-
-  enum mode_t this_mode;
-  static Bool rv_p;
-  static int ncolors = 0;
-  int shift;
-  double dshift;
-    
-  XGCValues gcv;
+  int delay, delay2;
+  signed char *cell;
+  int xmax, ymax;
+  int iteration, iterations;
 
-  XGetWindowAttributes (dsp, win, &wattrs);
-  cmap = wattrs.colormap;
+  int cx, xstep, ystep, xnextStep, ynextStep;
 
-  if (!ncolors)
-    {
-      char *mode_str = get_string_resource ("mode", "Mode");
-      rv_p = get_boolean_resource ("reverseVideo", "ReverseVideo");
-      cycle_p = get_boolean_resource ("cycle", "Cycle");
-      ncolors = get_integer_resource ("ncolors", "Integer");
-      timeout = get_integer_resource ("timeout", "Integer");
-      cycle_delay = get_integer_resource ("cycleDelay", "Integer");
-      iterations = get_integer_resource ("iterations", "Integer");
-      if (iterations < 0) iterations = 0;
-      else if (iterations > 7) iterations = 7;
-      pixels = (unsigned long *) calloc (ncolors, sizeof (unsigned int));
-      fg_pixel = get_pixel_resource ("background", "Background", dsp, cmap);
-      bg_pixel = get_pixel_resource ("foreground", "Foreground", dsp, cmap);
-
-      if (mono_p && fg_pixel == bg_pixel)
-       bg_pixel = !bg_pixel;
-
-      if (mono_p) cycle_p = False;
-
-      gcv.foreground = fg_pixel;
-      gcv.background = bg_pixel;
-      gc = XCreateGC (dsp, win, GCForeground|GCBackground, &gcv);
-      gcv.foreground = bg_pixel;
-      gc2 = XCreateGC (dsp, win, GCForeground, &gcv);
-
-      if (!mode_str || !strcmp (mode_str, "random"))
-       mode = MODE_RANDOM;
-      else if (!strcmp (mode_str, "h") || !strcmp (mode_str, "hue"))
-       mode = MODE_H;
-      else if (!strcmp (mode_str, "s") || !strcmp (mode_str, "saturation"))
-       mode = MODE_S;
-      else if (!strcmp (mode_str, "v") || !strcmp (mode_str, "value"))
-       mode = MODE_V;
-      else
-       {
-         fprintf (stderr,
-          "%s: mode must be hue, saturation, value, or random, not \"%s\"\n",
-                  progname, mode_str);
-         mode = MODE_RANDOM;
-       }
-    }
-    else if (! mono_p)
-      XFreeColors (dsp, cmap, pixels, npixels, 0);
-
-  this_mode = mode;
-  if (!mono_p && mode == MODE_RANDOM)
-    switch (random () % 3) {
-    case 0: this_mode = MODE_H; break;
-    case 1: this_mode = MODE_S; break;
-    case 2: this_mode = MODE_V; break;
-    }
+  unsigned int last_pixel, last_valid;
+  int flip_x;
+  int flip_xy;
 
-  if (mono_p)
-    {
-      npixels = ncolors;
-      pixels [0] = fg_pixel;
-      pixels [1] = bg_pixel;
-    }
-  else
-    {
-      XColor fg_color, bg_color;
+  GC gc, gc2;
+  XWindowAttributes xgwa;
 
-      if (fg_pixel == bg_pixel)
-       {
-       HSV_AGAIN:
-         fg_h = random () % 360;
-         bg_h = random () % 360;
-         fg_s = frand (1.0);
-         bg_s = frand (1.0);
-       V_AGAIN:
-         fg_v = frand (1.0);
-         bg_v = frand (1.0);
-         if ((fg_v - bg_v) > -0.4 && (fg_v - bg_v) < 0.4)
-           goto V_AGAIN;
-         hsv_to_rgb (fg_h, fg_s, fg_v, 
-                     &fg_color.red, &fg_color.green, &fg_color.blue);
-         hsv_to_rgb (bg_h, bg_s, bg_v, 
-                     &bg_color.red, &bg_color.green, &bg_color.blue);
-       }
-      else
-       {
-         fg_color.pixel = fg_pixel;
-         if (! XQueryColor (dsp, cmap, &fg_color))
-           abort ();
-         bg_color.pixel = bg_pixel;
-         if (! XQueryColor (dsp, cmap, &bg_color))
-           abort ();
-       }
-      fg_color.flags = DoRed|DoGreen|DoBlue;
-      bg_color.flags = DoRed|DoGreen|DoBlue;
-
-      rgb_to_hsv (fg_color.red, fg_color.green, fg_color.blue,
-                 &fg_h, &fg_s, &fg_v);
-      rgb_to_hsv (bg_color.red, bg_color.green, bg_color.blue,
-                 &bg_h, &bg_s, &bg_v);
-
-      if (/*mode == MODE_RANDOM &&*/
-         ((this_mode == MODE_S && (fg_s-bg_s) > -0.3 && (fg_s-bg_s) < 0.3) ||
-          (this_mode == MODE_V && (fg_v-bg_v) > -0.3 && (fg_v-bg_v) < 0.3) ||
-          (this_mode == MODE_H && (fg_h-bg_h) > -30 && (fg_h-bg_h) < 30)))
-       goto HSV_AGAIN;
-
-      switch (this_mode) {
-      case MODE_H:  shift = (bg_h - fg_h) / ncolors; break;
-      case MODE_S: dshift = (bg_s - fg_s) / ncolors; break;
-      case MODE_V: dshift = (bg_v - fg_v) / ncolors; break;
-      default: abort ();
-      }
-      
-      if (mode == MODE_RANDOM &&
-         ((this_mode == MODE_H)
-          ? ((shift > -2 && shift < 2) || fg_s < 0.3 || fg_v < 0.3)
-          : (dshift > -0.005 && dshift < 0.005)))
-       goto HSV_AGAIN;
-
-      if (mode == MODE_RANDOM && this_mode == MODE_S && fg_v < 0.5)
-       goto V_AGAIN;
-
-      for (npixels = 0; npixels < ncolors; npixels++)
-       {
-         if (cycle_p)
-           {
-             unsigned long plane_masks;
-             /* allocate the writable color cells, one at a time. */
-             if (! XAllocColorCells (dsp, cmap, False, &plane_masks, 0,
-                                     &fg_color.pixel, 1))
-               {
-                 fprintf (stderr,
-   "%s: couldn't allocate %s writable color cells.  Turning off -cycle.\n",
-                          progname, (npixels ? "enough" : "any"));
-                 cycle_p = 0;
-                 goto NON_CYCLE;
-               }
-             XStoreColor (dsp, cmap, &fg_color);
-           }
-         else
-           {
-           NON_CYCLE:
-             if (!XAllocColor (dsp, cmap, &fg_color))
-               break;
-           }
-         pixels[npixels] = fg_color.pixel;
-       
-         switch (this_mode)
-           {
-           case MODE_H: fg_h = (fg_h + shift) % 360; break;
-           case MODE_S: fg_s += dshift; break;
-           case MODE_V: fg_v += dshift; break;
-           default: abort ();
-           }
-         hsv_to_rgb (fg_h, fg_s, fg_v,
-                     &fg_color.red, &fg_color.green, &fg_color.blue);
-       }
-    }
-  XSetForeground (dsp, gc, pixels [0]);
-  XFillRectangle (dsp, win, gc, 0, 0, wattrs.width, wattrs.height);
-}
+  struct timeval then;
+};
 
 
-#define HEIGHT_TO_PIXEL(height) \
-       (((int) (height)) < 0 ? 0 : \
-        ((int) (height)) >= npixels ? npixels - 3 : ((int) (height)))
+#define HEIGHT_TO_PIXEL(height)                                        \
+       ((height) < 0                                           \
+        ? (st->extra_krinkly_p                                 \
+           ? st->ncolors - 1 -  ((-(height)) % st->ncolors)    \
+           : 0)                                                \
+        : ((height) >= st->ncolors                             \
+           ? (st->extra_krinkly_p                              \
+              ? (height) % st->ncolors                         \
+              : st->ncolors-1)                                 \
+           : (height)))
+
 
 static unsigned int
-set (l, c, size, height)
-     unsigned int l, c, size;
-     int height;
+set (struct state *st,
+     unsigned int l,
+     unsigned int c,
+     unsigned int size,
+     int height)
 {
   int rang = 1 << (NSTEPS - size);
   height = height + (random () % rang) - rang / 2;
+  height = HEIGHT_TO_PIXEL(height);
   CELL (l, c) = height;
-
-  return pixels [HEIGHT_TO_PIXEL (height)];
+  return st->colors[height].pixel;
 }
 
+
 static void
-floyd_steinberg ()
+floyd_steinberg (struct state *st)
 {
   int x, y, err;
 
@@ -244,14 +91,17 @@ floyd_steinberg ()
      don't use enormous amounts of memory.
    */
   XImage *image =
-    XCreateImage (disp, DefaultVisual(disp,DefaultScreen(disp)),
+    XCreateImage (st->dpy, st->xgwa.visual,
                  1, XYBitmap, 0,               /* depth, format, offset */
-                 (char *) calloc ((xmax + 1) / 8, 1),  /* data */
-                 xmax, 1, 8, 0);               /* w, h, pad, bpl */
+                 (char *) calloc ((st->xmax + 8) / 8, 1),      /* data */
+                 st->xmax, 1, 8, 0);           /* w, h, pad, bpl */
+
+  XSetForeground (st->dpy, st->gc, st->colors[0].pixel);
+  XSetBackground (st->dpy, st->gc, st->colors[1].pixel);
 
-  for (y = 0; y < ymax - 1; y++)
+  for (y = 0; y < st->ymax - 1; y++)
     {
-      for (x = 0; x < xmax - 1; x++)
+      for (x = 0; x < st->xmax - 1; x++)
        {
          if (CELL(x, y) < 0)
            {
@@ -268,172 +118,298 @@ floyd_steinberg ()
          CELL (x+1, y)   += (int) (((float) err) * 3.0/8.0);
          CELL (x+1, y+1) += (int) (((float) err) * 1.0/4.0);
        }
-      XPutImage (disp, wind, gc, image, 0, 0, 0, y, xmax, 1);
+      XPutImage (st->dpy, st->window, st->gc, image, 0, 0, 0, y, st->xmax, 1);
     }
   XDestroyImage (image);
 }
 
+
 static void
-draw (x, y, pixel, grid_size)  /* not called in mono mode */
-     int x, y, grid_size;
-     unsigned long pixel;
+draw (struct state *st,
+      int x, int y, unsigned long pixel, int grid_size)
 {
-  static unsigned int last_pixel, last_valid = 0;
-  if (! (last_valid && pixel == last_pixel))
-    XSetForeground (disp, gc, pixel);
-  last_valid = 1, last_pixel = pixel;
+  if (st->flip_x)
+    x = st->xmax - x;
+
+  if (st->flip_xy)
+    {
+      int swap = x;
+      x = y;
+      y = swap;
+    }
+
+  if (! (st->last_valid && pixel == st->last_pixel))
+    XSetForeground (st->dpy, st->gc, pixel);
+  st->last_valid = 1, st->last_pixel = pixel;
   if (grid_size == 1)
-    XDrawPoint (disp, wind, gc, x, y);
+    XDrawPoint (st->dpy, st->window, st->gc, x, y);
   else
-    XFillRectangle (disp, wind, gc, x, y, grid_size, grid_size);
+    XFillRectangle (st->dpy, st->window, st->gc, x, y, grid_size, grid_size);
 }
 
 
-static void 
-drawmap ()
+static void
+init_map (struct state *st)
 {
-  unsigned int x, y, i, step, nextStep, x1, x2, y1, y2;
-  unsigned int pixel, qpixels [4];
+  XGCValues gcv;
 
-  xmax = wattrs.width;
-  ymax = wattrs.height;
+  XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
+  st->cmap = st->xgwa.colormap;
 
-  cell = (signed char *) calloc (xmax * ymax, 1);
-  if (cell == NULL)
-    exit (1);
+  st->flip_x  = (random() % 2);
+  st->flip_xy = (random() % 2);
 
-  CELL (0, 0) = 0;
-  step = COUNT;
-  for (i = 0; i < iterations; i++)
+  if (mono_p)
+    st->flip_xy = 0;
+
+  st->ncolors = get_integer_resource (st->dpy, "ncolors", "Integer");
+  st->delay = get_integer_resource (st->dpy, "delay", "Integer");
+  st->delay2 = get_integer_resource (st->dpy, "delay2", "Integer");
+  st->iterations = get_integer_resource (st->dpy, "iterations", "Integer");
+  if (st->iterations < 0) st->iterations = 0;
+  else if (st->iterations > 7) st->iterations = 7;
+
+  if (st->ncolors <= 2) st->ncolors = 0;
+  if (st->ncolors == 0) mono_p = True;
+  if (st->ncolors > 255) st->ncolors = 255;  /* too many look bad */
+
+  if (!st->gc)  st->gc  = XCreateGC (st->dpy, st->window, 0, &gcv);
+  if (!st->gc2) st->gc2 = XCreateGC (st->dpy, st->window, 0, &gcv);
+
+  if (mono_p)
+    st->extra_krinkly_p = !(random() % 15);
+  else
+    st->extra_krinkly_p = !(random() % 5);
+
+  if (!mono_p)
     {
-      nextStep = step / 2;
-      for (x = 0; x < xmax; x += step)
-       {
-         x1 = x + nextStep;
-         if (x1 >= xmax)
-           x1 = 0;
-         x2 = x + step;
-         if (x2 >= xmax)
-           x2 = 0;
-         for (y = 0; y < ymax; y += step)
-           {
-             y1 = y + nextStep;
-             if (y1 >= ymax)
-               y1 = 0;
-             y2 = y + step;
-             if (y2 >= ymax)
-               y2 = 0;
-
-             qpixels [0] = pixels [HEIGHT_TO_PIXEL (CELL (x, y))];
-             qpixels [1] = pixels [HEIGHT_TO_PIXEL (CELL (x, y2))];
-             qpixels [2] = pixels [HEIGHT_TO_PIXEL (CELL (x2, y))];
-             qpixels [3] = pixels [HEIGHT_TO_PIXEL (CELL (x2, y2))];
-
-             pixel = set (x, y1, i,
-                          ((int) CELL (x, y) + (int) CELL (x, y2) + 1) / 2);
-             if (! mono_p &&
-                 (pixel != qpixels[0] || pixel != qpixels[1] || 
-                  pixel != qpixels[2] || pixel != qpixels[3]))
-               draw (x, y1, pixel, nextStep);
-
-             pixel = set (x1, y, i,
-                          ((int) CELL (x, y) + (int) CELL (x2, y) + 1) / 2);
-             if (! mono_p &&
-                 (pixel != qpixels[0] || pixel != qpixels[1] || 
-                  pixel != qpixels[2] || pixel != qpixels[3]))
-               draw (x1, y, pixel, nextStep);
-
-             pixel = set (x1, y1, i,
-                          ((int) CELL (x, y) + (int) CELL (x, y2) +
-                           (int) CELL (x2, y) + (int) CELL (x2, y2) + 2)
-                          / 4);
-             if (! mono_p &&
-                 (pixel != qpixels[0] || pixel != qpixels[1] || 
-                  pixel != qpixels[2] || pixel != qpixels[3]))
-               draw (x1, y1, pixel, nextStep);
-           }
-       }
-      step = nextStep;
-      if (!mono_p)
-       XSync (disp, True);
+      if (st->colors)
+       free_colors (st->dpy, st->cmap, st->colors, st->ncolors);
+      else
+       st->colors = (XColor *) malloc (st->ncolors * sizeof(*st->colors));
+
+      make_smooth_colormap (st->dpy, st->xgwa.visual, st->cmap,
+                            st->colors, &st->ncolors,
+                            True, 0, False);
+      if (st->ncolors <= 2)
+       mono_p = 1;
     }
+
   if (mono_p)
-    /* in mono-mode, we do all the drawing at the end */
-    floyd_steinberg ();
-  
-  free (cell);
-  XSync (disp, True);
+    {
+      int i;
+      unsigned long fg_pixel = 
+        get_pixel_resource (st->dpy, st->xgwa.colormap, 
+                            "foreground", "Foreground");
+      unsigned long bg_pixel = 
+        get_pixel_resource (st->dpy, st->xgwa.colormap, 
+                            "background", "Background");
+      if (!st->colors)
+        {
+          st->ncolors = 50;
+          st->colors = (XColor *) calloc (st->ncolors, sizeof(*st->colors));
+        }
+      st->colors[0].pixel = fg_pixel;
+      for (i = 1; i < st->ncolors; i++)
+        st->colors[i].pixel = bg_pixel;
+    }
+
+  XSetForeground (st->dpy, st->gc, st->colors[1].pixel);
+  XFillRectangle (st->dpy, st->window, st->gc, 0, 0, 
+                  st->xgwa.width, st->xgwa.height);
+
+  if (st->flip_xy)
+    {
+      st->xmax = st->xgwa.height;
+      st->ymax = st->xgwa.width;
+    }
+  else
+    {
+      st->xmax = st->xgwa.width;
+      st->ymax = st->xgwa.height;
+    }
+
+  if (st->cell) free (st->cell);
+  st->cell = (signed char *) calloc (st->xmax * st->ymax, 1);
+
+  CELL (0, 0) = 0;
+  st->xstep = COUNT;
+  st->ystep = COUNT;
+
+  st->iteration = 0;
+  st->cx = 0;
 }
 
-static void
-cycle (dpy)
-     Display *dpy;
+
+static void *
+imsmap_init (Display *dpy, Window window)
+{
+  struct state *st = (struct state *) calloc (1, sizeof(*st));
+  st->dpy = dpy;
+  st->window = window;
+  init_map (st);
+  return st;
+}
+
+
+static unsigned long
+imsmap_draw (Display *dpy, Window window, void *closure)
 {
-  XColor *colors = (XColor *) malloc (npixels * sizeof (XColor));
-  time_t stop;
+  struct state *st = (struct state *) closure;
+  int this_delay = st->delay2;
   int i;
-  for (i = 0; i < npixels; i++)
-    colors [i].pixel = pixels [i];
-  XQueryColors (dpy, cmap, colors, npixels);
-  stop = (time_t) ((time ((time_t) 0)) + timeout);
-  while (stop >= (time_t) time ((time_t) 0))
+
+  /* do this many lines at a time without pausing */
+  int col_chunk = st->iteration * 2 + 1;
+
+  if (st->iteration > st->iterations)
+    init_map (st);
+
+  if (st->cx == 0)
     {
-      unsigned long scratch = colors [npixels-1].pixel;
-      for (i = npixels-1; i > 0; i--)
-       colors [i].pixel = colors [i-1].pixel;
-      colors [0].pixel = scratch;
-      XStoreColors (dpy, cmap, colors, npixels);
-      XSync (dpy, True);
-      if (cycle_delay) usleep (cycle_delay);
+      st->xnextStep = st->xstep / 2;
+      st->ynextStep = st->ystep / 2;
     }
-  XSync (dpy, True);
-  free (colors);
+
+  for (i = 0; i < col_chunk; i++)
+    {
+      int x1, x2, y1, y2;
+      int y;
+      int x = st->cx;
+
+      x1 = x + st->xnextStep;
+      if (x1 < 0)
+        x1 = st->xmax-1;
+      else if (x1 >= st->xmax)
+        x1 = 0;
+
+      x2 = x + st->xstep;
+      if (x2 < 0)
+        x2 = st->xmax-1;
+      else if (x2 >= st->xmax)
+        x2 = 0;
+
+      for (y = 0; y < st->ymax; y += st->ystep)
+        {
+          unsigned int pixel, qpixels [4];
+
+          y1 = y + st->ynextStep;
+          if (y1 < 0)
+            y1 = st->ymax-1;
+          else if (y1 >= st->ymax)
+            y1 = 0;
+
+          y2 = y + st->ystep;
+          if (y2 < 0)
+            y2 = st->ymax-1;
+          else if (y2 >= st->ymax)
+            y2 = 0;
+
+          qpixels [0] = st->colors [HEIGHT_TO_PIXEL (CELL (x, y))].pixel;
+          qpixels [1] = st->colors [HEIGHT_TO_PIXEL (CELL (x, y2))].pixel;
+          qpixels [2] = st->colors [HEIGHT_TO_PIXEL (CELL (x2, y))].pixel;
+          qpixels [3] = st->colors [HEIGHT_TO_PIXEL (CELL (x2, y2))].pixel;
+
+          pixel = set (st, x, y1, st->iteration,
+                       ((int) CELL (x, y) + (int) CELL (x, y2) + 1) / 2);
+
+          if (! mono_p &&
+              (pixel != qpixels[0] || pixel != qpixels[1] || 
+               pixel != qpixels[2] || pixel != qpixels[3]))
+            draw (st, x, y1, pixel, st->ynextStep);
+
+          pixel = set (st, x1, y, st->iteration,
+                       ((int) CELL (x, y) + (int) CELL (x2, y) + 1) / 2);
+          if (! mono_p &&
+              (pixel != qpixels[0] || pixel != qpixels[1] || 
+               pixel != qpixels[2] || pixel != qpixels[3]))
+            draw (st, x1, y, pixel, st->ynextStep);
+
+          pixel = set (st, x1, y1, st->iteration,
+                       ((int) CELL (x, y) + (int) CELL (x, y2) +
+                        (int) CELL (x2, y) + (int) CELL (x2, y2) + 2)
+                       / 4);
+          if (! mono_p &&
+              (pixel != qpixels[0] || pixel != qpixels[1] || 
+               pixel != qpixels[2] || pixel != qpixels[3]))
+            draw (st, x1, y1, pixel, st->ynextStep);
+        }
+
+      st->cx += st->xstep;
+      if (st->cx >= st->xmax)
+        break;
+    }
+
+  if (st->cx >= st->xmax)
+    {
+      st->cx = 0;
+      st->xstep = st->xnextStep;
+      st->ystep = st->ynextStep;
+
+      st->iteration++;
+
+      if (st->iteration > st->iterations)
+        this_delay = st->delay * 1000000;
+
+      if (mono_p)
+        floyd_steinberg (st);  /* in mono, do all drawing at the end */
+    }
+
+  return this_delay;
+}
+
+
+static void
+imsmap_reshape (Display *dpy, Window window, void *closure, 
+                 unsigned int w, unsigned int h)
+{
+  struct state *st = (struct state *) closure;
+  init_map (st);
 }
 
 
-char *progclass = "Imsmap";
+static Bool
+imsmap_event (Display *dpy, Window window, void *closure, XEvent *event)
+{
+  struct state *st = (struct state *) closure;
+  if (event->xany.type == ButtonPress)
+    {
+      init_map (st);
+      return True;
+    }
+
+  return False;
+}
+
+
+static void
+imsmap_free (Display *dpy, Window window, void *closure)
+{
+  struct state *st = (struct state *) closure;
+  if (st->colors) free (st->colors);
+  if (st->cell) free (st->cell);
+  free (st);
+}
+
 
-char *defaults [] = {
-  "*background:        black",
-  "*foreground:        black",
+static const char *imsmap_defaults [] = {
+  ".background:        #000066",
+  ".foreground:        #FF00FF",
   "*mode:      random",
   "*ncolors:   50",
   "*iterations:        7",
-  "*timeout:   10",
-  "*cycleDelay:        100000",
-  "*cycle:     true",
+  "*delay:     5",
+  "*delay2:    20000",
   0
 };
 
-XrmOptionDescRec options [] = {
+static XrmOptionDescRec imsmap_options [] = {
   { "-ncolors",                ".ncolors",     XrmoptionSepArg, 0 },
-  { "-timeout",                ".timeout",     XrmoptionSepArg, 0 },
-  { "-cycle-delay",    ".cycleDelay",  XrmoptionSepArg, 0 },
+  { "-delay",          ".delay",       XrmoptionSepArg, 0 },
+  { "-delay2",         ".delay2",      XrmoptionSepArg, 0 },
   { "-mode",           ".mode",        XrmoptionSepArg, 0 },
   { "-iterations",     ".iterations",  XrmoptionSepArg, 0 },
-  { "-cycle",          ".cycle",       XrmoptionNoArg, "True"  },
-  { "-no-cycle",       ".cycle",       XrmoptionNoArg, "False" }
+  { 0, 0, 0, 0 }
 };
-int options_size = (sizeof (options) / sizeof (options[0]));
 
-
-void
-screenhack (dpy, window)
-     Display *dpy;
-     Window window;
-{
-    disp = dpy;
-    wind = window;
-    while (1)
-      {
-       initwin (dpy, window);
-       drawmap ();
-       if (timeout)
-         {
-           if (cycle_p)
-             cycle (dpy);
-           else
-             sleep (timeout);
-         }
-      }
-}
+XSCREENSAVER_MODULE ("IMSMAP", imsmap)