http://slackware.bholcomb.com/slackware/slackware-11.0/source/xap/xscreensaver/xscree...
[xscreensaver] / hacks / mismunch.c
index 0283f93840003d2d8e1010d0775a077cdafd2f09..cda0a0b0e523712a509f93c1ff9f54aa2acbc5c4 100644 (file)
 #include <math.h>
 #include "screenhack.h"
 
-char *progclass = "Mismunch";
-
-char *defaults [] = {
-  ".background:       black",
-  ".foreground:       white",
-  "*delay:            2500",
-  "*simul:            5",
-  "*clear:            65",
-  "*xor:              True",
-  0
-};
-
-XrmOptionDescRec options [] = {
-  { "-delay",         ".delay",       XrmoptionSepArg,  0 },
-  { "-simul",         ".simul",       XrmoptionSepArg,  0 },
-  { "-clear",         ".clear",       XrmoptionSepArg, "true" },
-  { "-xor",           ".xor",         XrmoptionNoArg,  "true" },
-  { "-no-xor",        ".xor",         XrmoptionNoArg,  "false" },
-  { 0, 0, 0, 0 }
-};
-
-
-static GC gc;
-static int delay, simul, clear, xor;
-static int logminwidth, logmaxwidth;
-static int restart, window_width, window_height;
-
 typedef struct _muncher {
   int width;
   int atX, atY;
@@ -62,11 +35,28 @@ typedef struct _muncher {
 } muncher;
 
 
+struct state {
+  Display *dpy;
+  Window window;
+
+  GC gc;
+  int delay, simul, clear, xor;
+  int logminwidth, logmaxwidth;
+  int restart, window_width, window_height;
+
+  int draw_n;  /* number of squares before we have to clear */
+  int draw_i;
+
+  muncher **munchers;
+};
+
+
 /*
  * 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++;
@@ -75,66 +65,45 @@ static int dumb_log_2(int k) {
 }
 
 
-void calc_logwidths (void) {
+static void calc_logwidths (struct state *st) 
+{
   /* Choose a range of square sizes based on the window size.  We want
      a power of 2 for the square width or the munch doesn't fill up.
      Also, if a square doesn't fit inside an area 20% smaller than the
      window, it's too big.  Mismunched squares that big make things
      look too noisy. */
 
-  if (window_height < window_width) {
-    logmaxwidth = (int)dumb_log_2(window_height * 0.8);
+  if (st->window_height < st->window_width) {
+    st->logmaxwidth = (int)dumb_log_2(st->window_height * 0.8);
   } else {
-    logmaxwidth = (int)dumb_log_2(window_width * 0.8);
+    st->logmaxwidth = (int)dumb_log_2(st->window_width * 0.8);
   }
 
-  if (logmaxwidth < 2) {
-    logmaxwidth = 2;
+  if (st->logmaxwidth < 2) {
+    st->logmaxwidth = 2;
   }
 
   /* we always want three sizes of squares */
-  logminwidth = logmaxwidth - 2;
+  st->logminwidth = st->logmaxwidth - 2;
 
-  if (logminwidth < 2) {
-    logminwidth = 2;
+  if (st->logminwidth < 2) {
+    st->logminwidth = 2;
   }
 }
 
 
-void mismunch_handle_events (Display *dpy) {
-  XEvent e;
-
-  while (XPending(dpy)) {
-    XNextEvent(dpy, &e);
-
-    switch (e.type) {
-      case ConfigureNotify:
-        if (e.xconfigure.width != window_width ||
-            e.xconfigure.height != window_height) {
-          window_width = e.xconfigure.width;
-          window_height = e.xconfigure.height;
-          calc_logwidths();
-          restart = 1;
-        }
-        break;
 
-      default:
-        screenhack_handle_event(dpy, &e);
-    }
-  }
-}
-
-
-static muncher *make_muncher (Display *dpy, Window w) {
+static muncher *make_muncher (struct state *st) 
+{
   int logwidth;
   XWindowAttributes xgwa;
   muncher *m = (muncher *) malloc(sizeof(muncher));
 
-  XGetWindowAttributes(dpy, w, &xgwa);
+  XGetWindowAttributes(st->dpy, st->window, &xgwa);
 
   /* choose size -- power of two */
-  logwidth = (logminwidth +
-              (random() % (1 + logmaxwidth - logminwidth)));
+  logwidth = (st->logminwidth +
+              (random() % (1 + st->logmaxwidth - st->logminwidth)));
 
   m->width = 1 << logwidth;
 
@@ -213,23 +182,21 @@ static muncher *make_muncher (Display *dpy, Window w) {
 }
 
 
-static void munch (Display *dpy, Window w, muncher *m) {
+static void munch (struct state *st, muncher *m) 
+{
   int drawX, drawY;
   XWindowAttributes xgwa;
-  static Colormap cmap;
 
   if (m->done) {
     return;
   }
 
-  XGetWindowAttributes(dpy, w, &xgwa);
+  XGetWindowAttributes(st->dpy, st->window, &xgwa);
 
   if (!mono_p) {
     /* XXX there are probably bugs with this. */
-    cmap = xgwa.colormap;
-
-    if (XAllocColor(dpy, cmap, &m->fgc)) {
-      XSetForeground(dpy, gc, m->fgc.pixel);
+    if (XAllocColor(st->dpy, xgwa.colormap, &m->fgc)) {
+      XSetForeground(st->dpy, st->gc, m->fgc.pixel);
     }
   }
 
@@ -251,111 +218,159 @@ static void munch (Display *dpy, Window w, muncher *m) {
     drawX = ((m->x + m->kX) % m->width) + m->atX;
     drawY = (m->grav ? m->y + m->atY : m->atY + m->width - 1 - m->y);
 
-    XDrawPoint(dpy, w, gc, drawX, drawY);
+    XDrawPoint(st->dpy, st->window, st->gc, drawX, drawY);
     if ((m->xshadow != 0) || (m->yshadow != 0)) {
       /* draw the corresponding shadow point */
-      XDrawPoint(dpy, w, gc, drawX + m->xshadow, drawY + m->yshadow);
+      XDrawPoint(st->dpy, st->window, st->gc, drawX + m->xshadow, drawY + m->yshadow);
     }
     /* 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);
-  mismunch_handle_events(dpy);
-
-  if (delay) usleep(delay);
-
   m->t++;
   if (m->t > m->doom) {
     m->done = 1;
-    return;
   }
-
-  return;
 }
 
 
-void screenhack (Display *dpy, Window w)
+static void *
+mismunch_init (Display *dpy, Window w)
 {
+  struct state *st = (struct state *) calloc (1, sizeof(*st));
   XWindowAttributes xgwa;
-  Colormap cmap;
   XGCValues gcv;
-  int n = 0;  /* number of squares before we have to clear */
-  muncher **munchers;
   int i;
 
-  restart = 0;
+  st->dpy = dpy;
+  st->window = w;
+  st->restart = 0;
 
   /* get the dimensions of the window */
-  XGetWindowAttributes(dpy, w, &xgwa);
+  XGetWindowAttributes(st->dpy, w, &xgwa);
 
   /* 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, xgwa.colormap,
+                                     "foreground","Foreground");
+  gcv.background= get_pixel_resource(st->dpy, 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;
 
-  simul = get_integer_resource("simul", "Integer");
-  if (simul < 1) simul = 1;
+  st->simul = get_integer_resource(st->dpy, "simul", "Integer");
+  if (st->simul < 1) st->simul = 1;
 
-  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;
 
-  xor = get_boolean_resource("xor", "Boolean");
+  st->xor = get_boolean_resource(st->dpy, "xor", "Boolean");
 
-  window_width = xgwa.width;
-  window_height = xgwa.height;
+  st->window_width = xgwa.width;
+  st->window_height = xgwa.height;
 
-  calc_logwidths();
+  calc_logwidths(st);
 
   /* always draw xor on mono. */
-  if (mono_p || xor) {
-    XSetFunction(dpy, gc, GXxor);
+  if (mono_p || st->xor) {
+    XSetFunction(st->dpy, st->gc, GXxor);
   }
 
-  munchers = (muncher **) calloc(simul, sizeof(muncher *));
-  for (i = 0; i < simul; i++) {
-    munchers[i] = make_muncher(dpy, w);
+  st->munchers = (muncher **) calloc(st->simul, sizeof(muncher *));
+  for (i = 0; i < st->simul; i++) {
+    st->munchers[i] = make_muncher(st);
   }
 
-  for(;;) {
-    for (i = 0; i < simul; i++) {
-      munch(dpy, w, munchers[i]);
+  return st;
+}
 
-      if (munchers[i]->done) {
-        n++;
+static unsigned long
+mismunch_draw (Display *dpy, Window w, void *closure)
+{
+  struct state *st = (struct state *) closure;
 
-        free(munchers[i]);
-        munchers[i] = make_muncher(dpy, w);
+  /* for (draw_i = 0; draw_i < simul; draw_i++)  */
+  {
+    munch(st, st->munchers[st->draw_i]);
 
-        mismunch_handle_events(dpy);
-      }
+    if (st->munchers[st->draw_i]->done) {
+      st->draw_n++;
+
+      free(st->munchers[st->draw_i]);
+      st->munchers[st->draw_i] = make_muncher(st);
     }
+  }
 
-    if (restart || (clear && n >= clear)) {
-      for (i = 0; i < simul; i++) {
-        free(munchers[i]);
-        munchers[i] = make_muncher(dpy, w);
+  st->draw_i++;
+  if (st->draw_i >= st->simul) {
+    int i = 0;
+    st->draw_i = 0;
+    if (st->restart || (st->clear && st->draw_n >= st->clear)) {
+      for (i = 0; i < st->simul; i++) {
+        free(st->munchers[i]);
+        st->munchers[i] = make_muncher(st);
       }
 
-      XClearWindow(dpy, w);
-      n = 0;
-      restart = 0;
+      XClearWindow(st->dpy, w);
+      st->draw_n = 0;
+      st->restart = 0;
     }
+  }
 
-    XSync(dpy, False);
+  return st->delay;
+}
+
+
+static void
+mismunch_reshape (Display *dpy, Window window, void *closure, 
+                 unsigned int w, unsigned int h)
+{
+  struct state *st = (struct state *) closure;
+  if (w != st->window_width ||
+      h != st->window_height) {
+    st->window_width = w;
+    st->window_height = h;
+    calc_logwidths(st);
+    st->restart = 1;
+    st->draw_i = 0;
   }
 }
+
+static Bool
+mismunch_event (Display *dpy, Window window, void *closure, XEvent *event)
+{
+  return False;
+}
+
+static void
+mismunch_free (Display *dpy, Window window, void *closure)
+{
+  struct state *st = (struct state *) closure;
+  free (st);
+}
+
+
+static const char *mismunch_defaults [] = {
+  ".background:       black",
+  ".foreground:       white",
+  "*delay:            2500",
+  "*simul:            5",
+  "*clear:            65",
+  "*xor:              True",
+  0
+};
+
+static XrmOptionDescRec mismunch_options [] = {
+  { "-delay",         ".delay",       XrmoptionSepArg,  0 },
+  { "-simul",         ".simul",       XrmoptionSepArg,  0 },
+  { "-clear",         ".clear",       XrmoptionSepArg, "true" },
+  { "-xor",           ".xor",         XrmoptionNoArg,  "true" },
+  { "-no-xor",        ".xor",         XrmoptionNoArg,  "false" },
+  { 0, 0, 0, 0 }
+};
+
+
+XSCREENSAVER_MODULE ("Mismunch", mismunch)