http://slackware.bholcomb.com/slackware/slackware-11.0/source/xap/xscreensaver/xscree...
[xscreensaver] / hacks / munch.c
index b3cd73517d2c477dc638eb727a72a7bdd1586476..226edc210dd211768627c833dd1ea84b5cd196f7 100644 (file)
 #define SHIFT_KY (0x04)
 #define GRAV     (0x08)
 
-char *progclass = "Munch";
 
-char *defaults [] = {
-    ".background:      black",
-    ".foreground:      white",
-    "*delay:           5000",
-    "*hold:            100000",
-    "*clear:           50",
-    "*logminwidth:     7",
-    "*shift:           True",
-    "*xor:             True",
-    0
-};
+struct state {
+  Display *dpy;
+  Window window;
 
-XrmOptionDescRec options [] = {
-    { "-delay",                ".delay",       XrmoptionSepArg, 0 },
-    { "-hold",         ".hold",        XrmoptionSepArg, 0 },
-    { "-clear",         ".clear",       XrmoptionSepArg, "true" },
-    { "-shift",         ".shift",       XrmoptionNoArg, "true" },
-    { "-no-shift",     ".shift",       XrmoptionNoArg, "false" },
-    { "-logminwidth",  ".logminwidth", XrmoptionSepArg, 0 },
-    { "-xor",           ".xor",                XrmoptionNoArg, "true" },
-    { "-no-xor",       ".xor",         XrmoptionNoArg, "false" },
-    { 0, 0, 0, 0 }
-};
+  GC gc;
+  int delay, hold, clear, logminwidth, shiftk, xor;
 
+  int logmaxwidth;
+  int maxwidth;
+  int randflags;
+  int thiswidth;
+  XWindowAttributes xgwa;
 
-static GC gc;
-/* only configurable things right now */
-static int delay, hold, clear, logminwidth, shiftk, xor;
+  int munch_t;
 
-static void munchOnce (Display* dpy, Window w,
-                      int width, /* pixels */
-                      int atX, int atY, /* pixels */
-                      int kX, int kT, int kY, /* pixels */
-                      int grav /* 0 or not */) {
+  int reset;
+  int atX, atY, kX, kT, kY, grav;
+  int square_count;
+};
 
-    int x, y, t;
-    static Colormap cmap;
-    XWindowAttributes xgwa;
-    XColor fgc;
-    int drawX, drawY;
 
-    /*
-    fprintf(stderr,"Doing width %d at %d %d shift %d %d %d grav %d\n",
-           width, atX, atY, kX, kT, kY, grav);
-           */
-    
-    XGetWindowAttributes (dpy, w, &xgwa);
+static int munchOnce (struct state *st, int width)
+{
 
-    if (!mono_p) {
-       /* XXX there are probably bugs with this. */
-       cmap = xgwa.colormap;
-   
+    if (st->munch_t == 0) {
+      /*
+        fprintf(stderr,"Doing width %d at %d %d shift %d %d %d grav %d\n",
+        width, atX, atY, kX, kT, kY, grav);
+      */
+    
+      if (!mono_p) {
+        XColor fgc;
        fgc.red = random() % 65535;
        fgc.green = random() % 65535;
        fgc.blue = random() % 65535;
     
-       if (XAllocColor(dpy, cmap, &fgc)) {
-           XSetForeground(dpy, gc, fgc.pixel);
+       if (XAllocColor(st->dpy, st->xgwa.colormap, &fgc)) {
+          XSetForeground(st->dpy, st->gc, fgc.pixel);
        }
+      }
     }
     
     /* Finally draw this munching square. */
-    for(t = 0; t < width; t++) {
-       for(x = 0; x < width; x++) {
-           /* figure out the next point */
-           y = ((x ^ ((t + kT) % width)) + kY) % width;
-
-           drawX = ((x + kX) % width) + atX;
-           drawY = (grav ? y + atY : atY + width - 1 - y);
-
-           /* used to be bugs where it would draw partially offscreen.
-              while that might be a pretty feature, I didn't want it to do
-              that yet.  if these trigger, please let me know.
-              */
-/*         assert(drawX >= 0 && drawX < xgwa.width);
-           assert(drawY >= 0 && drawY < xgwa.height);
-*/
-
-           XDrawPoint(dpy, w, gc, drawX, drawY);
-           /* XXX may want to change this to XDrawPoints,
-              but it's fast enough without it for the moment. */
+    /* for(munch_t = 0; munch_t < width; munch_t++) */
+    {
+      int x;
+      for(x = 0; x < width; x++) {
+        /* figure out the next point */
+        int y = ((x ^ ((st->munch_t + st->kT) % width)) + st->kY) % width;
+        int drawX = ((x + st->kX) % width) + st->atX;
+        int drawY = (st->grav ? y + st->atY : st->atY + width - 1 - y);
+
+        /* used to be bugs where it would draw partially offscreen.
+           while that might be a pretty feature, I didn'munch_t want it to do
+           that yet.  if these trigger, please let me know.
+        */
+        /*         assert(drawX >= 0 && drawX < xgwa.width);
+          assert(drawY >= 0 && drawY < xgwa.height);
+        */
+
+        XDrawPoint(st->dpy, st->window, st->gc, drawX, drawY);
+        /* XXX may want to change this to XDrawPoints,
+           but it's fast enough without it for the moment. */
            
-       }
-       
-       /* we've drawn one pass' worth of points.  let the server catch up
-          or this won't be interesting to watch at all.  we call this here
-          in the hopes of having one whole sequence of dots appear at the
-          same time (one for each value of x, surprisingly enough)
-          */
-       XSync(dpy, False);
-        screenhack_handle_events (dpy);
-       if (delay) usleep(delay);
+      }
+    }
+
+    st->munch_t++;
+    if (st->munch_t >= width) {
+      st->munch_t = 0;
+      return 1;
     }
+
+    return 0;
 }
 
 /*
  * dumb way to get # of digits in number.  Probably faster than actually
  * doing a log and a division, maybe.
  */
-static int dumb_log_2(int k) {
+static int dumb_log_2(int k)
+{
     int r = -1;
     while (k > 0) {
        k >>= 1; r++;
@@ -150,109 +131,168 @@ static int dumb_log_2(int k) {
     return r;
 }
 
-/* This parses arguments, initializes the window, etc., and finally starts
- * calling munchOnce ad infinitum.
- */
-void
-screenhack (dpy, w) Display *dpy; Window w;
+static void *
+munch_init (Display *dpy, Window w)
 {
-    int logmaxwidth;
-    int maxwidth;
-    XWindowAttributes xgwa;
-    Colormap cmap;
+    struct state *st = (struct state *) calloc (1, sizeof(*st));
     XGCValues gcv;
-    int n = 0;  /* number of squares before we have to clear */
-    int randflags;
-    int thiswidth;
     
+    st->dpy = dpy;
+    st->window = w;
+
     /* get the dimensions of the window */
-    XGetWindowAttributes (dpy, w, &xgwa);
+    XGetWindowAttributes (st->dpy, w, &st->xgwa);
     
     /* We need a square; limit on screen size? */
     /* we want a power of 2 for the width or the munch doesn't fill up.
      */
-    logmaxwidth = (int)
-       dumb_log_2(xgwa.height < xgwa.width ? xgwa.height : xgwa.width);
+    st->logmaxwidth = (int)
+       dumb_log_2(st->xgwa.height < st->xgwa.width ? st->xgwa.height : st->xgwa.width);
 
-    maxwidth = 1 << logmaxwidth;
+    st->maxwidth = 1 << st->logmaxwidth;
 
-    if (logmaxwidth < logminwidth) {
+    if (st->logmaxwidth < st->logminwidth) {
        /* off-by-one error here?  Anyone running on < 640x480? */
        fprintf(stderr, "munch: screen too small; use -logminwidth\n");
        fprintf(stderr, "\t(width is %d; log is %d; log must be at least "
                "%d)\n", 
-               (xgwa.height < xgwa.width ? xgwa.height : xgwa.width),
-               logmaxwidth, logminwidth);
+               (st->xgwa.height < st->xgwa.width ? st->xgwa.height : st->xgwa.width),
+               st->logmaxwidth, st->logminwidth);
        exit(0);
     }
     
     /* create the gc */
-    cmap = xgwa.colormap;
-    gcv.foreground= get_pixel_resource("foreground","Foreground",
-                                      dpy, cmap);
-    gcv.background= get_pixel_resource("background","Background",
-                                      dpy, cmap);
+    gcv.foreground= get_pixel_resource(st->dpy, st->xgwa.colormap,
+                                       "foreground","Foreground");
+    gcv.background= get_pixel_resource(st->dpy, st->xgwa.colormap,
+                                       "background","Background");
     
-    gc = XCreateGC(dpy, w, GCForeground|GCBackground, &gcv);
+    st->gc = XCreateGC(st->dpy, w, GCForeground|GCBackground, &gcv);
     
-    delay = get_integer_resource ("delay", "Integer");
-    if (delay < 0) delay = 0;
+    st->delay = get_integer_resource (st->dpy, "delay", "Integer");
+    if (st->delay < 0) st->delay = 0;
     
-    hold = get_integer_resource ("hold", "Integer");
-    if (hold < 0) hold = 0;
+    st->hold = get_integer_resource (st->dpy, "hold", "Integer");
+    if (st->hold < 0) st->hold = 0;
     
-    clear = get_integer_resource ("clear", "Integer");
-    if (clear < 0) clear = 0;
+    st->clear = get_integer_resource (st->dpy, "clear", "Integer");
+    if (st->clear < 0) st->clear = 0;
 
-    logminwidth = get_integer_resource ("logminwidth", "Integer");
-    if (logminwidth < 2) logminwidth = 2;
+    st->logminwidth = get_integer_resource (st->dpy, "logminwidth", "Integer");
+    if (st->logminwidth < 2) st->logminwidth = 2;
 
-    shiftk = get_boolean_resource("shift", "Boolean");
+    st->shiftk = get_boolean_resource(st->dpy, "shift", "Boolean");
 
-    xor = get_boolean_resource("xor", "Boolean");
+    st->xor = get_boolean_resource(st->dpy, "xor", "Boolean");
 
     /* always draw xor on mono. */
-    if (mono_p || xor) {
-       XSetFunction(dpy, gc, GXxor);
+    if (mono_p || st->xor) {
+       XSetFunction(st->dpy, st->gc, GXxor);
     }
 
-    for(;;) {
-       /* saves some calls to random.  big deal */
-       randflags = random();
+    st->reset = 1;
 
-       /* choose size -- power of two */
-       thiswidth = 1 << (logminwidth +
-                         (random() % (1 + logmaxwidth - logminwidth)));
+    return st;
+}
 
-       munchOnce(dpy, w,
-                 thiswidth, /* Width, in pixels */
-                 
-                 /* draw at this location */
-                 (random() % (xgwa.width <= thiswidth ? 1
-                              : xgwa.width - thiswidth)),
-                 (random() % (xgwa.height <= thiswidth ? 1
-                              : xgwa.width - thiswidth)),
+static unsigned long
+munch_draw (Display *dpy, Window w, void *closure)
+{
+  struct state *st = (struct state *) closure;
+  int this_delay = st->delay;
+
+  if (st->reset)
+    {
+      st->reset = 0;
+
+      this_delay = st->hold;
+      /* saves some calls to random.  big deal */
+      st->randflags = random();
+
+      /* choose size -- power of two */
+      st->thiswidth = 1 << (st->logminwidth +
+                        (random() % (1 + st->logmaxwidth - st->logminwidth)));
+
+      if (st->clear && ++st->square_count >= st->clear) {
+        XClearWindow(st->dpy, w);
+        st->square_count = 0;
+      }
+
+      /* draw at this location */
+      st->atX = (random() % (st->xgwa.width <= st->thiswidth ? 1
+                         : st->xgwa.width - st->thiswidth));
+      st->atY = (random() % (st->xgwa.height <= st->thiswidth ? 1
+                         : st->xgwa.width - st->thiswidth));
                  
-                 /* wrap-around by these values; no need to %
-                    as we end up doing that later anyway*/
-                 ((shiftk && (randflags & SHIFT_KX))
-                  ? (random() % thiswidth) : 0),
-                 ((shiftk && (randflags & SHIFT_KT))
-                  ? (random() % thiswidth) : 0),
-                 ((shiftk && (randflags & SHIFT_KY))
-                  ? (random() % thiswidth) : 0),
+      /* wrap-around by these values; no need to %
+         as we end up doing that later anyway*/
+      st->kX = ((st->shiftk && (st->randflags & SHIFT_KX))
+            ? (random() % st->thiswidth) : 0);
+      st->kT = ((st->shiftk && (st->randflags & SHIFT_KT))
+            ? (random() % st->thiswidth) : 0);
+      st->kY = ((st->shiftk && (st->randflags & SHIFT_KY))
+            ? (random() % st->thiswidth) : 0);
                  
-                 /* set the gravity of the munch, or rather,
-                    which direction we draw stuff in. */
-                 (randflags & GRAV)
-                 );
-       
-        screenhack_handle_events (dpy);
-       if (hold) usleep(hold);
-       
-       if (clear && ++n >= clear) {
-           XClearWindow(dpy, w);
-           n = 0;
-       }
+      /* set the gravity of the munch, or rather,
+         which direction we draw stuff in. */
+      st->grav = (st->randflags & GRAV);
     }
+
+  if (munchOnce (st, st->thiswidth))
+    st->reset = 1;
+
+/*  printf("%d\n",this_delay);*/
+  return this_delay;
 }
+
+static void
+munch_reshape (Display *dpy, Window window, void *closure, 
+                 unsigned int w, unsigned int h)
+{
+  struct state *st = (struct state *) closure;
+  st->xgwa.width = w;
+  st->xgwa.height = h;
+  st->logmaxwidth = (int)
+    dumb_log_2(st->xgwa.height < st->xgwa.width ? st->xgwa.height : st->xgwa.width);
+  st->maxwidth = 1 << st->logmaxwidth;
+}
+
+static Bool
+munch_event (Display *dpy, Window window, void *closure, XEvent *event)
+{
+  return False;
+}
+
+static void
+munch_free (Display *dpy, Window window, void *closure)
+{
+  struct state *st = (struct state *) closure;
+  free (st);
+}
+
+\f
+static const char *munch_defaults [] = {
+    ".background:      black",
+    ".foreground:      white",
+    "*delay:           5000",
+    "*hold:            100000",
+    "*clear:           50",
+    "*logminwidth:     7",
+    "*shift:           True",
+    "*xor:             True",
+    0
+};
+
+static XrmOptionDescRec munch_options [] = {
+    { "-delay",                ".delay",       XrmoptionSepArg, 0 },
+    { "-hold",         ".hold",        XrmoptionSepArg, 0 },
+    { "-clear",         ".clear",       XrmoptionSepArg, "true" },
+    { "-shift",         ".shift",       XrmoptionNoArg, "true" },
+    { "-no-shift",     ".shift",       XrmoptionNoArg, "false" },
+    { "-logminwidth",  ".logminwidth", XrmoptionSepArg, 0 },
+    { "-xor",           ".xor",                XrmoptionNoArg, "true" },
+    { "-no-xor",       ".xor",         XrmoptionNoArg, "false" },
+    { 0, 0, 0, 0 }
+};
+
+XSCREENSAVER_MODULE ("Munch", munch)