-/* xscreensaver, Copyright (c) 1993, 1995 Jamie Zawinski <jwz@netscape.com>
+/* xscreensaver, Copyright (c) 1993, 1995, 1996, 1997, 1998, 1999
+ * 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
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
}
static void
-init_circles (dpy, window)
- Display *dpy;
- Window window;
+init_circles (Display *dpy, Window window)
{
XGCValues gcv;
XWindowAttributes xgwa;
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;
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);
}
static void
-run_circles (dpy, window)
- Display *dpy;
- Window window;
+run_circles (Display *dpy, Window window)
{
int i;
static int iterations = 0;
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
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, };
+ 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;
}
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;
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)
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)
+ {
+ int 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);
+ }
}