X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=hacks%2Fhalo.c;h=2c002b54b994a4523a51efdc486aa5df9a2949bd;hb=6a1da724858673ac40aa13a9612340d8bed8c7b9;hp=b8270ee8960bdbe0b1895e554b6d3501edac2ac8;hpb=6edc84f12f15860a71430c45e8392a5e4ef8203c;p=xscreensaver diff --git a/hacks/halo.c b/hacks/halo.c index b8270ee8..2c002b54 100644 --- a/hacks/halo.c +++ b/hacks/halo.c @@ -1,4 +1,5 @@ -/* xscreensaver, Copyright (c) 1993 Jamie Zawinski +/* xscreensaver, Copyright (c) 1993, 1995, 1996, 1997, 1998, 1999, 2003 + * Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -19,6 +20,7 @@ */ #include "screenhack.h" +#include struct circle { int x, y, radius; @@ -26,25 +28,33 @@ struct circle { 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 @@ -71,35 +81,82 @@ 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; + 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); @@ -110,7 +167,7 @@ init_circles (dpy, window) #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; @@ -124,7 +181,7 @@ init_circles (dpy, window) 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; @@ -147,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; @@ -157,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 @@ -182,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 && - (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; @@ -219,28 +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) { - 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; @@ -254,55 +336,42 @@ run_circles (dpy, window) 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) @@ -310,36 +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); + } + } } char *progclass = "Halo"; char *defaults [] = { - "Halo.background: black", /* to placate SGI */ - "Halo.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); + } }