-/* xscreensaver, Copyright (c) 1993 Jamie Zawinski <jwz@lucid.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
but X doesn't support arithmetic combinations of pixmaps!! What losers.
I suppose I could crank out the 2's compliment math by hand, but that's
a real drag...
+
+ This would probably look good with shapes other than circles as well.
+
*/
#include "screenhack.h"
+#include <stdio.h>
struct circle {
int x, y, radius;
int dx, dy;
};
+static enum color_mode {
+ seuss_mode, ramp_mode, random_mode
+} cmode;
+
+
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 Bool xor_p;
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;
+ char *mode_str = 0;
XGetWindowAttributes (dpy, window, &xgwa);
cmap = xgwa.colormap;
global_count = get_integer_resource ("count", "Integer");
if (global_count < 0) global_count = 0;
global_inc = get_integer_resource ("increment", "Integer");
if (global_inc < 0) global_inc = 0;
- xor_p = get_boolean_resource ("xor", "Boolean");
-/* if (mono_p) */ xor_p = True;
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;
+ else if (!strcmp (mode_str, "ramp")) cmode = ramp_mode;
+ else if (!strcmp (mode_str, "random")) cmode = random_mode;
+ else {
+ fprintf (stderr,
+ "%s: colorMode must be seuss, ramp, or random, not \"%s\"\n",
+ progname, mode_str);
+ exit (1);
+ }
+
+ if (mono_p) cmode = seuss_mode;
+ if (cmode == random_mode)
+ cmode = ((random()&3) == 1) ? ramp_mode : 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
{
- hsv_to_rgb (0, 0.5, 1.0, &fgc.red, &fgc.green, &fgc.blue);
- hsv_to_rgb (180, 1.0, 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);
#endif
pixmap = XCreatePixmap (dpy, window, width, height, 1);
- if (xor_p)
+ if (cmode == seuss_mode)
buffer = XCreatePixmap (dpy, window, width, height, 1);
else
buffer = 0;
gcv.background = bg_pixel;
copy_gc = XCreateGC (dpy, window, GCForeground | GCBackground, &gcv);
- if (xor_p)
+ if (cmode == seuss_mode)
{
gcv.foreground = 1;
gcv.background = 0;
}
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 &&
- (xor_p || circles [0].increment < 0))
- XFillArc (dpy,
- (xor_p ? pixmap : window),
- (xor_p ? 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)
{
- cycle_hue (&fgc, 10);
- cycle_hue (&bgc, 10);
- XFreeColors (dpy, cmap, &fgc.pixel, 1, 0);
- XFreeColors (dpy, cmap, &bgc.pixel, 1, 0);
- XAllocColor (dpy, cmap, &fgc);
- XAllocColor (dpy, cmap, &bgc);
- 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;
if (buffer)
XCopyPlane (dpy, pixmap, buffer, merge_gc, 0, 0, width, height, 0, 0, 1);
- else if (!xor_p)
+ 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 [] = {
- "*background: black",
- "*foreground: white",
-/* "*xor: false", */
- "*count: 0",
- "*delay: 100000",
+ ".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 },
- { "-animate", ".animate", XrmoptionNoArg, "True" } /* ,
- { "-xor", ".xor", XrmoptionNoArg, "True" },
- { "-no-xor", ".xor", XrmoptionNoArg, "False" } */
+ { "-cycle-delay", ".cycleDelay", XrmoptionSepArg, 0 },
+ { "-animate", ".animate", XrmoptionNoArg, "True" },
+ { "-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);
+ }
}