From http://www.jwz.org/xscreensaver/xscreensaver-5.35.tar.gz
[xscreensaver] / hacks / barcode.c
index 218e3a1db679c3d5feb7d722760ad03daeb7c716..cd3038ce534b1bf4fc109b621232a387bb3bf6db 100644 (file)
  * See the included man page for more details.
  */
 
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
 #include <math.h>
+#include <time.h>
 #include "screenhack.h"
-#include <X11/Xutil.h>
-
-
-
-/* parameters that are user configurable */
-
-/* delay (usec) between iterations */
-static int delay;
-
-static int scroll_p;
-
-
 
 /* non-user-modifiable immutable definitions */
 
@@ -42,20 +27,7 @@ static int scroll_p;
 
 #define BARCODE_WIDTH (164)
 #define BARCODE_HEIGHT (69)
-#define MAX_MAG (6)
-
-/* width and height of the window */
-static int windowWidth;
-static int windowHeight;
-
-static Display *display;        /* the display to draw on */
-static Window window;           /* the window to draw on */
-static Visual *visual;          /* the visual to use */
-static Screen *screen;          /* the screen to draw on */
-static Colormap cmap;           /* the colormap of the window */
-
-static GC theGC;                /* GC for drawing */
-
+#define MAX_MAG (7)
 
 
 /* simple bitmap structure */
@@ -65,7 +37,7 @@ typedef struct
     int width;
     int height;
     int widthBytes;
-    unsigned char *buf;
+    char *buf;
 }
 Bitmap;
 
@@ -84,254 +56,314 @@ typedef struct
 }
 Barcode;
 
-static Barcode *barcodes; /* array of barcodes */
-static int barcode_count; /* how many barcodes are currently active */
-static int barcode_max;   /* the maximum number of active barcodes */
+struct state {
+  Display *dpy;
+  Window window;
+
+  /* parameters that are user configurable */
+
+  /* delay (usec) between iterations */
+  int delay;
+
+  /* width and height of the window */
+  int windowWidth;
+  int windowHeight;
+
+  Visual *visual;          /* the visual to use */
+  Colormap cmap;           /* the colormap of the window */
 
-static XImage *theImage;  /* ginormo image for drawing */
-static Bitmap *theBitmap; /* ginormo bitmap for drawing */
+  GC theGC;                /* GC for drawing */
+  unsigned long fg_pixel, grid_pixel;
+  Bool button_down_p;
+  int grid_alloced_p;
+  char *strings[200];
+
+  Barcode *barcodes; /* array of barcodes */
+  int barcode_count; /* how many barcodes are currently active */
+  int barcode_max;   /* the maximum number of active barcodes */
+
+  XImage *theImage;  /* ginormo image for drawing */
+  Bitmap *theBitmap; /* ginormo bitmap for drawing */
+
+  enum { BC_SCROLL, BC_GRID, BC_CLOCK12, BC_CLOCK24 } mode;
+
+  int grid_w;
+  int grid_h;
+};
 
 /* a bunch of words */
-static char *words[] = 
+static const char *words[] = 
 {
-    "abdomen",
-    "abeyance",
-    "abhorrent",
-    "abrasive",
-    "abstract",
-    "acid",
-    "addiction",
-    "alertness",
-    "Algeria",
-    "anxiety",
-    "aorta",
-    "argyle socks",
-    "attrition",
-    "bamboo",
-    "bangle",
-    "bankruptcy",
-    "baptism",
-    "beer",
-    "bellicose",
-    "bells",
-    "belly",
-    "bread",
-    "bubba",
-    "burrito",
-    "California",
-    "capybara",
-    "cardinality",
-    "caribou",
-    "carnage",
-    "chocolate",
-    "constriction",
-    "contrition",
-    "corpse",
-    "cowboy",
-    "cozy",
-    "crabapple",
-    "craziness",
-    "Death",
-    "Decker",
-    "decoded",
-    "decoy",
-    "defenestration",
-    "dependency",
-    "despair",
-    "desperation",
-    "disease",
-    "doberman",
-    "dreams",
-    "drench",
-    "drugs",
-    "easy",
-    "ebony",
-    "elliptic",
-    "eloquence",
-    "emergency",
-    "eureka",
-    "excommunicate",
-    "fat",
-    "fatherland",
-    "Faust",
-    "fear",
-    "fever",
-    "flatulence",
-    "fluff",
-    "fnord",
-    "freedom",
-    "fruit",
-    "fruit",
-    "gauche",
-    "gawk",
-    "gaze",
-    "gerbils",
-    "GOD",
-    "goggles",
-    "goobers",
-    "gorilla",
-    "halibut",
-    "handmaid",
-    "hapless",
-    "happiness",
-    "hate",
-    "helplessness",
-    "hermaphrodite",
-    "Hindi",
-    "hope",
-    "hysteria",
-    "icepick",
-    "ignorance",
-    "importance",
-    "impossibility",
-    "inkling",
-    "insurrection",
-    "intoxicant",
-    "ire",
-    "irritant",
-    "jade",
-    "jaundice",
-    "Joyce",
-    "kaput",
-    "kitchenette",
-    "kiwi",
-    "lathe",
-    "lattice",
-    "lemming",
-    "liquidation",
-    "love",
-    "lozenge",
-    "magazine",
-    "magnesium",
-    "malfunction",
-    "marmot",
-    "marshmallow",
-    "merit",
-    "mescaline",
-    "milk",
-    "mischief",
-    "mistrust",
-    "money",
-    "monkey",
-    "monkeybutter",
-    "multiple",
-    "nature",
-    "neuron",
-    "noise",
-    "nomenclature",
-    "nutria",
-    "obey",
-    "ocelot",
-    "offspring",
-    "overseer",
-    "pain",
-    "pajamas",
-    "passenger",
-    "passion",
-    "Passover",
-    "Prozac",
-    "peace",
-    "penance",
-    "persimmon",
-    "petticoat",
-    "pharmacist",
-    "pitchfork",
-    "plague",
-    "Poindexter",
-    "precept",
-    "prison",
-    "prophecy",
-    "quadratic",
-    "quagmire",
-    "quarantine",
-    "quartz",
-    "rabies",
-    "radish",
-    "rage",
-    "readout",
-    "reality",
-    "reject",
-    "rejection",
-    "respect",
-    "revolution",
-    "roadrunner",
-    "rule",
-    "sanguine",
-    "savor",
-    "scab",
-    "scalar",
-    "Scandinavia",
-    "security",
-    "sediment",
-    "sickness",
-    "silicone",
-    "slack",
-    "slander",
-    "slavery",
-    "sledgehammer",
-    "smelly socks",
-    "sorrow",
-    "stamen",
-    "standardization",
-    "subversion",
-    "suffering",
-    "surrender",
-    "surveilance",
-    "synthesis",
-    "tenant",
-    "tendril",
-    "terror",
-    "terrorism",
-    "terrorist",
-    "the unknown",
-    "toast",
-    "topography",
-    "truism",
-    "turgid",
-    "underbrush",
-    "underling",
-    "unguent",
-    "unusual",
-    "unworthy",
-    "uplink",
-    "urge",
-    "valor",
-    "variance",
-    "vastness",
-    "vaudeville",
-    "vegetarian",
-    "venom",
-    "verifiability",
-    "viagra",
-    "vibrator",
-    "victim",
-    "vignette",
-    "villainy",
-    "W.A.S.T.E.",
-    "wagon",
-    "waiver",
-    "warehouse",
-    "waste",
-    "waveform",
-    "whiffle ball",
-    "whorl",
-    "windmill",
-    "wistful",
-    "worm",
-    "worship",
-    "worship",
-    "Xanax",
-    "Xerxes",
-    "Xhosa",
-    "xylophone",
-    "yellow",
-    "yesterday",
-    "your nose",
-    "Zanzibar",
-    "zeal",
-    "zebra",
-    "zest",
-    "zinc"
+  "abdomen",
+  "abeyance",
+  "abhorrence",
+  "abrasion",
+  "abstraction",
+  "acid",
+  "addiction",
+  "alertness",
+  "Algeria",
+  "anxiety",
+  "aorta",
+  "argyle socks",
+  "attrition",
+  "axis of evil",
+  "bamboo",
+  "bangle",
+  "bankruptcy",
+  "baptism",
+  "beer",
+  "bellicosity",
+  "bells",
+  "belly",
+  "bliss",
+  "bogosity",
+  "boobies",
+  "boobs",
+  "booty",
+  "bread",
+  "bubba",
+  "burrito",
+  "California",
+  "capybara",
+  "cardinality",
+  "caribou",
+  "carnage",
+  "children",
+  "chocolate",
+  "CLONE",
+  "cock",
+  "constriction",
+  "contrition",
+  "cop",
+  "corpse",
+  "cowboy",
+  "crabapple",
+  "craziness",
+  "cthulhu",
+  "Death",
+  "decepticon",
+  "deception",
+  "Decker",
+  "decoder",
+  "decoy",
+  "defenestration",
+  "democracy",
+  "dependency",
+  "despair",
+  "desperation",
+  "disease",
+  "disease",
+  "doberman",
+  "DOOM",
+  "dreams",
+  "dreams",
+  "drugs",
+  "easy",
+  "ebony",
+  "election",
+  "eloquence",
+  "emergency",
+  "eureka",
+  "excommunication",
+  "fat",
+  "fatherland",
+  "Faust",
+  "fear",
+  "fever",
+  "filth",
+  "flatulence",
+  "fluff",
+  "fnord",
+  "freedom",
+  "fruit",
+  "fruit",
+  "futility",
+  "gerbils",
+  "GOD",
+  "goggles",
+  "goobers",
+  "gorilla",
+  "halibut",
+  "handmaid",
+  "happiness",
+  "hate",
+  "helplessness",
+  "hemorrhoid",
+  "hermaphrodite",
+  "heroin",
+  "heroine",
+  "hope",
+  "hysteria",
+  "icepick",
+  "identity",
+  "ignorance",
+  "importance",
+  "individuality",
+  "inkling",
+  "insurrection",
+  "intoxicant",
+  "ire",
+  "irritant",
+  "jade",
+  "jaundice",
+  "Joyce",
+  "kidney stone",
+  "kitchenette",
+  "kiwi",
+  "lathe",
+  "lattice",
+  "lawyer",
+  "lemming",
+  "liquidation",
+  "lobbyist",
+  "love",
+  "lozenge",
+  "magazine",
+  "magnesium",
+  "malfunction",
+  "marmot",
+  "marshmallow",
+  "merit",
+  "merkin",
+  "mescaline",
+  "milk",
+  "mischief",
+  "mistrust",
+  "money",
+  "monkey",
+  "monkeybutter",
+  "nationalism",
+  "nature",
+  "neuron",
+  "noise",
+  "nomenclature",
+  "nutria",
+  "OBEY",
+  "ocelot",
+  "offspring",
+  "overseer",
+  "pain",
+  "pajamas",
+  "passenger",
+  "passion",
+  "Passover",
+  "peace",
+  "penance",
+  "persimmon",
+  "petticoat",
+  "pharmacist",
+  "PhD",
+  "pitchfork",
+  "plague",
+  "Poindexter",
+  "politician",
+  "pony",
+  "presidency",
+  "prison",
+  "prophecy",
+  "Prozac",
+  "punishment",
+  "punk rock",
+  "punk",
+  "pussy",
+  "quagmire",
+  "quarantine",
+  "quartz",
+  "rabies",
+  "radish",
+  "rage",
+  "readout",
+  "reality",
+  "rectum",
+  "reject",
+  "rejection",
+  "respect",
+  "revolution",
+  "roadrunner",
+  "rule",
+  "savor",
+  "scab",
+  "scalar",
+  "Scandinavia",
+  "schadenfreude",
+  "security",
+  "sediment",
+  "self worth",
+  "sickness",
+  "silicone",
+  "slack",
+  "slander",
+  "slavery",
+  "sledgehammer",
+  "smegma",
+  "smelly socks",
+  "sorrow",
+  "space program",
+  "stamen",
+  "standardization",
+  "stench",
+  "subculture",
+  "subversion",
+  "suffering",
+  "surrender",
+  "surveillance",
+  "synthesis",
+  "television",
+  "tenant",
+  "tendril",
+  "terror",
+  "terrorism",
+  "terrorist",
+  "the impossible",
+  "the unknown",
+  "toast",
+  "topography",
+  "truism",
+  "turgid",
+  "underbrush",
+  "underling",
+  "unguent",
+  "unusual",
+  "uplink",
+  "urge",
+  "valor",
+  "variance",
+  "vaudeville",
+  "vector",
+  "vegetarian",
+  "venom",
+  "verifiability",
+  "viagra",
+  "vibrator",
+  "victim",
+  "vignette",
+  "villainy",
+  "W.A.S.T.E.",
+  "wagon",
+  "waiver",
+  "warehouse",
+  "waste",
+  "waveform",
+  "whiffle ball",
+  "whorl",
+  "windmill",
+  "words",
+  "worm",
+  "worship",
+  "worship",
+  "Xanax",
+  "Xerxes",
+  "Xhosa",
+  "xylophone",
+  "yellow",
+  "yesterday",
+  "your nose",
+  "Zanzibar",
+  "zeal",
+  "zebra",
+  "zest",
+  "zinc"
 };
 
 #define WORD_COUNT (sizeof(words) / sizeof(char *))
@@ -343,7 +375,7 @@ static char *words[] =
  */
 
 /* construct a new bitmap */
-Bitmap *makeBitmap (int width, int height)
+static Bitmap *makeBitmap (int width, int height)
 {
     Bitmap *result = malloc (sizeof (Bitmap));
     result->width = width;
@@ -354,21 +386,24 @@ Bitmap *makeBitmap (int width, int height)
 }
 
 /* clear a bitmap */
-void bitmapClear (Bitmap *b)
+static void bitmapClear (Bitmap *b)
 {
     memset (b->buf, 0, b->widthBytes * b->height);
 }
 
+#if 0
 /* free a bitmap */
-void bitmapFree (Bitmap *b)
+static void bitmapFree (Bitmap *b)
 {
     free (b->buf);
     free (b);
 }
+#endif
+
 
 /* get the byte value at the given byte-offset coordinates in the given
  * bitmap */
-int bitmapGetByte (Bitmap *b, int xByte, int y)
+static int bitmapGetByte (Bitmap *b, int xByte, int y)
 {
     if ((xByte < 0) || 
        (xByte >= b->widthBytes) || 
@@ -383,7 +418,7 @@ int bitmapGetByte (Bitmap *b, int xByte, int y)
 }
 
 /* get the bit value at the given coordinates in the given bitmap */
-int bitmapGet (Bitmap *b, int x, int y)
+static int bitmapGet (Bitmap *b, int x, int y)
 {
     int xbyte = x >> 3;
     int xbit = x & 0x7;
@@ -393,7 +428,7 @@ int bitmapGet (Bitmap *b, int x, int y)
 }
 
 /* set the bit value at the given coordinates in the given bitmap */
-void bitmapSet (Bitmap *b, int x, int y, int value)
+static void bitmapSet (Bitmap *b, int x, int y, int value)
 {
     int xbyte = x >> 3;
     int xbit = x & 0x7;
@@ -418,8 +453,8 @@ void bitmapSet (Bitmap *b, int x, int y, int value)
 }
 
 /* copy the given rectangle to the given destination from the given source. */
-void bitmapCopyRect (Bitmap *dest, int dx, int dy,
-                    Bitmap *src, int sx, int sy, int width, int height)
+static void bitmapCopyRect (Bitmap *dest, int dx, int dy,
+                            Bitmap *src, int sx, int sy, int width, int height)
 {
     int x, y;
 
@@ -433,7 +468,7 @@ void bitmapCopyRect (Bitmap *dest, int dx, int dy,
 }
 
 /* draw a vertical line in the given bitmap */
-void bitmapVlin (Bitmap *b, int x, int y1, int y2)
+static void bitmapVlin (Bitmap *b, int x, int y1, int y2)
 {
     while (y1 <= y2)
     {
@@ -443,13 +478,13 @@ void bitmapVlin (Bitmap *b, int x, int y1, int y2)
 }
 
 /* scale a bitmap into another bitmap */
-void bitmapScale (Bitmap *dest, Bitmap *src, int mag)
+static void bitmapScale (Bitmap *dest, Bitmap *src, int mag)
 {
     int x, y, x2, y2;
 
-    for (y = 0; y < src->height; y++)
+    for (y = 0; y < BARCODE_HEIGHT; y++)
     {
-       for (x = 0; x < src->width; x++)
+       for (x = 0; x < BARCODE_WIDTH; x++)
        {
            int v = bitmapGet (src, x, y);
            for (x2 = 0; x2 < mag; x2++) 
@@ -558,16 +593,16 @@ static unsigned char font5x8Buf[] =
    0x0f, 0x0f, 0x0f, 0x00
 };
 
-static Bitmap font5x8 = { 8, 1024, 1, font5x8Buf };
+static Bitmap font5x8 = { 8, 1024, 1, (char *) font5x8Buf };
 
 /* draw the given 5x8 character at the given coordinates */
-void bitmapDrawChar5x8 (Bitmap *b, int x, int y, char c)
+static void bitmapDrawChar5x8 (Bitmap *b, int x, int y, char c)
 {
     bitmapCopyRect (b, x, y, &font5x8, 0, c * 8, 5, 8);
 }
 
 /* draw a string of 5x8 characters at the given coordinates */
-void bitmapDrawString5x8 (Bitmap *b, int x, int y, char *str)
+static void bitmapDrawString5x8 (Bitmap *b, int x, int y, char *str)
 {
     int origx = x;
 
@@ -742,34 +777,34 @@ typedef enum
 UpcSet;
 
 /* the Left A patterns */
-unsigned int upcLeftA[] = { 
+static unsigned int upcLeftA[] = { 
     0x0d, 0x19, 0x13, 0x3d, 0x23, 0x31, 0x2f, 0x3b, 0x37, 0x0b 
 };
 
 /* the Left B patterns */
-unsigned int upcLeftB[] = { 
+static unsigned int upcLeftB[] = { 
     0x27, 0x33, 0x1b, 0x21, 0x1d, 0x39, 0x05, 0x11, 0x09, 0x17
 };
 
 /* the Right patterns */
-unsigned int upcRight[] = { 
+static unsigned int upcRight[] = { 
     0x72, 0x66, 0x6c, 0x42, 0x5c, 0x4e, 0x50, 0x44, 0x48, 0x74
 };
 
 /* the EAN-13 first-digit patterns */
-unsigned int ean13FirstDigit[] = {
+static unsigned int ean13FirstDigit[] = {
     0x00, 0x0b, 0x0d, 0x0e, 0x13, 0x19, 0x1c, 0x15, 0x16, 0x1a
 };
 
 /* the UPC-E last-digit patterns for first digit 0 (complement for
  * digit 1); also used for 5-digit supplemental check patterns */
-unsigned int upcELastDigit[] = {
+static unsigned int upcELastDigit[] = {
     0x38, 0x34, 0x32, 0x31, 0x2c, 0x26, 0x23, 0x2a, 0x29, 0x25
 };
 
 /* turn a character into an int representing its digit value; return
  * 0 for things not in the range '0'-'9' */
-int charToDigit (char c)
+static int charToDigit (char c)
 {
     if ((c >= '0') && (c <= '9'))
     {
@@ -783,19 +818,19 @@ int charToDigit (char c)
 
 /* draw the given digit character at the given coordinates; a '0' is
  * used in place of any non-digit character */
-void drawDigitChar (Bitmap *b, int x, int y, char c)
+static void drawDigitChar (struct state *st, Bitmap *b, int x, int y, char c)
 {
+  if (st->mode != BC_CLOCK24 &&
+      st->mode != BC_CLOCK12)
     if ((c < '0') || (c > '9'))
-    {
-       c = '0';
-    }
+      c = '0';
 
-    bitmapDrawChar5x8 (b, x, y, c);
+  bitmapDrawChar5x8 (b, x, y, c);
 }
 
 /* draw a upc/ean digit at the given coordinates */
-void drawUpcEanDigit (Bitmap *upcBitmap, int x, int y1, int y2, char n, 
-                     UpcSet set)
+static void drawUpcEanDigit (Bitmap *upcBitmap, int x, int y1, int y2, char n, 
+                             UpcSet set)
 {
     unsigned int bits;
     int i;
@@ -826,7 +861,7 @@ void drawUpcEanDigit (Bitmap *upcBitmap, int x, int y1, int y2, char n,
 
 /* report the width of the given supplemental code or 0 if it is a bad
  * supplement form */
-int upcEanSupplementWidth (char *digits)
+static int upcEanSupplementWidth (char *digits)
 {
     switch (strlen (digits))
     {
@@ -837,8 +872,9 @@ int upcEanSupplementWidth (char *digits)
 }
 
 /* draw the given supplemental barcode, including the textual digits */
-void drawUpcEanSupplementalBars (Bitmap *upcBitmap, char *digits, 
-                                int x, int y, int y2, int textAbove)
+static void drawUpcEanSupplementalBars (struct state *st, 
+                                        Bitmap *upcBitmap, char *digits, 
+                                        int x, int y, int y2, int textAbove)
 {
     int len = strlen (digits);
     int i;
@@ -881,7 +917,8 @@ void drawUpcEanSupplementalBars (Bitmap *upcBitmap, char *digits,
        }
        default:
        {
-           printf("Bad supplement\n");
+           fprintf (stderr, "%s: bad supplement (%d digits)\n",
+                     progname, len);
            exit(1);
            break;
        }
@@ -912,13 +949,13 @@ void drawUpcEanSupplementalBars (Bitmap *upcBitmap, char *digits,
                         digits[i], 
                         lset);
 
-        drawDigitChar (upcBitmap, textX + i*6, textY, digits[i]);
+        drawDigitChar (st, upcBitmap, textX + i*6, textY, digits[i]);
     }
 }
 
 /* draw the actual barcode part of a UPC-A barcode */
-void drawUpcABars (Bitmap *upcBitmap, char *digits, int x, int y, 
-                  int barY2, int guardY2)
+static void drawUpcABars (Bitmap *upcBitmap, char *digits, int x, int y, 
+                          int barY2, int guardY2)
 {
     int i;
 
@@ -952,10 +989,10 @@ void drawUpcABars (Bitmap *upcBitmap, char *digits, int x, int y,
 }
 
 /* make and return a full-height UPC-A barcode */
-int makeUpcAFull (Bitmap *dest, char *digits, int y)
+static int makeUpcAFull (struct state *st, Bitmap *dest, char *digits, int y)
 {
-    static int baseWidth = 108;
-    static int baseHeight = 60;
+    int baseWidth = 108;
+    int baseHeight = 60;
 
     int height = baseHeight + y;
     int i;
@@ -963,21 +1000,21 @@ int makeUpcAFull (Bitmap *dest, char *digits, int y)
     bitmapClear (dest);
     drawUpcABars (dest, digits, 6, y, height - 10, height - 4);
 
-    drawDigitChar (dest, 0, height - 14, digits[0]);
+    drawDigitChar (st, dest, 0, height - 14, digits[0]);
 
     for (i = 0; i < 5; i++)
     {
-        drawDigitChar (dest, 18 + i*7, height - 7, digits[i+1]);
-        drawDigitChar (dest, 57 + i*7, height - 7, digits[i+6]);
+        drawDigitChar (st, dest, 18 + i*7, height - 7, digits[i+1]);
+        drawDigitChar (st, dest, 57 + i*7, height - 7, digits[i+6]);
     }
 
-    drawDigitChar (dest, 103, height - 14, digits[11]);
+    drawDigitChar (st, dest, 103, height - 14, digits[11]);
 
     return baseWidth;
 }
 
 /* make and return a UPC-A barcode */
-int makeUpcA (Bitmap *dest, char *digits, int y)
+static int makeUpcA (struct state *st, Bitmap *dest, char *digits, int y)
 {
     int i;
     unsigned int mul = 3;
@@ -994,37 +1031,57 @@ int makeUpcA (Bitmap *dest, char *digits, int y)
         digits[11] = ((10 - (sum % 10)) % 10) + '0';
     }
 
-    return makeUpcAFull (dest, digits, y);
+    return makeUpcAFull (st, dest, digits, y);
 }
 
 /* draw the actual barcode part of a UPC-E barcode */
-void drawUpcEBars (Bitmap *upcBitmap, char *digits, int x, int y, 
-                  int barY2, int guardY2)
+static void drawUpcEBars (struct state *st, 
+                          Bitmap *upcBitmap, char *digits, int x, int y, 
+                          int barY2, int guardY2)
 {
     int i;
     int parityPattern = upcELastDigit[charToDigit(digits[7])];
 
+    int clockp = (st->mode == BC_CLOCK12 || st->mode == BC_CLOCK24);
+
     if (digits[0] == '1')
     {
        parityPattern = ~parityPattern;
     }
 
     /* header */
-    bitmapVlin (upcBitmap, x, y, guardY2);
+    bitmapVlin (upcBitmap, x,     y, guardY2);
     bitmapVlin (upcBitmap, x + 2, y, guardY2);
 
     /* trailer */
-    bitmapVlin (upcBitmap, x + 46, y, guardY2);
-    bitmapVlin (upcBitmap, x + 48, y, guardY2);
-    bitmapVlin (upcBitmap, x + 50, y, guardY2);
+    bitmapVlin (upcBitmap, x + 46 + (clockp?8:0), y, guardY2);
+    bitmapVlin (upcBitmap, x + 48 + (clockp?8:0), y, guardY2);
+    bitmapVlin (upcBitmap, x + 50 + (clockp?8:0), y, guardY2);
+
+    /* clock kludge -- this draws an extra set of dividers after
+       digits 2 and 4.  This makes this *not* be a valid bar code,
+       but, it looks pretty for the clock dpy.
+     */
+    if (clockp)
+      {
+        bitmapVlin (upcBitmap, x + 18,     y, guardY2);
+        bitmapVlin (upcBitmap, x + 18 + 2, y, guardY2);
+
+        bitmapVlin (upcBitmap, x + 36,     y, guardY2);
+        bitmapVlin (upcBitmap, x + 36 + 2, y, guardY2);
+      }
 
     for (i = 0; i < 6; i++)
     {
        UpcSet lset = 
            (parityPattern & (1 << (5 - i))) ? UPC_LEFT_B : UPC_LEFT_A;
-
+        int off = (clockp
+                   ? (i < 2 ? 0 :
+                      i < 4 ? 4 :      /* extra spacing for clock bars */
+                              8)
+                   : 0);
         drawUpcEanDigit (upcBitmap,
-                        x + 3 + i*7
+                        x + 3 + i*7 + off,
                         y,
                         barY2,
                         digits[i + 1], 
@@ -1033,25 +1090,25 @@ void drawUpcEBars (Bitmap *upcBitmap, char *digits, int x, int y,
 }
 
 /* make and return a full-height UPC-E barcode */
-int makeUpcEFull (Bitmap *dest, char *digits, int y)
+static int makeUpcEFull (struct state *st, Bitmap *dest, char *digits, int y)
 {
-    static int baseWidth = 64;
-    static int baseHeight = 60;
+    int baseWidth = 64;
+    int baseHeight = 60;
 
     int height = baseHeight + y;
     int i;
 
     bitmapClear (dest);
-    drawUpcEBars (dest, digits, 6, y, height - 10, height - 4);
+    drawUpcEBars (st, dest, digits, 6, y, height - 10, height - 4);
 
-    drawDigitChar (dest, 0, height - 14, digits[0]);
+    drawDigitChar (st, dest, 0, height - 14, digits[0]);
 
     for (i = 0; i < 6; i++)
     {
-        drawDigitChar (dest, 11 + i*7, height - 7, digits[i+1]);
+        drawDigitChar (st, dest, 11 + i*7, height - 7, digits[i+1]);
     }
 
-    drawDigitChar (dest, 59, height - 14, digits[7]);
+    drawDigitChar (st, dest, 59, height - 14, digits[7]);
 
     return baseWidth;
 }
@@ -1060,7 +1117,7 @@ int makeUpcEFull (Bitmap *dest, char *digits, int y)
  * array, or just store '\0' into the first element, if the form factor
  * is incorrect; this will also calculate the check digit, if it is
  * specified as '?' */
-void expandToUpcADigits (char *compressed, char *expanded)
+static void expandToUpcADigits (char *compressed, char *expanded)
 {
     int i;
 
@@ -1144,7 +1201,7 @@ void expandToUpcADigits (char *compressed, char *expanded)
 }
 
 /* make and return a UPC-E barcode */
-int makeUpcE (Bitmap *dest, char *digits, int y)
+static int makeUpcE (struct state *st, Bitmap *dest, char *digits, int y)
 {
     char expandedDigits[13];
     char compressedDigits[9];
@@ -1161,12 +1218,12 @@ int makeUpcE (Bitmap *dest, char *digits, int y)
     
     compressedDigits[7] = expandedDigits[11];
 
-    return makeUpcEFull (dest, compressedDigits, y);
+    return makeUpcEFull (st, dest, compressedDigits, y);
 }
 
 /* draw the actual barcode part of a EAN-13 barcode */
-void drawEan13Bars (Bitmap *upcBitmap, char *digits, int x, int y, 
-                  int barY2, int guardY2)
+static void drawEan13Bars (Bitmap *upcBitmap, char *digits, int x, int y, 
+                           int barY2, int guardY2)
 {
     int i;
     int leftPattern = ean13FirstDigit[charToDigit (digits[0])];
@@ -1203,10 +1260,10 @@ void drawEan13Bars (Bitmap *upcBitmap, char *digits, int x, int y,
 }
 
 /* make and return a full-height EAN-13 barcode */
-int makeEan13Full (Bitmap *dest, char *digits, int y)
+static int makeEan13Full (struct state *st, Bitmap *dest, char *digits, int y)
 {
-    static int baseWidth = 102;
-    static int baseHeight = 60;
+    int baseWidth = 102;
+    int baseHeight = 60;
 
     int height = baseHeight + y;
     int i;
@@ -1214,19 +1271,19 @@ int makeEan13Full (Bitmap *dest, char *digits, int y)
     bitmapClear (dest);
     drawEan13Bars (dest, digits, 6, y, height - 10, height - 4);
 
-    drawDigitChar (dest, 0, height - 7, digits[0]);
+    drawDigitChar (st, dest, 0, height - 7, digits[0]);
 
     for (i = 0; i < 6; i++)
     {
-        drawDigitChar (dest, 11 + i*7, height - 7, digits[i+1]);
-        drawDigitChar (dest, 57 + i*7, height - 7, digits[i+7]);
+        drawDigitChar (st, dest, 11 + i*7, height - 7, digits[i+1]);
+        drawDigitChar (st, dest, 57 + i*7, height - 7, digits[i+7]);
     }
 
     return baseWidth;
 }
 
 /* make and return an EAN-13 barcode */
-int makeEan13 (Bitmap *dest, char *digits, int y)
+static int makeEan13 (struct state *st, Bitmap *dest, char *digits, int y)
 {
     int i;
     unsigned int mul = 1;
@@ -1243,12 +1300,12 @@ int makeEan13 (Bitmap *dest, char *digits, int y)
         digits[12] = ((10 - (sum % 10)) % 10) + '0';
     }
 
-    return makeEan13Full (dest, digits, y);
+    return makeEan13Full (st, dest, digits, y);
 }
 
 /* draw the actual barcode part of an EAN-8 barcode */
-void drawEan8Bars (Bitmap *upcBitmap, char *digits, int x, int y, 
-                  int barY2, int guardY2)
+static void drawEan8Bars (Bitmap *upcBitmap, char *digits, int x, int y, 
+                          int barY2, int guardY2)
 {
     int i;
 
@@ -1282,10 +1339,10 @@ void drawEan8Bars (Bitmap *upcBitmap, char *digits, int x, int y,
 }
 
 /* make and return a full-height EAN-8 barcode */
-int makeEan8Full (Bitmap *dest, char *digits, int y)
+static int makeEan8Full (struct state *st, Bitmap *dest, char *digits, int y)
 {
-    static int baseWidth = 68;
-    static int baseHeight = 60;
+    int baseWidth = 68;
+    int baseHeight = 60;
 
     int height = baseHeight + y;
     int i;
@@ -1295,15 +1352,15 @@ int makeEan8Full (Bitmap *dest, char *digits, int y)
 
     for (i = 0; i < 4; i++)
     {
-        drawDigitChar (dest, 5 + i*7, height - 7, digits[i]);
-        drawDigitChar (dest, 37 + i*7, height - 7, digits[i+4]);
+        drawDigitChar (st, dest, 5 + i*7, height - 7, digits[i]);
+        drawDigitChar (st, dest, 37 + i*7, height - 7, digits[i+4]);
     }
 
     return baseWidth;
 }
 
 /* make and return an EAN-8 barcode */
-int makeEan8 (Bitmap *dest, char *digits, int y)
+static int makeEan8 (struct state *st, Bitmap *dest, char *digits, int y)
 {
     int i;
     unsigned int mul = 3;
@@ -1320,11 +1377,11 @@ int makeEan8 (Bitmap *dest, char *digits, int y)
         digits[7] = ((10 - (sum % 10)) % 10) + '0';
     }
 
-    return makeEan8Full (dest, digits, y);
+    return makeEan8Full (st, dest, digits, y);
 }
 
 /* Dispatch to the right form factor UPC/EAN barcode generator */
-void processUpcEan (char *str, Bitmap *dest)
+static void processUpcEan (struct state *st, char *str, Bitmap *dest)
 {
     char digits[16];
     int digitCount = 0;
@@ -1381,7 +1438,8 @@ void processUpcEan (char *str, Bitmap *dest)
     }
     else
     {
-       printf ("Invalid supplement (must be 2 or 5 digits)\n");
+       fprintf (stderr, "%s: invalid supplement (must be 2 or 5 digits)\n",
+                 progname);
        exit (1);
     }
 
@@ -1394,34 +1452,35 @@ void processUpcEan (char *str, Bitmap *dest)
     {
        case 7: 
        {
-           width = makeUpcE (dest, digits, vstart);
+           width = makeUpcE (st, dest, digits, vstart);
            break;
        }
        case 8: 
        {
-           width = makeEan8 (dest, digits, vstart);
+           width = makeEan8 (st, dest, digits, vstart);
            break;
        }
        case 12: 
        {
-           width = makeUpcA (dest, digits, vstart);
+           width = makeUpcA (st, dest, digits, vstart);
            break;
        }
        case 13:
        {
-           width = makeEan13 (dest, digits, vstart);
+           width = makeEan13 (st, dest, digits, vstart);
            break;
        }
        default:
        {
-           printf("Bad barcode\n");
+           fprintf (stderr, "%s: bad barcode (%d digits)\n",
+                     progname, digitCount);
            exit(1);
        }
     }
 
     if (supplement)
     {
-       drawUpcEanSupplementalBars (dest, supDigits,
+       drawUpcEanSupplementalBars (st, dest, supDigits,
                                    width,
                                    vstart + 1, dest->height - 4, 1);
     }
@@ -1447,29 +1506,31 @@ void processUpcEan (char *str, Bitmap *dest)
  */
 
 /* set up the system */
-static void setup (void)
+static void setup (struct state *st)
 {
     XWindowAttributes xgwa;
     XGCValues gcv;
 
-    XGetWindowAttributes (display, window, &xgwa);
-
-    screen = xgwa.screen;
-    visual = xgwa.visual;
-    cmap = xgwa.colormap;
-    windowWidth = xgwa.width;
-    windowHeight = xgwa.height;
-
-    gcv.background = get_pixel_resource ("background", "Background",
-                                        display, xgwa.colormap);
-    gcv.foreground = get_pixel_resource ("foreground", "Foreground",
-                                        display, xgwa.colormap);
-    theGC = XCreateGC (display, window, GCForeground|GCBackground, &gcv);
-
-    theBitmap = makeBitmap(BARCODE_WIDTH * MAX_MAG, BARCODE_HEIGHT * MAX_MAG);
-    theImage = XCreateImage(display, visual, 1, XYBitmap, 0, theBitmap->buf,
-                           theBitmap->width, theBitmap->height, 8,
-                           theBitmap->widthBytes);
+    XGetWindowAttributes (st->dpy, st->window, &xgwa);
+
+    st->visual = xgwa.visual;
+    st->cmap = xgwa.colormap;
+    st->windowWidth = xgwa.width;
+    st->windowHeight = xgwa.height;
+
+    gcv.background = get_pixel_resource (st->dpy, xgwa.colormap,
+                                         "background", "Background");
+    gcv.foreground = get_pixel_resource (st->dpy, xgwa.colormap,
+                                         "foreground", "Foreground");
+    st->fg_pixel = gcv.foreground;
+    st->theGC = XCreateGC (st->dpy, st->window, GCForeground|GCBackground, &gcv);
+
+    st->theBitmap = makeBitmap(BARCODE_WIDTH * MAX_MAG, BARCODE_HEIGHT * MAX_MAG);
+    st->theImage = XCreateImage(st->dpy, st->visual, 1, XYBitmap, 0, st->theBitmap->buf,
+                           st->theBitmap->width, st->theBitmap->height, 8,
+                           st->theBitmap->widthBytes);
+    st->theImage->bitmap_bit_order = LSBFirst;
+    st->theImage->byte_order       = LSBFirst;
 }
 
 
@@ -1479,23 +1540,23 @@ static void setup (void)
  */
 
 /* set up the model */
-static void setupModel (void)
+static void setupModel (struct state *st)
 {
     int i;
 
-    barcode_max = 20;
-    barcode_count = 0;
-    barcodes = malloc (sizeof (Barcode) * barcode_max);
+    st->barcode_max = 20;
+    st->barcode_count = 0;
+    st->barcodes = malloc (sizeof (Barcode) * st->barcode_max);
 
-    for (i = 0; i < barcode_max; i++)
+    for (i = 0; i < st->barcode_max; i++)
     {
-       barcodes[i].bitmap = makeBitmap(BARCODE_WIDTH * MAX_MAG, 
+       st->barcodes[i].bitmap = makeBitmap(BARCODE_WIDTH * MAX_MAG, 
                                        BARCODE_HEIGHT * MAX_MAG);
     }
 }
 
 /* make a new barcode string */
-static void makeBarcodeString (char *str)
+static void makeBarcodeString (struct state *st, char *str)
 {
     int dig, i;
 
@@ -1541,120 +1602,113 @@ static void makeBarcodeString (char *str)
 }
 
 /* update the model for one iteration */
-static void scrollModel (void)
+static void scrollModel (struct state *st)
 {
     int i;
 
-    for (i = 0; i < barcode_count; i++) 
+    for (i = 0; i < st->barcode_count; i++) 
     {
-       Barcode *b = &barcodes[i];
+       Barcode *b = &st->barcodes[i];
        b->x--;
        if ((b->x + BARCODE_WIDTH * b->mag) < 0) 
        {
            /* fell off the edge */
-           if (i != (barcode_count - 1)) {
+           if (i != (st->barcode_count - 1)) {
                Bitmap *oldb = b->bitmap;
-               memmove (b, b + 1, (barcode_count - i - 1) * sizeof (Barcode));
-               barcodes[barcode_count - 1].bitmap = oldb;
+               memmove (b, b + 1, (st->barcode_count - i - 1) * sizeof (Barcode));
+               st->barcodes[st->barcode_count - 1].bitmap = oldb;
 
-                XFreeColors (display, cmap, &b->pixel, 1, 0);
+                XFreeColors (st->dpy, st->cmap, &b->pixel, 1, 0);
            }
 
            i--;
-           barcode_count--;
+           st->barcode_count--;
        }
     }
 
-    while (barcode_count < barcode_max)
+    while (st->barcode_count < st->barcode_max)
     {
-       Barcode *barcode = &barcodes[barcode_count];
-       barcode->x = (barcode_count == 0) ? 
+       Barcode *barcode = &st->barcodes[st->barcode_count];
+       barcode->x = (st->barcode_count == 0) ? 
            0 : 
-           (barcodes[barcode_count - 1].x + 
-            barcodes[barcode_count - 1].mag * BARCODE_WIDTH);
+           (st->barcodes[st->barcode_count - 1].x + 
+            st->barcodes[st->barcode_count - 1].mag * BARCODE_WIDTH);
        barcode->x += RAND_FLOAT_01 * 100;
        barcode->mag = RAND_FLOAT_01 * MAX_MAG;
        barcode->y =
-           RAND_FLOAT_01 * (windowHeight - BARCODE_HEIGHT * barcode->mag);
+           RAND_FLOAT_01 * (st->windowHeight - BARCODE_HEIGHT * barcode->mag);
        if (barcode->y < 0) 
        {
            barcode->y = 0;
        }
-       makeBarcodeString(barcode->code);
-       processUpcEan (barcode->code, theBitmap);
-       bitmapScale (barcode->bitmap, theBitmap, barcode->mag);
+       makeBarcodeString(st, barcode->code);
+       processUpcEan (st, barcode->code, st->theBitmap);
+       bitmapScale (barcode->bitmap, st->theBitmap, barcode->mag);
 
         {
           XColor c;
-          int i, ok = 0;
-          for (i = 0; i < 100; i++)
+          int ii, ok = 0;
+          for (ii = 0; ii < 100; ii++)
             {
               hsv_to_rgb (random() % 360, 1.0, 1.0, &c.red, &c.green, &c.blue);
-              ok = XAllocColor (display, cmap, &c);
+              ok = XAllocColor (st->dpy, st->cmap, &c);
               if (ok) break;
             }
           if (!ok)
             {
               c.red = c.green = c.blue = 0xFFFF;
-              if (!XAllocColor (display, cmap, &c))
+              if (!XAllocColor (st->dpy, st->cmap, &c))
                 abort();
             }
           barcode->pixel = c.pixel;
         }
 
-       barcode_count++;
+       st->barcode_count++;
     }
 }
 
 /* update the model for one iteration */
-static void updateGrid (void)
+static void updateGrid (struct state *st)
 {
     int i, x, y;
-    static int grid_w = 0;
-    static int grid_h = 0;
 
-    static unsigned long pixel;
-    static int alloced_p = 0;
-
-    static char *strings[200] = { 0, };
-
-    if (grid_w == 0 || grid_h == 0 ||
+    if (st->grid_w == 0 || st->grid_h == 0 ||
         (! (random() % 400)))
       {
-        XClearWindow (display, window);
-        grid_w = 1 + (random() % 3);
-        grid_h = 1 + (random() % 4);
+        XClearWindow (st->dpy, st->window);
+        st->grid_w = 1 + (random() % 3);
+        st->grid_h = 1 + (random() % 4);
       }
 
-    if (!alloced_p || (! (random() % 100)))
+    if (!st->grid_alloced_p || (! (random() % 100)))
       {
         XColor c;
         hsv_to_rgb (random() % 360, 1.0, 1.0, &c.red, &c.green, &c.blue);
-        if (alloced_p)
-          XFreeColors (display, cmap, &pixel, 1, 0);
-        XAllocColor (display, cmap, &c);
-        pixel = c.pixel;
-        alloced_p = 1;
+        if (st->grid_alloced_p)
+          XFreeColors (st->dpy, st->cmap, &st->grid_pixel, 1, 0);
+        XAllocColor (st->dpy, st->cmap, &c);
+        st->grid_pixel = c.pixel;
+        st->grid_alloced_p = 1;
       }
 
-    barcode_count = grid_w * grid_h;
-    if (barcode_count > barcode_max) abort();
+    st->barcode_count = st->grid_w * st->grid_h;
+    if (st->barcode_count > st->barcode_max) abort();
 
-    for (i = 0; i < barcode_max; i++)
+    for (i = 0; i < st->barcode_max; i++)
       {
-        Barcode *b = &barcodes[i];
+        Barcode *b = &st->barcodes[i];
         b->x = b->y = 999999;
       }
 
     i = 0;
-    for (y = 0; y < grid_h; y++)
-      for (x = 0; x < grid_w; x++, i++)
+    for (y = 0; y < st->grid_h; y++)
+      for (x = 0; x < st->grid_w; x++, i++)
         {
-          Barcode *b = &barcodes[i];
+          Barcode *b = &st->barcodes[i];
           int digits = 12;
 
-          int cell_w = (windowWidth  / grid_w);
-          int cell_h = (windowHeight / grid_h);
+          int cell_w = (st->windowWidth  / st->grid_w);
+          int cell_h = (st->windowHeight / st->grid_h);
           int mag_x  = cell_w / BARCODE_WIDTH;
           int mag_y  = cell_h / BARCODE_HEIGHT;
           int BW = 108 /*BARCODE_WIDTH*/;
@@ -1664,48 +1718,142 @@ static void updateGrid (void)
 
           b->x = (x * cell_w) + ((cell_w - b->mag * BW) / 2);
           b->y = (y * cell_h) + ((cell_h - b->mag * BH) / 2);
-          b->pixel = pixel;
+          b->pixel = st->grid_pixel;
 
-          if (!strings[i])
+          if (!st->strings[i])
             {
               int j;
               char *s = malloc (digits + 10);
-              strings[i] = s;
+              st->strings[i] = s;
               for (j = 0; j < digits; j++)
                 s[j] = (random() % 10) + '0';
               s[j++] = '?';
               s[j++] = ':';
-              s[j++] = 0;
+              s[j] = 0;
             }
 
           /* change one digit in this barcode */
-          strings[i][random() % digits] = (random() % 10) + '0';
+          st->strings[i][random() % digits] = (random() % 10) + '0';
 
-          strcpy (b->code, strings[i]);
-          processUpcEan (b->code, b->bitmap);
+          strcpy (b->code, st->strings[i]);
+          processUpcEan (st, b->code, b->bitmap);
         }
 }
 
 
+/* update the model for one iteration.
+   This one draws a clock.  By jwz.  */
+static void updateClock (struct state *st)
+{
+  Barcode *b = &st->barcodes[0];
+  int BW = 76 /* BARCODE_WIDTH  */;
+  int BH = BARCODE_HEIGHT;
+  int mag_x, mag_y;
+  int i;
+  time_t now = time ((time_t *) 0);
+  struct tm *tm = localtime (&now);
+  XWindowAttributes xgwa;
+  int ow = st->windowWidth;
+  int oh = st->windowHeight;
+
+  XGetWindowAttributes (st->dpy, st->window, &xgwa);
+  st->windowWidth = xgwa.width;
+  st->windowHeight = xgwa.height;
+
+  mag_x  = st->windowWidth  / BW;
+  mag_y  = st->windowHeight / BH;
+
+  st->barcode_count = 1;
+
+  b->mag = (mag_x < mag_y ? mag_x : mag_y);
+
+  if (b->mag > MAX_MAG) b->mag = MAX_MAG;
+  if (b->mag < 1) b->mag = 1;
+
+  b->x = (st->windowWidth  - (b->mag * BW      )) / 2;
+  b->y = (st->windowHeight - (b->mag * (BH + 9))) / 2;
+  b->pixel = st->fg_pixel;
+
+  if (!st->button_down_p)
+    sprintf (b->code, "0%02d%02d%02d?:",
+             (st->mode == BC_CLOCK24
+              ? tm->tm_hour
+              : (tm->tm_hour > 12
+                 ? tm->tm_hour - 12
+                 : (tm->tm_hour == 0
+                    ? 12
+                    : tm->tm_hour))),
+             tm->tm_min,
+             tm->tm_sec);
+  else
+    sprintf (b->code, "0%02d%02d%02d?:",
+             tm->tm_year % 100, tm->tm_mon+1, tm->tm_mday);
+
+  {
+    int vstart = 9;
+    int hh = BH + vstart;
+    char expandedDigits[13];
 
-/* render and display the current model */
-static void renderFrame (void)
+    expandedDigits[0] = '\0';
+
+    expandToUpcADigits (b->code, expandedDigits);
+    if (expandedDigits[0] != '\0')
+      b->code[7] = expandedDigits[11];
+
+    bitmapClear (st->theBitmap);
+    drawUpcEBars (st, st->theBitmap, b->code, 6, 9, 59, 65);
+    for (i = 0; i < 6; i++)
+      {
+        int off = (i < 2 ? 0 :
+                   i < 4 ? 4 :
+                   8);
+        drawDigitChar (st, st->theBitmap, 11 + i*7 + off, hh - 16, b->code[i+1]);
+      }
+
+    if (!st->button_down_p)
+      {
+#if 0
+        char *days[] = { "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" };
+        char *s = days[tm->tm_wday];
+        bitmapDrawString5x8 (st->theBitmap, (BW - strlen (s)*5) / 2, 0, s);
+#endif
+        drawDigitChar (st, st->theBitmap,  0, hh - 23, (tm->tm_hour < 12 ? 'A' : 'P'));
+        drawDigitChar (st, st->theBitmap, 68, hh - 23, 'M');
+      }
+    else
+      {
+        char s[20];
+        sprintf (s, "%03d", tm->tm_yday);
+        bitmapDrawString5x8 (st->theBitmap, (BW - strlen (s)*5) / 2, 0, s);
+      }
+  }
+
+  bitmapScale (b->bitmap, st->theBitmap, b->mag);
+
+  if (ow != st->windowWidth || oh != st->windowHeight)
+    XClearWindow (st->dpy, st->window);
+}
+
+
+
+/* render and dpy the current model */
+static void renderFrame (struct state *st)
 {
     int i;
 
-    for (i = 0; i < barcode_count; i++)
+    for (i = 0; i < st->barcode_count; i++)
     {
-       Barcode *barcode = &barcodes[i];
+       Barcode *barcode = &st->barcodes[i];
 
-       if (barcode->x > windowWidth) {
+       if (barcode->x > st->windowWidth) {
            break;
        }
 
-       /* bitmapScale (theBitmap, barcode->bitmap, barcode->mag);*/
-       theImage->data = barcode->bitmap->buf;
+       /* bitmapScale (st->theBitmap, barcode->bitmap, barcode->mag);*/
+       st->theImage->data = barcode->bitmap->buf;
 
-        XSetForeground (display, theGC, barcode->pixel);
-       XPutImage (display, window, theGC, theImage, 
+        XSetForeground (st->dpy, st->theGC, barcode->pixel);
+       XPutImage (st->dpy, st->window, st->theGC, st->theImage, 
                   0, 0, barcode->x, barcode->y, 
                   BARCODE_WIDTH * barcode->mag,
                   BARCODE_HEIGHT * barcode->mag);
@@ -1713,46 +1861,109 @@ static void renderFrame (void)
 }
 
 /* do one iteration */
-static void oneIteration (void)
+static unsigned long
+barcode_draw (Display *dpy, Window win, void *closure)
 {
-    if (scroll_p)
-      scrollModel ();
+  struct state *st = (struct state *) closure;
+    if (st->mode == BC_SCROLL)
+      scrollModel (st);
+    else if (st->mode == BC_GRID)
+      updateGrid (st);
+    else if (st->mode == BC_CLOCK12 || st->mode == BC_CLOCK24)
+      updateClock (st);
     else
-      updateGrid ();
-    renderFrame ();
+      abort();
+
+    renderFrame (st);
+
+    return st->delay;
 }
 
 
+static Bool
+barcode_event (Display *dpy, Window window, void *closure, XEvent *event)
+{
+  struct state *st = (struct state *) closure;
+  int clockp = (st->mode == BC_CLOCK12 || st->mode == BC_CLOCK24);
+  if (clockp && event->xany.type == ButtonPress) {
+    st->button_down_p = True;
+    return True;
+  } else if (clockp && event->xany.type == ButtonRelease) {
+    st->button_down_p = False;
+    return True;
+  } else
+    return False;
+}
 
-/* main and options and stuff */
+static void
+barcode_reshape (Display *dpy, Window window, void *closure, 
+                 unsigned int w, unsigned int h)
+{
+  struct state *st = (struct state *) closure;
+  st->windowWidth = w;
+  st->windowHeight = h;
+}
 
-char *progclass = "Barcode";
+static void
+barcode_free (Display *dpy, Window window, void *closure)
+{
+}
+
+
+/* main and options and stuff */
 
-char *defaults [] = {
+static const char *barcode_defaults [] = {
     ".background:      black",
-    ".foreground:      white",
+    ".foreground:      green",
+    "*fpsSolid:        true",
     "*delay:           10000",
+    "*mode:            scroll",
     0
 };
 
-XrmOptionDescRec options [] = {
+static XrmOptionDescRec barcode_options [] = {
   { "-delay",            ".delay",          XrmoptionSepArg, 0 },
+  { "-mode",             ".mode",           XrmoptionSepArg, 0 },
+  { "-scroll",           ".mode",           XrmoptionNoArg, "scroll"  },
+  { "-grid",             ".mode",           XrmoptionNoArg, "grid"    },
+  { "-clock",            ".mode",           XrmoptionNoArg, "clock"   },
+  { "-clock12",          ".mode",           XrmoptionNoArg, "clock12" },
+  { "-clock24",          ".mode",           XrmoptionNoArg, "clock24" },
   { 0, 0, 0, 0 }
 };
 
 /* initialize the user-specifiable params */
-static void initParams (void)
+static void initParams (struct state *st)
 {
     int problems = 0;
+    char *s;
 
-    delay = get_integer_resource ("delay", "Delay");
-    if (delay < 0)
+    st->delay = get_integer_resource (st->dpy, "delay", "Delay");
+    if (st->delay < 0)
     {
-       fprintf (stderr, "error: delay must be at least 0\n");
+       fprintf (stderr, "%s: delay must be at least 0\n", progname);
        problems = 1;
     }
 
-    scroll_p = 1;
+    s = get_string_resource (st->dpy, "mode", "Mode");
+    if (!s || !*s || !strcasecmp (s, "scroll"))
+      st->mode = BC_SCROLL;
+    else if (!strcasecmp (s, "grid"))
+      st->mode = BC_GRID;
+    else if (!strcasecmp (s, "clock") ||
+             !strcasecmp (s, "clock12"))
+      st->mode = BC_CLOCK12;
+    else if (!strcasecmp (s, "clock24"))
+      st->mode = BC_CLOCK24;
+    else
+      {
+       fprintf (stderr, "%s: unknown mode \"%s\"\n", progname, s);
+       problems = 1;
+      }
+    free (s);
+
+    if (st->mode == BC_CLOCK12 || st->mode == BC_CLOCK24)
+      st->delay = 10000;  /* only update every 1/10th second */
 
     if (problems)
     {
@@ -1760,21 +1971,18 @@ static void initParams (void)
     }
 }
 
-/* main function */
-void screenhack (Display *dpy, Window win)
+static void *
+barcode_init (Display *dpy, Window win)
 {
-    display = dpy;
-    window = win;
+  struct state *st = (struct state *) calloc (1, sizeof(*st));
+  st->dpy = dpy;
+  st->window = win;
+
+  initParams (st);
+  setup (st);
+  setupModel (st);
+  return st;
+}
 
-    initParams ();
-    setup ();
-    setupModel ();
 
-    for (;;) 
-    {
-       oneIteration ();
-        XSync (dpy, False);
-        screenhack_handle_events (dpy);
-       usleep (delay);
-    }
-}
+XSCREENSAVER_MODULE ("Barcode", barcode)