1 /* xscreensaver, Copyright (c) 1993 Jamie Zawinski <jwz@lucid.com>
3 * Permission to use, copy, modify, distribute, and sell this software and its
4 * documentation for any purpose is hereby granted without fee, provided that
5 * the above copyright notice appear in all copies and that both that
6 * copyright notice and this permission notice appear in supporting
7 * documentation. No representations are made about the suitability of this
8 * software for any purpose. It is provided "as is" without express or
12 /* I wanted to lay down new circles with TV:ALU-ADD instead of TV:ALU-XOR,
13 but X doesn't support arithmetic combinations of pixmaps!! What losers.
14 I suppose I could crank out the 2's compliment math by hand, but that's
17 This would probably look good with shapes other than circles as well.
21 #include "screenhack.h"
29 static struct circle *circles;
30 static int count, global_count;
31 static Pixmap pixmap, buffer;
32 static int width, height, global_inc;
34 static unsigned long fg_pixel, bg_pixel;
35 static XColor fgc, bgc;
37 static GC draw_gc, erase_gc, copy_gc, merge_gc;
41 #define min(x,y) ((x)<(y)?(x):(y))
42 #define max(x,y) ((x)>(y)?(x):(y))
45 init_circles_1 (dpy, window)
50 count = (global_count ? global_count
51 : (3 + (random () % max (1, (min (width, height) / 50)))
52 + (random () % max (1, (min (width, height) / 50)))));
53 circles = (struct circle *) malloc (count * sizeof (struct circle));
54 for (i = 0; i < count; i++)
56 circles [i].x = 10 + random () % (width - 20);
57 circles [i].y = 10 + random () % (height - 20);
59 circles [i].increment = global_inc;
61 { /* prefer smaller increments to larger ones */
63 int inc = ((random()%j) + (random()%j) + (random()%j)) - ((j*3)/2);
64 if (inc < 0) inc = -inc + 3;
65 circles [i].increment = inc + 3;
67 circles [i].radius = random () % circles [i].increment;
68 circles [i].dx = ((random () % 3) - 1) * (1 + random () % 5);
69 circles [i].dy = ((random () % 3) - 1) * (1 + random () % 5);
74 init_circles (dpy, window)
79 XWindowAttributes xgwa;
80 XGetWindowAttributes (dpy, window, &xgwa);
82 global_count = get_integer_resource ("count", "Integer");
83 if (global_count < 0) global_count = 0;
84 global_inc = get_integer_resource ("increment", "Integer");
85 if (global_inc < 0) global_inc = 0;
86 xor_p = get_boolean_resource ("xor", "Boolean");
87 /* if (mono_p) */ xor_p = True;
88 anim_p = get_boolean_resource ("animate", "Boolean");
89 delay = get_integer_resource ("delay", "Integer");
92 fg_pixel = get_pixel_resource ("foreground","Foreground", dpy, cmap);
93 bg_pixel = get_pixel_resource ("background","Background", dpy, cmap);
97 hsv_to_rgb (0, 0.5, 1.0, &fgc.red, &fgc.green, &fgc.blue);
98 hsv_to_rgb (180, 1.0, 0.7, &bgc.red, &bgc.green, &bgc.blue);
99 XAllocColor (dpy, cmap, &fgc);
100 XAllocColor (dpy, cmap, &bgc);
101 fg_pixel = fgc.pixel;
102 bg_pixel = bgc.pixel;
105 width = max (50, xgwa.width);
106 height = max (50, xgwa.height);
112 pixmap = XCreatePixmap (dpy, window, width, height, 1);
114 buffer = XCreatePixmap (dpy, window, width, height, 1);
120 draw_gc = XCreateGC (dpy, pixmap, GCForeground | GCBackground, &gcv);
122 erase_gc = XCreateGC (dpy, pixmap, GCForeground, &gcv);
123 gcv.foreground = fg_pixel;
124 gcv.background = bg_pixel;
125 copy_gc = XCreateGC (dpy, window, GCForeground | GCBackground, &gcv);
131 gcv.function = GXxor;
132 merge_gc = XCreateGC (dpy, pixmap,
133 GCForeground | GCBackground | GCFunction, &gcv);
137 gcv.foreground = fg_pixel;
138 gcv.background = bg_pixel;
139 gcv.function = GXcopy;
140 merge_gc = XCreateGC (dpy, window,
141 GCForeground | GCBackground | GCFunction, &gcv);
144 init_circles_1 (dpy, window);
145 XClearWindow (dpy, window);
146 if (buffer) XFillRectangle (dpy, buffer, erase_gc, 0, 0, width, height);
150 run_circles (dpy, window)
155 static int iterations = 0;
156 static int oiterations = 0;
157 static Bool first_time_p = True;
159 Bool inhibit_sleep = False;
160 XFillRectangle (dpy, pixmap, erase_gc, 0, 0, width, height);
161 for (i = 0; i < count; i++)
163 int radius = circles [i].radius;
164 int inc = circles [i].increment;
165 if (! (iterations & 1))
167 else if (radius == 0)
173 /* Probably there's a simpler way to ask the musical question,
174 "is this square completely enclosed by this circle," but I've
175 forgotten too much trig to know it... (That's not really the
176 right question anyway, but the right question is too hard.) */
177 double x1 = ((double) (-circles [i].x)) / ((double) radius);
178 double y1 = ((double) (-circles [i].y)) / ((double) radius);
179 double x2 = ((double) (width - circles [i].x)) / ((double) radius);
180 double y2 = ((double) (height - circles [i].y)) / ((double) radius);
181 x1 *= x1; x2 *= x2; y1 *= y1; y2 *= y2;
182 if ((x1 + y1) < 1 && (x2 + y2) < 1 && (x1 + y2) < 1 && (x2 + y1) < 1)
186 (xor_p || circles [0].increment < 0))
188 (xor_p ? pixmap : window),
189 (xor_p ? draw_gc : merge_gc),
190 circles [i].x - radius, circles [i].y - radius,
191 radius * 2, radius * 2, 0, 360*64);
192 circles [i].radius += inc;
195 if (anim_p && !first_time_p)
196 inhibit_sleep = !done;
202 first_time_p = False;
203 for (i = 0; i < count; i++)
205 circles [i].x += circles [i].dx;
206 circles [i].y += circles [i].dy;
207 circles [i].radius %= circles [i].increment;
208 if (circles [i].x < 0 || circles [i].x >= width)
210 circles [i].dx = -circles [i].dx;
211 circles [i].x += (2 * circles [i].dx);
213 if (circles [i].y < 0 || circles [i].y >= height)
215 circles [i].dy = -circles [i].dy;
216 circles [i].y += (2 * circles [i].dy);
220 else if (circles [0].increment < 0)
223 init_circles_1 (dpy, window);
226 cycle_hue (&fgc, 10);
227 cycle_hue (&bgc, 10);
228 XFreeColors (dpy, cmap, &fgc.pixel, 1, 0);
229 XFreeColors (dpy, cmap, &bgc.pixel, 1, 0);
230 XAllocColor (dpy, cmap, &fgc);
231 XAllocColor (dpy, cmap, &bgc);
232 XSetForeground (dpy, copy_gc, fgc.pixel);
233 XSetBackground (dpy, copy_gc, bgc.pixel);
237 else if ((random () % 2) == 0)
239 iterations = 0; /* ick */
240 for (i = 0; i < count; i++)
241 circles [i].radius %= circles [i].increment;
246 oiterations = iterations;
247 for (i = 0; i < count; i++)
249 circles [i].increment = -circles [i].increment;
250 circles [i].radius += (2 * circles [i].increment);
256 XCopyPlane (dpy, pixmap, buffer, merge_gc, 0, 0, width, height, 0, 0, 1);
259 static int ncolors = 0;
260 static XColor *colors = 0;
261 if (circles [0].increment >= 0)
262 inhibit_sleep = True;
266 double fgs, fgv, bgs, bgv;
268 for (i = 0; i < ncolors; i++)
269 XFreeColors (dpy, cmap, &colors [i].pixel, 1, 0);
271 rgb_to_hsv (fgc.red, fgc.green, fgc.blue, &fgh, &fgs, &fgv);
272 rgb_to_hsv (bgc.red, bgc.green, bgc.blue, &bgh, &bgs, &bgv);
273 ncolors = oiterations;
276 ? realloc (colors, sizeof (XColor) * ncolors)
277 : malloc (sizeof (XColor) * ncolors)));
279 make_color_ramp (bgh, bgs, bgv, fgh, fgs, fgv, colors, ncolors);
280 for (i = 0; i < ncolors; i++)
281 XAllocColor (dpy, cmap, &colors [i]);
282 XSetForeground (dpy, merge_gc, colors [0].pixel);
286 XSetForeground (dpy, merge_gc, colors [iterations].pixel);
290 XCopyPlane (dpy, pixmap, window, merge_gc, 0, 0, width, height, 0, 0, 1);
292 if (buffer && (anim_p
293 ? (done || (first_time_p && (iterations & 1)))
296 XCopyPlane (dpy, buffer, window, copy_gc, 0, 0, width, height, 0, 0, 1);
299 XFillRectangle (dpy, buffer, erase_gc, 0, 0, width, height);
302 XCopyPlane (dpy, pixmap, window, copy_gc, 0,0,width,height,width,height, 1);
304 XCopyPlane (dpy, buffer, window, copy_gc, 0,0,width,height,0,height, 1);
313 if (delay && !inhibit_sleep) usleep (delay);
317 char *progclass = "Halo";
319 char *defaults [] = {
320 "*background: black",
321 "*foreground: white",
328 XrmOptionDescRec options [] = {
329 { "-count", ".count", XrmoptionSepArg, 0 },
330 { "-delay", ".delay", XrmoptionSepArg, 0 },
331 { "-animate", ".animate", XrmoptionNoArg, "True" } /* ,
332 { "-xor", ".xor", XrmoptionNoArg, "True" },
333 { "-no-xor", ".xor", XrmoptionNoArg, "False" } */
335 int options_size = (sizeof (options) / sizeof (options[0]));
338 screenhack (dpy, window)
342 init_circles (dpy, window);
344 run_circles (dpy, window);