ftp://ftp.krokus.ru/pub/OpenBSD/distfiles/xscreensaver-5.01.tar.gz
[xscreensaver] / hacks / petri.c
index b4c748f65f36b7c572b2b9d64604ba0f6a7df905..275fb42c83740304dfd2470b93bae72d91028cd5 100644 (file)
@@ -1,4 +1,4 @@
-/* petri, simulate mold in a petri dish. v2.6
+/* petri, simulate mold in a petri dish. v2.7
  * by Dan Bornstein, danfuzz@milk.com
  * with help from Jamie Zawinski, jwz@jwz.org
  * Copyright (c) 1992-1999 Dan Bornstein.
 
 typedef struct cell_s 
 {
-    short x;                        /*  0    - */
-    short y;                        /*  2      */
-    unsigned char col;              /*  4      */
-    unsigned char isnext;           /*  5      */
-    unsigned char nextcol;          /*  6      */
-                                    /*  7      */
-    struct cell_s *next;            /*  8    - */
-    struct cell_s *prev;            /* 12      */
-    FLOAT speed;                    /* 16    - */
-    FLOAT growth;                   /* 20 24   */
-    FLOAT nextspeed;                /* 24 32 - */
-                                    /* 28 40   */
+    unsigned char col;              /*  0      */
+    unsigned char isnext;           /*  1      */
+    unsigned char nextcol;          /*  2      */
+                                    /*  3      */
+    struct cell_s *next;            /*  4      */
+    struct cell_s *prev;            /*  8    - */
+    FLOAT speed;                    /* 12      */
+    FLOAT growth;                   /* 16 20 - */
+    FLOAT nextspeed;                /* 20 28   */
+                                    /* 24 36 - */
 } cell;
 
-static int arr_width;
-static int arr_height;
-static int count;
-
-static cell *arr;
-static cell *head;
-static cell *tail;
-static int blastcount;
-
-static Display *display;
-static Window window;
-static GC *coloredGCs;
-
-static int windowWidth;
-static int windowHeight;
-static int xOffset;
-static int yOffset;
-static int xSize;
-static int ySize;
-
-static FLOAT orthlim = 1.0;
-static FLOAT diaglim;
-static FLOAT anychan;
-static FLOAT minorchan;
-static FLOAT instantdeathchan;
-static int minlifespan;
-static int maxlifespan;
-static FLOAT minlifespeed;
-static FLOAT maxlifespeed;
-static FLOAT mindeathspeed;
-static FLOAT maxdeathspeed;
-static Bool originalcolors;
-
-static int random_life_value (void)
+struct state {
+  Display *dpy;
+  Window window;
+
+  int arr_width;
+  int arr_height;
+  int count;
+
+  cell *arr;
+  cell *head;
+  cell *tail;
+  int blastcount;
+
+  GC *coloredGCs;
+
+  int windowWidth;
+  int windowHeight;
+  int xOffset;
+  int yOffset;
+  int xSize;
+  int ySize;
+
+  FLOAT orthlim;
+  FLOAT diaglim;
+  FLOAT anychan;
+  FLOAT minorchan;
+  FLOAT instantdeathchan;
+  int minlifespan;
+  int maxlifespan;
+  FLOAT minlifespeed;
+  FLOAT maxlifespeed;
+  FLOAT mindeathspeed;
+  FLOAT maxdeathspeed;
+  Bool originalcolors;
+
+  int warned;
+  int delay;
+};
+
+
+#define cell_x(c) (st->arr_width ? ((c) - st->arr) % st->arr_width : 0)
+#define cell_y(c) (st->arr_width ? ((c) - st->arr) / st->arr_width : 0)
+
+
+static int random_life_value (struct state *st)
 {
-    return (int) ((RAND_FLOAT * (maxlifespan - minlifespan)) + minlifespan);
+    return (int) ((RAND_FLOAT * (st->maxlifespan - st->minlifespan)) + st->minlifespan);
 }
 
-static void setup_random_colormap (XWindowAttributes *xgwa)
+static void setup_random_colormap (struct state *st, XWindowAttributes *xgwa)
 {
     XGCValues gcv;
     int lose = 0;
-    int ncolors = count - 1;
+    int ncolors = st->count - 1;
     int n;
-    XColor *colors = (XColor *) calloc (sizeof(*colors), count*2);
+    XColor *colors = (XColor *) calloc (sizeof(*colors), st->count*2);
     
-    colors[0].pixel = get_pixel_resource ("background", "Background",
-                                         display, xgwa->colormap);
+    colors[0].pixel = get_pixel_resource (st->dpy, xgwa->colormap,
+                                          "background", "Background");
     
-    make_random_colormap (display, xgwa->visual, xgwa->colormap,
+    make_random_colormap (st->dpy, xgwa->visual, xgwa->colormap,
                          colors+1, &ncolors, True, True, 0, True);
     if (ncolors < 1)
       {
@@ -141,20 +150,20 @@ static void setup_random_colormap (XWindowAttributes *xgwa)
       }
     
     ncolors++;
-    count = ncolors;
+    st->count = ncolors;
     
-    memcpy (colors + count, colors, count * sizeof(*colors));
-    colors[count].pixel = get_pixel_resource ("foreground", "Foreground",
-                                             display, xgwa->colormap);
+    memcpy (colors + st->count, colors, st->count * sizeof(*colors));
+    colors[st->count].pixel = get_pixel_resource (st->dpy, xgwa->colormap,
+                                              "foreground", "Foreground");
     
-    for (n = 1; n < count; n++)
+    for (n = 1; n < st->count; n++)
     {
-       int m = n + count;
+       int m = n + st->count;
        colors[n].red = colors[m].red / 2;
        colors[n].green = colors[m].green / 2;
        colors[n].blue = colors[m].blue / 2;
        
-       if (!XAllocColor (display, xgwa->colormap, &colors[n]))
+       if (!XAllocColor (st->dpy, xgwa->colormap, &colors[n]))
        {
            lose++;
            colors[n] = colors[m];
@@ -168,36 +177,36 @@ static void setup_random_colormap (XWindowAttributes *xgwa)
                 progname, lose);
     }
     
-    for (n = 0; n < count*2; n++) 
+    for (n = 0; n < st->count*2; n++) 
     {
        gcv.foreground = colors[n].pixel;
-       coloredGCs[n] = XCreateGC (display, window, GCForeground, &gcv);
+       st->coloredGCs[n] = XCreateGC (st->dpy, st->window, GCForeground, &gcv);
     }
 
     free (colors);
 }
 
-static void setup_original_colormap (XWindowAttributes *xgwa)
+static void setup_original_colormap (struct state *st, XWindowAttributes *xgwa)
 {
     XGCValues gcv;
     int lose = 0;
     int n;
-    XColor *colors = (XColor *) calloc (sizeof(*colors), count*2);
+    XColor *colors = (XColor *) calloc (sizeof(*colors), st->count*2);
     
-    colors[0].pixel = get_pixel_resource ("background", "Background",
-                                         display, xgwa->colormap);
+    colors[0].pixel = get_pixel_resource (st->dpy, xgwa->colormap,
+                                          "background", "Background");
 
-    colors[count].pixel = get_pixel_resource ("foreground", "Foreground",
-                                             display, xgwa->colormap);
+    colors[st->count].pixel = get_pixel_resource (st->dpy, xgwa->colormap,
+                                              "foreground", "Foreground");
 
-    for (n = 1; n < count; n++)
+    for (n = 1; n < st->count; n++)
     {
-       int m = n + count;
+       int m = n + st->count;
        colors[n].red =   ((n & 0x01) != 0) * 0x8000;
        colors[n].green = ((n & 0x02) != 0) * 0x8000;
        colors[n].blue =  ((n & 0x04) != 0) * 0x8000;
 
-       if (!XAllocColor (display, xgwa->colormap, &colors[n]))
+       if (!XAllocColor (st->dpy, xgwa->colormap, &colors[n]))
        {
            lose++;
            colors[n] = colors[0];
@@ -207,10 +216,10 @@ static void setup_original_colormap (XWindowAttributes *xgwa)
        colors[m].green = colors[n].green + 0x4000;
        colors[m].blue  = colors[n].blue + 0x4000;
 
-       if (!XAllocColor (display, xgwa->colormap, &colors[m]))
+       if (!XAllocColor (st->dpy, xgwa->colormap, &colors[m]))
        {
            lose++;
-           colors[m] = colors[count];
+           colors[m] = colors[st->count];
        }
     }
 
@@ -221,21 +230,22 @@ static void setup_original_colormap (XWindowAttributes *xgwa)
                 progname, lose);
     }
     
-    for (n = 0; n < count*2; n++) 
+    for (n = 0; n < st->count*2; n++) 
     {
        gcv.foreground = colors[n].pixel;
-       coloredGCs[n] = XCreateGC (display, window, GCForeground, &gcv);
+       st->coloredGCs[n] = XCreateGC (st->dpy, st->window, GCForeground, &gcv);
     }
 
     free (colors);
 }
 
-static void setup_display (void)
+static void
+setup_display (struct state *st)
 {
     XWindowAttributes xgwa;
     Colormap cmap;
 
-    int cell_size = get_integer_resource ("size", "Integer");
+    int cell_size = get_integer_resource (st->dpy, "size", "Integer");
     int osize, alloc_size, oalloc;
     int mem_throttle = 0;
     char *s;
@@ -244,7 +254,7 @@ static void setup_display (void)
 
     osize = cell_size;
 
-    s = get_string_resource ("memThrottle", "MemThrottle");
+    s = get_string_resource (st->dpy, "memThrottle", "MemThrottle");
     if (s)
       {
         int n;
@@ -267,249 +277,256 @@ static void setup_display (void)
         free (s);
       }
 
-    XGetWindowAttributes (display, window, &xgwa);
+    XGetWindowAttributes (st->dpy, st->window, &xgwa);
+
+    st->originalcolors = get_boolean_resource (st->dpy, "originalcolors", "Boolean");
+
+    st->count = get_integer_resource (st->dpy, "count", "Integer");
+    if (st->count < 2) st->count = 2;
 
-    originalcolors = get_boolean_resource ("originalcolors", "Boolean");
+    /* number of colors can't be greater than the half depth of the screen. */
+    if (st->count > (unsigned int) (1L << (xgwa.depth-1)))
+      st->count = (unsigned int) (1L << (xgwa.depth-1));
 
-    count = get_integer_resource ("count", "Integer");
-    if (count < 2) count = 2;
-    if (count > (1L << (xgwa.depth-1)))
-      count = (1L << (xgwa.depth-1));
+    /* Actually, since cell->col is of type char, this has to be small. */
+    if (st->count >= (unsigned int) (1L << ((sizeof(st->arr[0].col) * 8) - 1)))
+      st->count = (unsigned int) (1L << ((sizeof(st->arr[0].col) * 8) - 1));
 
-    if (originalcolors && (count > 8))
+
+    if (st->originalcolors && (st->count > 8))
     {
-       count = 8;
+       st->count = 8;
     }
 
-    coloredGCs = (GC *) calloc (sizeof(GC), count * 2);
+    st->coloredGCs = (GC *) calloc (sizeof(GC), st->count * 2);
 
-    diaglim  = get_float_resource ("diaglim", "Float");
-    if (diaglim < 1.0)
+    st->diaglim  = get_float_resource (st->dpy, "diaglim", "Float");
+    if (st->diaglim < 1.0)
     {
-       diaglim = 1.0;
+       st->diaglim = 1.0;
     }
-    else if (diaglim > 2.0)
+    else if (st->diaglim > 2.0)
     {
-       diaglim = 2.0;
+       st->diaglim = 2.0;
     }
-    diaglim *= orthlim;
+    st->diaglim *= st->orthlim;
 
-    anychan  = get_float_resource ("anychan", "Float");
-    if (anychan < 0.0)
+    st->anychan  = get_float_resource (st->dpy, "anychan", "Float");
+    if (st->anychan < 0.0)
     {
-       anychan = 0.0;
+       st->anychan = 0.0;
     }
-    else if (anychan > 1.0)
+    else if (st->anychan > 1.0)
     {
-       anychan = 1.0;
+       st->anychan = 1.0;
     }
     
-    minorchan = get_float_resource ("minorchan","Float");
-    if (minorchan < 0.0)
+    st->minorchan = get_float_resource (st->dpy, "minorchan","Float");
+    if (st->minorchan < 0.0)
     {
-       minorchan = 0.0;
+       st->minorchan = 0.0;
     }
-    else if (minorchan > 1.0)
+    else if (st->minorchan > 1.0)
     {
-       minorchan = 1.0;
+       st->minorchan = 1.0;
     }
     
-    instantdeathchan = get_float_resource ("instantdeathchan","Float");
-    if (instantdeathchan < 0.0)
+    st->instantdeathchan = get_float_resource (st->dpy, "instantdeathchan","Float");
+    if (st->instantdeathchan < 0.0)
     {
-       instantdeathchan = 0.0;
+       st->instantdeathchan = 0.0;
     }
-    else if (instantdeathchan > 1.0)
+    else if (st->instantdeathchan > 1.0)
     {
-       instantdeathchan = 1.0;
+       st->instantdeathchan = 1.0;
     }
 
-    minlifespan = get_integer_resource ("minlifespan", "Integer");
-    if (minlifespan < 1)
+    st->minlifespan = get_integer_resource (st->dpy, "minlifespan", "Integer");
+    if (st->minlifespan < 1)
     {
-       minlifespan = 1;
+       st->minlifespan = 1;
     }
 
-    maxlifespan = get_integer_resource ("maxlifespan", "Integer");
-    if (maxlifespan < minlifespan)
+    st->maxlifespan = get_integer_resource (st->dpy, "maxlifespan", "Integer");
+    if (st->maxlifespan < st->minlifespan)
     {
-       maxlifespan = minlifespan;
+       st->maxlifespan = st->minlifespan;
     }
 
-    minlifespeed = get_float_resource ("minlifespeed", "Float");
-    if (minlifespeed < 0.0)
+    st->minlifespeed = get_float_resource (st->dpy, "minlifespeed", "Float");
+    if (st->minlifespeed < 0.0)
     {
-       minlifespeed = 0.0;
+       st->minlifespeed = 0.0;
     }
-    else if (minlifespeed > 1.0)
+    else if (st->minlifespeed > 1.0)
     {
-       minlifespeed = 1.0;
+       st->minlifespeed = 1.0;
     }
 
-    maxlifespeed = get_float_resource ("maxlifespeed", "Float");
-    if (maxlifespeed < minlifespeed)
+    st->maxlifespeed = get_float_resource (st->dpy, "maxlifespeed", "Float");
+    if (st->maxlifespeed < st->minlifespeed)
     {
-       maxlifespeed = minlifespeed;
+       st->maxlifespeed = st->minlifespeed;
     }
-    else if (maxlifespeed > 1.0)
+    else if (st->maxlifespeed > 1.0)
     {
-       maxlifespeed = 1.0;
+       st->maxlifespeed = 1.0;
     }
 
-    mindeathspeed = get_float_resource ("mindeathspeed", "Float");
-    if (mindeathspeed < 0.0)
+    st->mindeathspeed = get_float_resource (st->dpy, "mindeathspeed", "Float");
+    if (st->mindeathspeed < 0.0)
     {
-       mindeathspeed = 0.0;
+       st->mindeathspeed = 0.0;
     }
-    else if (mindeathspeed > 1.0)
+    else if (st->mindeathspeed > 1.0)
     {
-       mindeathspeed = 1.0;
+       st->mindeathspeed = 1.0;
     }
 
-    maxdeathspeed = get_float_resource ("maxdeathspeed", "Float");
-    if (maxdeathspeed < mindeathspeed)
+    st->maxdeathspeed = get_float_resource (st->dpy, "maxdeathspeed", "Float");
+    if (st->maxdeathspeed < st->mindeathspeed)
     {
-       maxdeathspeed = mindeathspeed;
+       st->maxdeathspeed = st->mindeathspeed;
     }
-    else if (maxdeathspeed > 1.0)
+    else if (st->maxdeathspeed > 1.0)
     {
-       maxdeathspeed = 1.0;
+       st->maxdeathspeed = 1.0;
     }
 
-    minlifespeed *= diaglim;
-    maxlifespeed *= diaglim;
-    mindeathspeed *= diaglim;
-    maxdeathspeed *= diaglim;
+    st->minlifespeed *= st->diaglim;
+    st->maxlifespeed *= st->diaglim;
+    st->mindeathspeed *= st->diaglim;
+    st->maxdeathspeed *= st->diaglim;
 
     cmap = xgwa.colormap;
     
-    windowWidth = xgwa.width;
-    windowHeight = xgwa.height;
+    st->windowWidth = xgwa.width;
+    st->windowHeight = xgwa.height;
     
-    arr_width = windowWidth / cell_size;
-    arr_height = windowHeight / cell_size;
+    st->arr_width = st->windowWidth / cell_size;
+    st->arr_height = st->windowHeight / cell_size;
 
-    alloc_size = sizeof(cell) * arr_width * arr_height;
+    alloc_size = sizeof(cell) * st->arr_width * st->arr_height;
     oalloc = alloc_size;
 
     if (mem_throttle > 0)
-      while (cell_size < windowWidth/10 &&
-             cell_size < windowHeight/10 &&
+      while (cell_size < st->windowWidth/10 &&
+             cell_size < st->windowHeight/10 &&
              alloc_size > mem_throttle)
         {
           cell_size++;
-          arr_width = windowWidth / cell_size;
-          arr_height = windowHeight / cell_size;
-          alloc_size = sizeof(cell) * arr_width * arr_height;
+          st->arr_width = st->windowWidth / cell_size;
+          st->arr_height = st->windowHeight / cell_size;
+          alloc_size = sizeof(cell) * st->arr_width * st->arr_height;
         }
 
     if (osize != cell_size)
       {
-        static int warned = 0;
-        if (!warned)
+        if (!st->warned)
           {
             fprintf (stderr,
              "%s: throttling cell size from %d to %d because of %dM limit.\n",
                      progname, osize, cell_size, mem_throttle / (1 << 20));
             fprintf (stderr, "%s: %dx%dx%d = %.1fM, %dx%dx%d = %.1fM.\n",
                      progname,
-                     windowWidth, windowHeight, osize,
+                     st->windowWidth, st->windowHeight, osize,
                      ((float) oalloc) / (1 << 20),
-                     windowWidth, windowHeight, cell_size,
+                     st->windowWidth, st->windowHeight, cell_size,
                      ((float) alloc_size) / (1 << 20));
-            warned = 1;
+            st->warned = 1;
           }
       }
 
-    xSize = windowWidth / arr_width;
-    ySize = windowHeight / arr_height;
-    if (xSize > ySize)
+    st->xSize = st->arr_width ? st->windowWidth / st->arr_width : 0;
+    st->ySize = st->arr_height ? st->windowHeight / st->arr_height : 0;
+    if (st->xSize > st->ySize)
     {
-       xSize = ySize;
+       st->xSize = st->ySize;
     }
     else
     {
-       ySize = xSize;
+       st->ySize = st->xSize;
     }
     
-    xOffset = (windowWidth - (arr_width * xSize)) / 2;
-    yOffset = (windowHeight - (arr_height * ySize)) / 2;
+    st->xOffset = (st->windowWidth - (st->arr_width * st->xSize)) / 2;
+    st->yOffset = (st->windowHeight - (st->arr_height * st->ySize)) / 2;
 
-    if (originalcolors)
+    if (st->originalcolors)
     {
-       setup_original_colormap (&xgwa);
+       setup_original_colormap (st, &xgwa);
     }
     else
     {
-       setup_random_colormap (&xgwa);
+       setup_random_colormap (st, &xgwa);
     }
 }
 
-static void drawblock (int x, int y, unsigned char c)
+static void drawblock (struct state *st, int x, int y, unsigned char c)
 {
-  if (xSize == 1 && ySize == 1)
-    XDrawPoint (display, window, coloredGCs[c], x + xOffset, y + yOffset);
+  if (st->xSize == 1 && st->ySize == 1)
+    XDrawPoint (st->dpy, st->window, st->coloredGCs[c], x + st->xOffset, y + st->yOffset);
   else
-    XFillRectangle (display, window, coloredGCs[c],
-                   x * xSize + xOffset, y * ySize + yOffset,
-                   xSize, ySize);
+    XFillRectangle (st->dpy, st->window, st->coloredGCs[c],
+                   x * st->xSize + st->xOffset, y * st->ySize + st->yOffset,
+                   st->xSize, st->ySize);
 }
 
-static void setup_arr (void)
+static void setup_arr (struct state *st)
 {
     int x, y;
 
-    if (arr != NULL)
+    if (st->arr != NULL)
     {
-       free (arr);
+       free (st->arr);
     }
 
-    XFillRectangle (display, window, coloredGCs[0], 0, 0, 
-                   windowWidth, windowHeight);
+    XFillRectangle (st->dpy, st->window, st->coloredGCs[0], 0, 0, 
+                   st->windowWidth, st->windowHeight);
+    
+    if (!st->arr_width) st->arr_width = 1;
+    if (!st->arr_height) st->arr_height = 1;
 
-    arr = (cell *) calloc (sizeof(cell), arr_width * arr_height);  
-    if (!arr)
+    st->arr = (cell *) calloc (sizeof(cell), st->arr_width * st->arr_height);  
+    if (!st->arr)
       {
         fprintf (stderr, "%s: out of memory allocating %dx%d grid\n",
-                 progname, arr_width, arr_height);
+                 progname, st->arr_width, st->arr_height);
         exit (1);
       }
 
-    for (y = 0; y < arr_height; y++)
+    for (y = 0; y < st->arr_height; y++)
     {
-      int row = y * arr_width;
-       for (x = 0; x < arr_width; x++) 
+      int row = y * st->arr_width;
+       for (x = 0; x < st->arr_width; x++) 
        {
-           arr[row+x].x = x;
-           arr[row+x].y = y;
-           arr[row+x].speed = 0.0;
-           arr[row+x].growth = 0.0;
-           arr[row+x].col = 0;
-           arr[row+x].isnext = 0;
-           arr[row+x].next = 0;
-           arr[row+x].prev = 0;
+           st->arr[row+x].speed = 0.0;
+           st->arr[row+x].growth = 0.0;
+           st->arr[row+x].col = 0;
+           st->arr[row+x].isnext = 0;
+           st->arr[row+x].next = 0;
+           st->arr[row+x].prev = 0;
        }
     }
 
-    if (head == NULL)
+    if (st->head == NULL)
     {
-       head = (cell *) malloc (sizeof (cell));
+       st->head = (cell *) malloc (sizeof (cell));
     }
     
-    if (tail == NULL)
+    if (st->tail == NULL)
     {
-       tail = (cell *) malloc (sizeof (cell));
+       st->tail = (cell *) malloc (sizeof (cell));
     }
 
-    head->next = tail;
-    head->prev = head;
-    tail->next = tail;
-    tail->prev = head;
+    st->head->next = st->tail;
+    st->head->prev = st->head;
+    st->tail->next = st->tail;
+    st->tail->prev = st->head;
 
-    blastcount = random_life_value ();
+    st->blastcount = random_life_value (st);
 }
 
-static void newcell (cell *c, unsigned char col, FLOAT sp)
+static void newcell (struct state *st, cell *c, unsigned char col, FLOAT sp)
 {
     if (! c) return;
     
@@ -520,48 +537,48 @@ static void newcell (cell *c, unsigned char col, FLOAT sp)
     c->isnext = 1;
     
     if (c->prev == 0) {
-       c->next = head->next;
-       c->prev = head;
-       head->next = c;
+       c->next = st->head->next;
+       c->prev = st->head;
+       st->head->next = c;
        c->next->prev = c;
     }
 }
 
-static void killcell (cell *c)
+static void killcell (struct state *st, cell *c)
 {
     c->prev->next = c->next;
     c->next->prev = c->prev;
     c->prev = 0;
     c->speed = 0.0;
-    drawblock (c->x, c->y, c->col);
+    drawblock (st, cell_x(c), cell_y(c), c->col);
 }
 
 
-static void randblip (int doit)
+static void randblip (struct state *st, int doit)
 {
     int n;
     int b = 0;
     if (!doit 
-       && (blastcount-- >= 0) 
-       && (RAND_FLOAT > anychan))
+       && (st->blastcount-- >= 0) 
+       && (RAND_FLOAT > st->anychan))
     {
        return;
     }
     
-    if (blastcount < 0) 
+    if (st->blastcount < 0) 
     {
        b = 1;
        n = 2;
-       blastcount = random_life_value ();
-       if (RAND_FLOAT < instantdeathchan)
+       st->blastcount = random_life_value (st);
+       if (RAND_FLOAT < st->instantdeathchan)
        {
            /* clear everything every so often to keep from getting into a
             * rut */
-           setup_arr ();
+           setup_arr (st);
            b = 0;
        }
     }
-    else if (RAND_FLOAT <= minorchan) 
+    else if (RAND_FLOAT <= st->minorchan) 
     {
        n = 2;
     }
@@ -572,65 +589,74 @@ static void randblip (int doit)
     
     while (n--) 
     {
-       int x = random () % arr_width;
-       int y = random () % arr_height;
+      int x = st->arr_width ? random () % st->arr_width : 0;
+      int y = st->arr_height ? random () % st->arr_height : 0;
        int c;
        FLOAT s;
        if (b)
        {
            c = 0;
-           s = RAND_FLOAT * (maxdeathspeed - mindeathspeed) + mindeathspeed;
+           s = RAND_FLOAT * (st->maxdeathspeed - st->mindeathspeed) + st->mindeathspeed;
        }
        else
        {
-           c = (random () % (count-1)) + 1;
-           s = RAND_FLOAT * (maxlifespeed - minlifespeed) + minlifespeed;
+           c = ((st->count - 1) ? random () % (st->count-1) : 0) + 1;
+           s = RAND_FLOAT * (st->maxlifespeed - st->minlifespeed) + st->minlifespeed;
        }
-       newcell (&arr[y * arr_width + x], c, s);
+       newcell (st, &st->arr[y * st->arr_width + x], c, s);
     }
 }
 
-static void update (void)
+static void update (struct state *st)
 {
     cell *a;
     
-    for (a = head->next; a != tail; a = a->next) 
+    for (a = st->head->next; a != st->tail; a = a->next) 
     {
-        static XPoint coords1[] = {{-1,  0}, { 1, 0}, {0, -1}, {0, 1}};
-        static XPoint coords2[] = {{-1, -1}, {-1, 1}, {1, -1}, {1, 1}};
-        XPoint *coords = 0;
-        int i;
+       static const XPoint all_coords[] = {{-1, -1}, {-1, 1}, {1, -1}, {1, 1},
+                                            {-1,  0}, { 1, 0}, {0, -1}, {0, 1},
+                                            {99, 99}};
+
+        const XPoint *coords = 0;
 
         if (a->speed == 0) continue;
         a->growth += a->speed;
-        if (a->growth >= orthlim) 
-          coords = coords1;
 
-       if (a->growth >= diaglim) 
-          coords = coords2;
-
-        if (coords)
-          for (i = 0; i < 4; i++)
-            {
-              int x = a->x + coords[i].x;
-              int y = a->y + coords[i].y;
+       if (a->growth >= st->diaglim) 
+       {
+           coords = all_coords;
+       }
+        else if (a->growth >= st->orthlim)
+       {
+           coords = &all_coords[4];
+       }
+       else
+       {
+           continue;
+       }
 
-              if (x < 0) x = arr_width - 1;
-              else if (x >= arr_width) x = 0;
+       while (coords->x != 99)
+       {
+           int x = cell_x(a) + coords->x;
+           int y = cell_y(a) + coords->y;
+           coords++;
+
+           if (x < 0) x = st->arr_width - 1;
+           else if (x >= st->arr_width) x = 0;
+           
+           if (y < 0) y = st->arr_height - 1;
+           else if (y >= st->arr_height) y = 0;
+           
+           newcell (st, &st->arr[y * st->arr_width + x], a->col, a->speed);
+       }
 
-              if (y < 0) y = arr_height - 1;
-              else if (y >= arr_height) y = 0;
+       if (a->growth >= st->diaglim) 
+           killcell (st, a);
+    }
 
-              newcell (&arr[y * arr_width + x], a->col, a->speed);
-            }
+    randblip (st, (st->head->next) == st->tail);
 
-       if (a->growth >= diaglim) 
-           killcell (a);
-    }
-    
-    randblip ((head->next) == tail);
-    
-    for (a = head->next; a != tail; a = a->next)
+    for (a = st->head->next; a != st->tail; a = a->next)
     {
        if (a->isnext) 
        {
@@ -638,20 +664,63 @@ static void update (void)
            a->speed = a->nextspeed;
            a->growth = 0.0;
            a->col = a->nextcol;
-           drawblock (a->x, a->y, a->col + count);
+           drawblock (st, cell_x(a), cell_y(a), a->col + st->count);
        }
     }
 }
 
-\f
-char *progclass = "Petri";
+static void *
+petri_init (Display *dpy, Window win)
+{
+    struct state *st = (struct state *) calloc (1, sizeof(*st));
+    st->dpy = dpy;
+    st->window = win;
+
+    st->delay = get_integer_resource (st->dpy, "delay", "Delay");
+    st->orthlim = 1;
 
-char *defaults [] = {
+    setup_display (st);
+    setup_arr (st);
+    randblip (st, 1);
+    
+    return st;
+}
+
+static unsigned long
+petri_draw (Display *dpy, Window window, void *closure)
+{
+  struct state *st = (struct state *) closure;
+  update (st);
+  return st->delay;
+}
+
+static void
+petri_reshape (Display *dpy, Window window, void *closure, 
+                 unsigned int w, unsigned int h)
+{
+}
+
+static Bool
+petri_event (Display *dpy, Window window, void *closure, XEvent *event)
+{
+  return False;
+}
+
+static void
+petri_free (Display *dpy, Window window, void *closure)
+{
+  struct state *st = (struct state *) closure;
+  free (st);
+}
+
+
+
+static const char *petri_defaults [] = {
   ".background:                black",
   ".foreground:                white",
   "*delay:             10000",
-  "*count:             8",
-  "*size:              4",
+  "*count:             20",
+  "*size:              2",
   "*diaglim:           1.414",
   "*anychan:           0.0015",
   "*minorchan:         0.5",
@@ -668,7 +737,7 @@ char *defaults [] = {
     0
 };
 
-XrmOptionDescRec options [] = {
+static XrmOptionDescRec petri_options [] = {
   { "-delay",           ".delay",              XrmoptionSepArg, 0 },
   { "-size",            ".size",               XrmoptionSepArg, 0 },
   { "-count",           ".count",              XrmoptionSepArg, 0 },
@@ -687,22 +756,5 @@ XrmOptionDescRec options [] = {
   { 0, 0, 0, 0 }
 };
 
-void screenhack (Display *dpy, Window win)
-{
-    int delay = get_integer_resource ("delay", "Delay");
-    display = dpy;
-    window = win;
-    setup_display ();
-    
-    setup_arr ();
-    
-    randblip (1);
-    
-    for (;;) 
-    {
-       update ();
-        XSync (dpy, False);
-        screenhack_handle_events (dpy);
-       usleep (delay);
-    }
-}
+
+XSCREENSAVER_MODULE ("Petri", petri)