1 /* The Spiral Generator, Copyright (c) 2000
2 * by Rohit Singh <rohit_singh@hotmail.com>
4 * Contains code from / To be used with:
5 * xscreensaver, Copyright (c) 1992, 1995, 1996, 1997
6 * Jamie Zawinski <jwz@jwz.org>
8 * Permission to use, copy, modify, distribute, and sell this software and its
9 * documentation for any purpose is hereby granted without fee, provided that
10 * the above copyright notices appear in all copies and that both that
11 * copyright notices and this permission notice appear in supporting
12 * documentation. No representations are made about the suitability of this
13 * software for any purpose. It is provided "as is" without express or
16 * Modified (Dec 2001) by Matthew Strait <straitm@mathcs.carleton.edu>
17 * Added -subdelay and -alwaysfinish
18 * Prevented redrawing over existing lines
22 #include "screenhack.h"
28 XWindowAttributes xgwa;
34 unsigned int default_fg_pixel;
55 init_tsg (struct state *st)
60 XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
61 cmap = st->xgwa.colormap;
62 gcv.foreground = st->default_fg_pixel =
63 get_pixel_resource (st->dpy, cmap, "foreground", "Foreground");
64 st->draw_gc = XCreateGC (st->dpy, st->window, GCForeground, &gcv);
65 gcv.foreground = get_pixel_resource (st->dpy, cmap, "background", "Background");
70 go (struct state *st, int radius1, int radius2, int d)
77 width = st->xgwa.width;
78 height = st->xgwa.height;
84 st->x1 = xmid + radius1 - radius2 + d;
88 /* for (theta = 1; / * theta < ( 360 * 100 ) * /; theta++) */
89 /* see below about alwaysfinish */
91 tmpx = xmid + (( radius1 /* * * * * */
92 - radius2 ) /* This algo simulates */
93 * cos(( st->theta /* the rotation of a */
94 * M_PI ) /* circular disk inside */
95 / 180 )) /* a hollow circular */
96 + ( d /* rim. A point on the */
97 * cos(((( radius1 /* disk dist d from the */
98 * st->theta ) /* centre, traces the */
99 - delta ) /* path given by this */
100 / radius2 ) /* equation. */
101 * M_PI /* A deviation (error) */
102 / 180 ) /* of delta needs to be */
103 ); /* given, which greatly */
104 /* adds to the beauty */
105 tmpy = ymid + ( /* of the figure. */
106 ( radius1 - radius2 /* */
107 ) * sin /* Imperfection adds to */
108 ( /* beauty, symbolically */
109 ( st->theta * M_PI /* ... */
110 ) / 180 /* Algo deduced by */
111 ) /* Rohit Singh, Jan'00 */
112 ) + /* based on a toy he */
113 ( d * sin /* used to play with */
114 ( /* when he was a kid. */
117 ( radius1 * st->theta
124 /*makes integers from the calculated values to do the drawing*/
128 /*stores the first values for later reference*/
136 XDrawLine (st->dpy, st->window, st->draw_gc,
137 st->x1, st->y1, st->x2, st->y2);
142 /* compares the exact values calculated to the first
143 exact values calculated */
144 /* this will break when nothing new is being drawn */
145 if(tmpx == st->firstx && tmpy == st->firsty && st->theta != 1) {
146 st->firstx = st->firsty = 0;
151 /* this will break after 36000 iterations if
152 the -alwaysfinish option is not specified */
153 if(!st->always_finish_p && st->theta > ( 360 * 100 ) ) {
154 st->firstx = st->firsty = 0;
166 #define min(a,b) ((a)<(b)?(a):(b))
170 pick_new (struct state *st)
172 int radius = min (st->xgwa.width, st->xgwa.height) / 2;
173 st->divisor = ((frand (3.0) + 1) * (((random() & 1) * 2) - 1));
174 st->radius1 = radius;
175 st->radius2 = radius / st->divisor + 5;
176 st->distance = 100 + (random() % 200);
182 xspirograph_init (Display *dpy, Window window)
184 struct state *st = (struct state *) calloc (1, sizeof(*st));
187 st->long_delay = get_integer_resource(st->dpy, "delay", "Integer");
188 st->sub_sleep_time = get_integer_resource(st->dpy, "subdelay", "Integer");
189 st->num_layers = get_integer_resource(st->dpy, "layers", "Integer");
190 st->always_finish_p = get_boolean_resource (st->dpy, "alwaysfinish", "Boolean");
192 XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
203 new_colors (struct state *st)
206 XSetForeground (st->dpy, st->draw_gc, st->default_fg_pixel);
209 hsv_to_rgb (random () % 360, frand (1.0), frand (0.5) + 0.5,
210 &st->color.red, &st->color.green, &st->color.blue);
211 if ((st->got_color = XAllocColor (st->dpy, st->xgwa.colormap,
213 XSetForeground (st->dpy, st->draw_gc, st->color.pixel);
215 XSetForeground (st->dpy, st->draw_gc, st->default_fg_pixel);
222 xspirograph_draw (Display *dpy, Window window, void *closure)
224 struct state *st = (struct state *) closure;
225 Bool free_color = False;
228 /* 5 sec delay before starting the erase */
229 if (st->erasing == 2) {
231 return (st->long_delay == 0 ? 0 : 5000000);
234 /* erase, delaying 1/50th sec between frames */
235 if (st->erasing || st->eraser) {
237 st->eraser = erase_window (st->dpy, st->window, st->eraser);
241 /* just finished erasing -- leave screen black for 1 sec */
242 return (st->long_delay == 0 ? 0 : 1000000);
245 flip_p = (st->counter & 1);
252 if (st->counter > (2 * st->num_layers))
257 XFreeColors (st->dpy, st->xgwa.colormap, &st->color.pixel, 1, 0);
271 for (i = 0; i < 1000; i++) {
272 if (go (st, st->radius1,
273 (flip_p ? st->radius2 : -st->radius2),
281 return st->sub_sleep_time;
286 xspirograph_reshape (Display *dpy, Window window, void *closure,
287 unsigned int w, unsigned int h)
289 struct state *st = (struct state *) closure;
290 XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
294 xspirograph_event (Display *dpy, Window window, void *closure, XEvent *event)
300 xspirograph_free (Display *dpy, Window window, void *closure)
302 struct state *st = (struct state *) closure;
307 static const char *xspirograph_defaults [] = {
308 ".background: black",
309 ".foreground: white",
314 "*alwaysfinish: false",
318 static XrmOptionDescRec xspirograph_options [] = {
319 { "-delay", ".delay", XrmoptionSepArg, 0 },
320 { "-subdelay", ".subdelay", XrmoptionSepArg, 0 },
321 { "-layers", ".layers", XrmoptionSepArg, 0 },
322 { "-alwaysfinish", ".alwaysfinish", XrmoptionNoArg, "true"},
323 { "-noalwaysfinish", ".alwaysfinish", XrmoptionNoArg, "false"},
327 XSCREENSAVER_MODULE ("XSpirograph", xspirograph)