+++ /dev/null
-/* 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
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation. No representations are made about the suitability of this
- * software for any purpose. It is provided "as is" without express or
- * implied warranty.
- */
-
-/* I wanted to lay down new circles with TV:ALU-ADD instead of TV:ALU-XOR,
- 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 increment;
- 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, delay2, cycle_delay;
-static unsigned long fg_pixel, bg_pixel;
-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 (Display *dpy, Window window)
-{
- int i;
- count = (global_count ? global_count
- : (3 + (random () % max (1, (min (width, height) / 50)))
- + (random () % max (1, (min (width, height) / 50)))));
- circles = (struct circle *) malloc (count * sizeof (struct circle));
- for (i = 0; i < count; i++)
- {
- circles [i].x = 10 + random () % (width - 20);
- circles [i].y = 10 + random () % (height - 20);
- if (global_inc)
- circles [i].increment = global_inc;
- else
- { /* prefer smaller increments to larger ones */
- int j = 8;
- int inc = ((random()%j) + (random()%j) + (random()%j)) - ((j*3)/2);
- if (inc < 0) inc = -inc + 3;
- circles [i].increment = inc + 3;
- }
- circles [i].radius = random () % circles [i].increment;
- circles [i].dx = ((random () % 3) - 1) * (1 + random () % 5);
- circles [i].dy = ((random () % 3) - 1) * (1 + random () % 5);
- }
-}
-
-static void
-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;
- 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);
- }
- else
- {
- 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);
- height = max (50, xgwa.height);
-
-#ifdef DEBUG
- width/=2; height/=2;
-#endif
-
- pixmap = XCreatePixmap (dpy, window, width, height, 1);
- if (cmode == seuss_mode)
- buffer = XCreatePixmap (dpy, window, width, height, 1);
- else
- buffer = 0;
-
- gcv.foreground = 1;
- gcv.background = 0;
- draw_gc = XCreateGC (dpy, pixmap, GCForeground | GCBackground, &gcv);
- gcv.foreground = 0;
- erase_gc = XCreateGC (dpy, pixmap, GCForeground, &gcv);
- gcv.foreground = fg_pixel;
- gcv.background = bg_pixel;
- copy_gc = XCreateGC (dpy, window, GCForeground | GCBackground, &gcv);
-
- if (cmode == seuss_mode)
- {
- gcv.foreground = 1;
- gcv.background = 0;
- gcv.function = GXxor;
- merge_gc = XCreateGC (dpy, pixmap,
- GCForeground | GCBackground | GCFunction, &gcv);
- }
- else
- {
- gcv.foreground = fg_pixel;
- gcv.background = bg_pixel;
- gcv.function = GXcopy;
- merge_gc = XCreateGC (dpy, window,
- GCForeground | GCBackground | GCFunction, &gcv);
- }
-
- init_circles_1 (dpy, window);
- XClearWindow (dpy, window);
- if (buffer) XFillRectangle (dpy, buffer, erase_gc, 0, 0, width, height);
-}
-
-static void
-run_circles (Display *dpy, Window window)
-{
- int i;
- static int iterations = 0;
- static int oiterations = 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)) /* never stop on an odd number of iterations */
- ;
- else if (radius == 0) /* eschew inf */
- ;
- else if (radius < 0) /* stop when the circles are points */
- done = True;
- 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
- forgotten too much trig to know it... (That's not really the
- right question anyway, but the right question is too hard.) */
- double x1 = ((double) (-circles [i].x)) / ((double) radius);
- double y1 = ((double) (-circles [i].y)) / ((double) radius);
- double x2 = ((double) (width - circles [i].x)) / ((double) radius);
- double y2 = ((double) (height - circles [i].y)) / ((double) radius);
- x1 *= x1; x2 *= x2; y1 *= y1; y2 *= y2;
- if ((x1 + y1) < 1 && (x2 + y2) < 1 && (x1 + y2) < 1 && (x2 + y1) < 1)
- done = True;
- }
-
- if (radius > 0 &&
- (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;
-
- if (done)
- {
- if (anim_p)
- {
- first_time_p = False;
- for (i = 0; i < count; i++)
- {
- circles [i].x += circles [i].dx;
- circles [i].y += circles [i].dy;
- circles [i].radius %= circles [i].increment;
- if (circles [i].x < 0 || circles [i].x >= width)
- {
- circles [i].dx = -circles [i].dx;
- circles [i].x += (2 * circles [i].dx);
- }
- if (circles [i].y < 0 || circles [i].y >= height)
- {
- circles [i].dy = -circles [i].dy;
- circles [i].y += (2 * circles [i].dy);
- }
- }
- }
- 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)
- {
- 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);
- }
- }
- /* 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 */
- }
- else
- {
- oiterations = iterations;
- for (i = 0; i < count; i++)
- {
- circles [i].increment = -circles [i].increment;
- circles [i].radius += (2 * circles [i].increment);
- }
- }
- }
-
- if (buffer)
- XCopyPlane (dpy, pixmap, buffer, merge_gc, 0, 0, width, height, 0, 0, 1);
- else if (cmode != seuss_mode)
- {
-
- if (!mono_p)
- {
- 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, 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, False);
-#endif
-
- if (done)
- iterations = 0;
- else
- iterations++;
-
- 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",
- "*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 },
- { "-colors", ".colors", XrmoptionSepArg, 0 },
- { "-cycle", ".cycle", XrmoptionNoArg, "True" },
- { "-no-cycle", ".cycle", XrmoptionNoArg, "False" },
- { 0, 0, 0, 0 }
-};
-
-void
-screenhack (Display *dpy, Window window)
-{
- init_circles (dpy, window);
- while (1)
- {
- run_circles (dpy, window);
- screenhack_handle_events (dpy);
- }
-}