http://packetstormsecurity.org/UNIX/admin/xscreensaver-4.14.tar.gz
[xscreensaver] / hacks / halo.c
index d61e2ac33c60aeb310024e39281c5ea6e3758a56..fc69ea730af60d27e8f3709fba42ce335a0ababe 100644 (file)
@@ -1,4 +1,5 @@
-/* xscreensaver, Copyright (c) 1993, 1995 Jamie Zawinski <jwz@netscape.com>
+/* xscreensaver, Copyright (c) 1993, 1995, 1996, 1997, 1998, 1999, 2003
+ *  Jamie Zawinski <jwz@jwz.org>
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
@@ -36,20 +37,24 @@ static struct circle *circles;
 static int count, global_count;
 static Pixmap pixmap, buffer;
 static int width, height, global_inc;
-static int delay;
+static int delay, delay2, cycle_delay;
 static unsigned long fg_pixel, bg_pixel;
-static XColor fgc, bgc;
 static GC draw_gc, erase_gc, copy_gc, merge_gc;
 static Bool anim_p;
 static Colormap cmap;
 
+static int ncolors;
+static XColor *colors;
+static Bool cycle_p;
+static int fg_index;
+static int bg_index;
+
+
 #define min(x,y) ((x)<(y)?(x):(y))
 #define max(x,y) ((x)>(y)?(x):(y))
 
 static void
-init_circles_1 (dpy, window)
-     Display *dpy;
-     Window window;
+init_circles_1 (Display *dpy, Window window)
 {
   int i;
   count = (global_count ? global_count
@@ -76,9 +81,7 @@ init_circles_1 (dpy, window)
 }
 
 static void
-init_circles (dpy, window)
-     Display *dpy;
-     Window window;
+init_circles (Display *dpy, Window window)
 {
   XGCValues gcv;
   XWindowAttributes xgwa;
@@ -91,6 +94,8 @@ init_circles (dpy, window)
   if (global_inc < 0) global_inc = 0;
   anim_p = get_boolean_resource ("animate", "Boolean");
   delay = get_integer_resource ("delay", "Integer");
+  delay2 = get_integer_resource ("delay2", "Integer") * 1000000;
+  cycle_delay = get_integer_resource ("cycleDelay", "Integer");
   mode_str = get_string_resource ("colorMode", "ColorMode");
   if (! mode_str) cmode = random_mode;
   else if (!strcmp (mode_str, "seuss"))  cmode = seuss_mode;
@@ -110,26 +115,48 @@ init_circles (dpy, window)
   if (cmode == ramp_mode)
     anim_p = False;    /* This combo doesn't work right... */
 
+  ncolors = get_integer_resource ("colors", "Colors");
+  if (ncolors < 2) ncolors = 2;
+  if (ncolors <= 2) mono_p = True;
+
+  if (mono_p)
+    colors = 0;
+  else
+    colors = (XColor *) malloc(sizeof(*colors) * (ncolors+1));
+
+  cycle_p = mono_p ? False : get_boolean_resource ("cycle", "Cycle");
+
+  /* If the visual isn't color-indexed, don't bother trying to
+     allocate writable cells. */
+  if (cycle_p && !has_writable_cells (xgwa.screen, xgwa.visual))
+    cycle_p = False;
+
+
+  if (mono_p)
+    ;
+  else if (random() % (cmode == seuss_mode ? 2 : 10))
+    make_uniform_colormap (dpy, xgwa.visual, cmap, colors, &ncolors,
+                          True, &cycle_p, True);
+  else
+    make_smooth_colormap (dpy, xgwa.visual, cmap, colors, &ncolors,
+                         True, &cycle_p, True);
+
+  if (ncolors <= 2) mono_p = True;
+  if (mono_p) cycle_p = False;
+  if (mono_p) cmode = seuss_mode;
+
   if (mono_p)
     {
-      fg_pixel = get_pixel_resource ("foreground","Foreground", dpy, cmap);
-      bg_pixel = get_pixel_resource ("background","Background", dpy, cmap);
+      fg_pixel = get_pixel_resource ("foreground", "Foreground", dpy, cmap);
+      bg_pixel = get_pixel_resource ("background", "Background", dpy, cmap);
     }
   else
     {
-      int r  = random() % 360;
-      int r2 = (random() % 180) + 45;
-      double fs, bs;
-      if (cmode == seuss_mode)
-       fs = 0.5, bs = 1.0;
-      else
-       fs = 1.0, bs = 0.1;
-      hsv_to_rgb (r,          fs, 1.0, &fgc.red, &fgc.green, &fgc.blue);
-      hsv_to_rgb ((r+r2)%360, bs, 0.7, &bgc.red, &bgc.green, &bgc.blue);
-      XAllocColor (dpy, cmap, &fgc);
-      XAllocColor (dpy, cmap, &bgc);
-      fg_pixel = fgc.pixel;
-      bg_pixel = bgc.pixel;
+      fg_index = 0;
+      bg_index = ncolors / 4;
+      if (fg_index == bg_index) bg_index++;
+      fg_pixel = colors[fg_index].pixel;
+      bg_pixel = colors[bg_index].pixel;
     }
 
   width = max (50, xgwa.width);
@@ -177,9 +204,7 @@ init_circles (dpy, window)
 }
 
 static void
-run_circles (dpy, window)
-     Display *dpy;
-     Window window;
+run_circles (Display *dpy, Window window)
 {
   int i;
   static int iterations = 0;
@@ -187,18 +212,21 @@ run_circles (dpy, window)
   static Bool first_time_p = True;
   Bool done = False;
   Bool inhibit_sleep = False;
+  static int clear_tick = 0;
+
   XFillRectangle (dpy, pixmap, erase_gc, 0, 0, width, height);
   for (i = 0; i < count; i++)
     {
       int radius = circles [i].radius;
       int inc = circles [i].increment;
-      if (! (iterations & 1))
+
+      if (! (iterations & 1))  /* never stop on an odd number of iterations */
        ;
-      else if (radius == 0)
+      else if (radius == 0)    /* eschew inf */
        ;
-      else if (radius < 0)
+      else if (radius < 0)     /* stop when the circles are points */
        done = True;
-      else
+      else                     /* stop when the circles fill the window */
        {
          /* Probably there's a simpler way to ask the musical question,
             "is this square completely enclosed by this circle," but I've
@@ -212,16 +240,40 @@ run_circles (dpy, window)
          if ((x1 + y1) < 1 && (x2 + y2) < 1 && (x1 + y2) < 1 && (x2 + y1) < 1)
            done = True;
        }
+
       if (radius > 0 &&
-         (cmode == seuss_mode || circles [0].increment < 0))
-       XFillArc (dpy,
-                 (cmode == seuss_mode ? pixmap : window),
-                 (cmode == seuss_mode ? draw_gc : merge_gc),
-                 circles [i].x - radius, circles [i].y - radius,
-                 radius * 2, radius * 2, 0, 360*64);
+         (cmode == seuss_mode ||       /* drawing all circles, or */
+          circles [0].increment < 0))  /* on the way back in */
+       {
+         XFillArc (dpy,
+                   (cmode == seuss_mode ? pixmap : window),
+                   (cmode == seuss_mode ? draw_gc : merge_gc),
+                   circles [i].x - radius, circles [i].y - radius,
+                   radius * 2, radius * 2, 0, 360*64);
+       }
       circles [i].radius += inc;
     }
 
+  if (cycle_p && cmode != seuss_mode)
+    {
+      struct timeval now;
+      static struct timeval then = { 0, 0 };
+      unsigned long diff;
+#ifdef GETTIMEOFDAY_TWO_ARGS
+      struct timezone tzp;
+      gettimeofday(&now, &tzp);
+#else
+      gettimeofday(&now);
+#endif
+      diff = (((now.tv_sec - then.tv_sec)  * 1000000) +
+             (now.tv_usec - then.tv_usec));
+      if (diff > cycle_delay)
+       {
+         rotate_colors (dpy, cmap, colors, ncolors, 1);
+         then = now;
+       }
+    }
+
   if (anim_p && !first_time_p)
     inhibit_sleep = !done;
 
@@ -249,33 +301,28 @@ run_circles (dpy, window)
        }
       else if (circles [0].increment < 0)
        {
+         /* We've zoomed out and the screen is blank -- re-pick the
+            center points, and shift the colors.
+          */
          free (circles);
          init_circles_1 (dpy, window);
          if (! mono_p)
            {
-             XColor d1, d2;
-             cycle_hue (&fgc, 10);
-             cycle_hue (&bgc, 10);
-             XFreeColors (dpy, cmap, &fgc.pixel, 1, 0);
-             XFreeColors (dpy, cmap, &bgc.pixel, 1, 0);
-             d1 = fgc;
-             d2 = bgc;
-             XAllocColor (dpy, cmap, &fgc);
-             XAllocColor (dpy, cmap, &bgc);
-             fgc.red = d1.red; fgc.green = d1.green; fgc.blue = d1.blue;
-             bgc.red = d2.red; bgc.green = d2.green; bgc.blue = d2.blue;
-             XSetForeground (dpy, copy_gc, fgc.pixel);
-             XSetBackground (dpy, copy_gc, bgc.pixel);
+             fg_index = (fg_index + 1) % ncolors;
+             bg_index = (fg_index + (ncolors/2)) % ncolors;
+             XSetForeground (dpy, copy_gc, colors [fg_index].pixel);
+             XSetBackground (dpy, copy_gc, colors [bg_index].pixel);
            }
        }
-#if 0
-      else if ((random () % 2) == 0)
+      /* Sometimes go out from the inside instead of the outside */
+      else if (clear_tick == 0 && ((random () % 3) == 0))
        {
          iterations = 0; /* ick */
          for (i = 0; i < count; i++)
            circles [i].radius %= circles [i].increment;
+
+          clear_tick = ((random() % 8) + 4) | 1;   /* must be odd */
        }
-#endif
       else
        {
          oiterations = iterations;
@@ -291,53 +338,40 @@ run_circles (dpy, window)
     XCopyPlane (dpy, pixmap, buffer, merge_gc, 0, 0, width, height, 0, 0, 1);
   else if (cmode != seuss_mode)
     {
-      static int ncolors = 0;
-      static XColor *colors = 0;
-      if (circles [0].increment >= 0)
-       inhibit_sleep = True;
-      else if (done)
-       {
-         int fgh, bgh;
-         double fgs, fgv, bgs, bgv;
-         if (colors)
-           for (i = 0; i < ncolors; i++)
-             XFreeColors (dpy, cmap, &colors [i].pixel, 1, 0);
-
-         rgb_to_hsv (fgc.red, fgc.green, fgc.blue, &fgh, &fgs, &fgv);
-         rgb_to_hsv (bgc.red, bgc.green, bgc.blue, &bgh, &bgs, &bgv);
-         ncolors = oiterations;
-         colors = ((XColor *)
-                   (colors
-                    ? realloc (colors, sizeof (XColor) * ncolors)
-                    : malloc (sizeof (XColor) * ncolors)));
-         
-         make_color_ramp (bgh, bgs, bgv, fgh, fgs, fgv, colors, ncolors);
-         for (i = 0; i < ncolors; i++)
-           XAllocColor (dpy, cmap, &colors [i]);
-         XSetForeground (dpy, merge_gc, colors [0].pixel);
-       }
-      else
+
+      if (!mono_p)
        {
-         XSetForeground (dpy, merge_gc, colors [iterations].pixel);
+         fg_index++;
+         bg_index++;
+         if (fg_index >= ncolors) fg_index = 0;
+         if (bg_index >= ncolors) bg_index = 0;
+         XSetForeground (dpy, merge_gc, colors [fg_index].pixel);
        }
+
+      if (circles [0].increment >= 0)
+       inhibit_sleep = True;
+      else if (done && cmode == seuss_mode)
+       XFillRectangle (dpy, window, merge_gc, 0, 0, width, height);
     }
   else
     XCopyPlane (dpy, pixmap, window, merge_gc, 0, 0, width, height, 0, 0, 1);
 
+  /* buffer is only used in seuss-mode or anim-mode */
   if (buffer && (anim_p
                 ? (done || (first_time_p && (iterations & 1)))
                 : (iterations & 1)))
     {
       XCopyPlane (dpy, buffer, window, copy_gc, 0, 0, width, height, 0, 0, 1);
-      XSync (dpy, True);
+      XSync (dpy, False);
       if (anim_p && done)
        XFillRectangle (dpy, buffer, erase_gc, 0, 0, width, height);
     }
+
 #ifdef DEBUG
   XCopyPlane (dpy, pixmap, window, copy_gc, 0,0,width,height,width,height, 1);
   if (buffer)
     XCopyPlane (dpy, buffer, window, copy_gc, 0,0,width,height,0,height, 1);
-  XSync (dpy, True);
+  XSync (dpy, False);
 #endif
 
   if (done)
@@ -345,35 +379,88 @@ run_circles (dpy, window)
   else
     iterations++;
 
-  if (delay && !inhibit_sleep) usleep (delay);
+  if (delay && !inhibit_sleep)
+    {
+      static Bool really_first_p = True;
+      int direction = 1;
+      int d = delay;
+      if (done && cycle_p && cmode != seuss_mode && !really_first_p)
+       {
+         d = delay2;
+         if (! (random() % 10))
+           direction = -1;
+       }
+
+      XSync(dpy, False);
+      screenhack_handle_events (dpy);
+
+      if (cycle_p && cycle_delay)
+       {
+          i = 0;
+         while (i < d)
+           {
+             rotate_colors (dpy, cmap, colors, ncolors, direction);
+             usleep(cycle_delay);
+              screenhack_handle_events (dpy);
+             i += cycle_delay;
+           }
+       }
+      else if (cmode != seuss_mode &&
+               done && !really_first_p && cycle_delay > 0)
+        usleep (cycle_delay * 50);
+      else
+        usleep (d);
+
+      if (done)
+       really_first_p = False;
+    }
+
+  if (done && clear_tick > 0)
+    {
+      clear_tick--;
+      if (!clear_tick)
+        {
+          XClearWindow (dpy, window);
+          if (buffer) XFillRectangle (dpy, buffer, erase_gc, 0,0,width,height);
+        }
+    }
 }
 
 \f
 char *progclass = "Halo";
 
 char *defaults [] = {
-  "Halo.background:    black",         /* to placate SGI */
-  "Halo.foreground:    white",
+  ".background:                black",
+  ".foreground:                white",
   "*colorMode:         random",
+  "*colors:            100",
+  "*cycle:             true",
   "*count:             0",
   "*delay:             100000",
+  "*delay2:            20",
+  "*cycleDelay:                100000",
   0
 };
 
 XrmOptionDescRec options [] = {
   { "-count",          ".count",       XrmoptionSepArg, 0 },
   { "-delay",          ".delay",       XrmoptionSepArg, 0 },
+  { "-cycle-delay",    ".cycleDelay",  XrmoptionSepArg, 0 },
   { "-animate",                ".animate",     XrmoptionNoArg, "True" },
-  { "-mode",           ".colorMode",   XrmoptionSepArg, 0 }
+  { "-mode",           ".colorMode",   XrmoptionSepArg, 0 },
+  { "-colors",         ".colors",      XrmoptionSepArg, 0 },
+  { "-cycle",          ".cycle",       XrmoptionNoArg, "True" },
+  { "-no-cycle",       ".cycle",       XrmoptionNoArg, "False" },
+  { 0, 0, 0, 0 }
 };
-int options_size = (sizeof (options) / sizeof (options[0]));
 
 void
-screenhack (dpy, window)
-     Display *dpy;
-     Window window;
+screenhack (Display *dpy, Window window)
 {
   init_circles (dpy, window);
   while (1)
-    run_circles (dpy, window);
+    {
+      run_circles (dpy, window);
+      screenhack_handle_events (dpy);
+    }
 }