http://www.tienza.es/crux/src/www.jwz.org/xscreensaver/xscreensaver-5.05.tar.gz
[xscreensaver] / hacks / imsmap.c
index 54e8a77409eff781728f5d9e2d4f02655c063a65..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
 
 #include <stdio.h>
 #include <math.h>
-#include <sys/time.h> /* for gettimeofday() */
-
-#include <X11/Xlib.h>
-#include <X11/Xutil.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 XWindowAttributes xgwa;
+#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 Colormap cmap;
-static int ncolors;
-static XColor *colors;
-static Bool cycle_p;
-static int cycle_direction;
-static Bool extra_krinkly_p;
-
-static int delay, cycle_delay;
-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
-init_map (Display *dpy, Window window)
-{
-  unsigned long fg_pixel = 0, bg_pixel = 0;
-  int fg_h, bg_h;
-  double fg_s, fg_v, bg_s, bg_v;
-
-  enum mode_t this_mode;
-  static Bool rv_p;
-    
-  XGCValues gcv;
+  int delay, delay2;
+  signed char *cell;
+  int xmax, ymax;
+  int iteration, iterations;
 
-  XGetWindowAttributes (dpy, window, &xgwa);
-  cmap = xgwa.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");
-      delay = get_integer_resource ("delay", "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;
-
-      if (ncolors <= 2) ncolors = 0;
-      if (ncolors == 0) mono_p = True;
-
-      fg_pixel = get_pixel_resource ("background", "Background", dpy, cmap);
-      bg_pixel = get_pixel_resource ("foreground", "Foreground", dpy, cmap);
-
-      if (fg_pixel == bg_pixel)
-       {
-         XColor black, white;
-         black.red = black.green = black.blue = 0;
-         white.red = white.green = white.blue = 0xFFFF;
-         black.flags = white.flags = DoRed|DoGreen|DoBlue;
-         XAllocColor(dpy, cmap, &black);
-         XAllocColor(dpy, cmap, &white);
-         if (bg_pixel == black.pixel)
-           fg_pixel = white.pixel;
-         else
-           fg_pixel = black.pixel;
-       }
+  unsigned int last_pixel, last_valid;
+  int flip_x;
+  int flip_xy;
 
-      if (mono_p) cycle_p = False;
-
-      gcv.foreground = fg_pixel;
-      gcv.background = bg_pixel;
-      gc = XCreateGC (dpy, window, GCForeground|GCBackground, &gcv);
-      gcv.foreground = bg_pixel;
-      gc2 = XCreateGC (dpy, window, 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;
-       }
-    }
+  GC gc, gc2;
+  XWindowAttributes xgwa;
 
-  this_mode = mode;
-  if (!mono_p && mode == MODE_RANDOM)
-    switch (random () % 6) {
-    case 0: this_mode = MODE_H; break;
-    case 1: this_mode = MODE_S; break;
-    case 2: this_mode = MODE_V; break;
-    default: break;
-    }
-
-  if (mono_p)
-    extra_krinkly_p = !(random() % 15);
-  else
-    extra_krinkly_p = !(random() % 5);
-
-  if (!mono_p)
-    {
-      double distance, fg_H, bg_H, dh;
-
-    RETRY:
-      fg_h = random() % 360;
-      fg_s = frand(1.0);
-      fg_v = frand(1.0);
-
-      bg_h = fg_h;
-      bg_s = fg_s;
-      bg_v = fg_v;
-
-      switch (this_mode)
-       {
-       case MODE_H:
-         bg_h = random() % 360;
-         if (fg_v < 0.4)
-           goto RETRY;
-         distance = fg_h - bg_h;
-         if (distance < 0)
-           distance = -distance;
-         if (distance > 360)
-           distance = 180 - (distance - 180);
-         if (distance < 30)
-           goto RETRY;
-         break;
-
-       case MODE_S:
-         bg_s = frand(1.0);
-         if (fg_v < 0.4)
-           goto RETRY;
-         distance = fg_s - bg_s;
-         if (distance < 0)
-           distance = -distance;
-         if (distance < 0.2)
-           goto RETRY;
-         break;
-
-       case MODE_V:
-         bg_v = frand(1.0);
-         distance = fg_v - bg_v;
-         if (distance < 0)
-           distance = -distance;
-         if (distance < 0.4)
-           goto RETRY;
-         break;
-
-       default:
-         bg_h = random() % 360;
-         bg_s = frand(1.0);
-         bg_v = frand(1.0);
-
-         fg_H = ((double) fg_h) / 360;
-         bg_H = ((double) bg_h) / 360;
-         dh = fg_H - bg_H;
-         if (dh < 0) dh = -dh;
-         if (dh > 0.5) dh = 0.5 - (dh - 0.5);
-         distance = sqrt ((dh * dh) +
-                          ((fg_s - bg_s) * (fg_s - bg_s)) +
-                          ((fg_v - bg_v) * (fg_v - bg_v)));
-         if (distance < 0.2)
-           goto RETRY;
-       }
-
-      cycle_p = True;
-      if (colors)
-       free_colors (dpy, cmap, colors, ncolors);
-      else
-       colors = (XColor *) malloc (ncolors * sizeof(*colors));
-
-      cycle_direction = (random() & 1 ? 1 : -1);
-
-    RETRY_NON_WRITABLE:
-      {
-       int n = ncolors;
-       make_color_ramp (dpy, cmap,
-                        fg_h, fg_s, fg_v,
-                        bg_h, bg_s, bg_v,
-                        colors, &n,
-                        True, True, cycle_p);
-       if (n == 0 && cycle_p)
-         {
-           cycle_p = False;
-           goto RETRY_NON_WRITABLE;
-         }
-       ncolors = n;
-      }
-
-      if (ncolors <= 0)
-       mono_p = 1;
-    }
-
-  if (mono_p)
-    {
-      static Bool done = False;
-      static XColor c[50];
-         colors = c;
-      cycle_p = False;
-      ncolors = sizeof(c)/sizeof(*c);
-      if (!done)
-       {
-         int i;
-         done = True;
-         colors[0].pixel = fg_pixel;
-         for (i = 1; i < ncolors; i++)
-           colors[i].pixel = bg_pixel;
-       }
-    }
-
-  XSetForeground (dpy, gc, colors[1].pixel);
-  XFillRectangle (dpy, window, gc, 0, 0, xgwa.width, xgwa.height);
-}
+  struct timeval then;
+};
 
 
-#define HEIGHT_TO_PIXEL(height)                                \
-       ((height) < 0                                   \
-        ? (extra_krinkly_p                             \
-           ? ncolors - ((-(height)) % ncolors)         \
-           : 0)                                        \
-        : ((height) >= ncolors                         \
-           ? (extra_krinkly_p                          \
-              ? (height) % ncolors                     \
-              : ncolors-1)                             \
+#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 (unsigned int l,
+set (struct state *st,
+     unsigned int l,
      unsigned int c,
      unsigned int size,
      int height)
@@ -271,11 +76,12 @@ set (unsigned int l,
   height = height + (random () % rang) - rang / 2;
   height = HEIGHT_TO_PIXEL(height);
   CELL (l, c) = height;
-  return colors[height].pixel;
+  return st->colors[height].pixel;
 }
 
+
 static void
-floyd_steinberg (Display *dpy, Window window)
+floyd_steinberg (struct state *st)
 {
   int x, y, err;
 
@@ -285,17 +91,17 @@ floyd_steinberg (Display *dpy, Window window)
      don't use enormous amounts of memory.
    */
   XImage *image =
-    XCreateImage (dpy, xgwa.visual,
+    XCreateImage (st->dpy, st->xgwa.visual,
                  1, XYBitmap, 0,               /* depth, format, offset */
-                 (char *) calloc ((xmax + 8) / 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 (dpy, gc, colors[0].pixel);
-  XSetBackground (dpy, gc, colors[1].pixel);
+  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)
            {
@@ -312,191 +118,298 @@ floyd_steinberg (Display *dpy, Window window)
          CELL (x+1, y)   += (int) (((float) err) * 3.0/8.0);
          CELL (x+1, y+1) += (int) (((float) err) * 1.0/4.0);
        }
-      XPutImage (dpy, window, 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 (Display *dpy, Window window,
+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 (dpy, 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 (dpy, window, gc, x, y);
+    XDrawPoint (st->dpy, st->window, st->gc, x, y);
   else
-    XFillRectangle (dpy, window, gc, x, y, grid_size, grid_size);
+    XFillRectangle (st->dpy, st->window, st->gc, x, y, grid_size, grid_size);
 }
 
 
-static void 
-draw_map (Display *dpy, Window window)
+static void
+init_map (struct state *st)
 {
-  int xstep, ystep, xnextStep, ynextStep;
-  int x, y, i, x1, x2, y1, y2;
-  unsigned int pixel, qpixels [4];
+  XGCValues gcv;
+
+  XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
+  st->cmap = st->xgwa.colormap;
 
-  int backwards = random() & 1;
+  st->flip_x  = (random() % 2);
+  st->flip_xy = (random() % 2);
 
-  xmax = xgwa.width;
-  ymax = xgwa.height;
+  if (mono_p)
+    st->flip_xy = 0;
 
-  cell = (signed char *) calloc (xmax * ymax, 1);
-  if (cell == NULL)
-    exit (1);
+  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;
 
-  CELL (0, 0) = 0;
-  xstep = (backwards ? -COUNT : COUNT);
-  ystep = COUNT;
-  for (i = 0; i < iterations; i++)
+  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)
     {
-      xnextStep = xstep / 2;
-      ynextStep = ystep / 2;
-      for (x = (backwards ? xmax-1 : 0);
-          (backwards ? x >= 0 : x < xmax);
-          x += xstep)
-       {
-         x1 = x + xnextStep;
-         if (x1 < 0)
-           x1 = xmax-1;
-         else if (x1 >= xmax)
-           x1 = 0;
-
-         x2 = x + xstep;
-         if (x2 < 0)
-           x2 = xmax-1;
-         else if (x2 >= xmax)
-           x2 = 0;
-
-         for (y = 0; y < ymax; y += ystep)
-           {
-             y1 = y + ynextStep;
-             if (y1 < 0)
-               y1 = ymax-1;
-             else if (y1 >= ymax)
-               y1 = 0;
-
-             y2 = y + ystep;
-             if (y2 < 0)
-               y2 = ymax-1;
-             else if (y2 >= ymax)
-               y2 = 0;
-
-             qpixels [0] = colors [HEIGHT_TO_PIXEL (CELL (x, y))].pixel;
-             qpixels [1] = colors [HEIGHT_TO_PIXEL (CELL (x, y2))].pixel;
-             qpixels [2] = colors [HEIGHT_TO_PIXEL (CELL (x2, y))].pixel;
-             qpixels [3] = colors [HEIGHT_TO_PIXEL (CELL (x2, y2))].pixel;
-
-             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 (dpy, window, x, y1, pixel, ynextStep);
-
-             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 (dpy, window, x1, y, pixel, ynextStep);
-
-             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 (dpy, window, x1, y1, pixel, ynextStep);
-
-
-             if (cycle_p)
-               {
-                 struct timeval now;
-                 static struct timeval then = { 0, };
-                 unsigned long diff;
-#ifdef GETTIMEOFDAY_TWO_ARGS
-                 struct timezone tzp;
-                 gettimeofday(&now, &tzp);
-#else
-                 gettimeofday(&now);
-#endif
-                 diff = (((now.tv_sec - then.tv_sec)  * 1000000) +
-                         (now.tv_usec - then.tv_usec));
-                 if (diff > cycle_delay)
-                   {
-                     rotate_colors (dpy, cmap, colors, ncolors,
-                                    cycle_direction);
-                     then = now;
-                   }
-               }
-           }
-       }
-      xstep = xnextStep;
-      ystep = ynextStep;
-      if (!mono_p)
-       XSync (dpy, 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 (dpy, window);
-  
-  free (cell);
-  XSync (dpy, 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 *
+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;
 }
 
 
-char *progclass = "Imsmap";
+static unsigned long
+imsmap_draw (Display *dpy, Window window, void *closure)
+{
+  struct state *st = (struct state *) closure;
+  int this_delay = st->delay2;
+  int i;
 
-char *defaults [] = {
-  "Imsmap.background:  black",         /* to placate SGI */
-  "Imsmap.foreground:  black",
+  /* 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)
+    {
+      st->xnextStep = st->xstep / 2;
+      st->ynextStep = st->ystep / 2;
+    }
+
+  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);
+}
+
+
+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);
+}
+
+
+static const char *imsmap_defaults [] = {
+  ".background:        #000066",
+  ".foreground:        #FF00FF",
   "*mode:      random",
   "*ncolors:   50",
   "*iterations:        7",
-  "*delay:     10",
-  "*cycleDelay:        100000",
-  "*cycle:     true",
+  "*delay:     5",
+  "*delay2:    20000",
   0
 };
 
-XrmOptionDescRec options [] = {
+static XrmOptionDescRec imsmap_options [] = {
   { "-ncolors",                ".ncolors",     XrmoptionSepArg, 0 },
   { "-delay",          ".delay",       XrmoptionSepArg, 0 },
-  { "-cycle-delay",    ".cycleDelay",  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 }
 };
 
-
-void
-screenhack (Display *dpy, Window window)
-{
-    while (1)
-      {
-       init_map (dpy, window);
-       draw_map (dpy, window);
-       if (delay)
-         {
-           if (cycle_p)
-             {
-               time_t start = time((time_t) 0);
-               while (start + delay > time((time_t) 0))
-                 {
-                   rotate_colors (dpy, cmap, colors, ncolors,
-                                  cycle_direction);
-                   if (cycle_delay) usleep(cycle_delay);
-                 }
-             }
-           else
-             sleep (delay);
-         }
-      }
-}
+XSCREENSAVER_MODULE ("IMSMAP", imsmap)