1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* toneclock --- Screenhack inspired by Peter Schat's toneclock
3  */
4 
5 #if 0
6 static const char sccsid[] = "@(#)toneclock.c	5.00 2004/09/16 xlockmore";
7 
8 #endif
9 
10 /*-
11  * Copyright (c) 2004 by Jouk Jansen <joukj AT hrem.nano.tudelft.nl>
12  *
13  * Permission to use, copy, modify, and distribute this software and its
14  * documentation for any purpose and without fee is hereby granted,
15  * provided that the above copyright notice appear in all copies and that
16  * both that copyright notice and this permission notice appear in
17  * supporting documentation.
18  *
19  * This file is provided AS IS with no warranties of any kind.  The author
20  * shall have no liability with respect to the infringement of copyrights,
21  * trade secrets or any patents by this file or any part thereof.  In no
22  * event will the author be liable for any lost revenue or profits or
23  * other special, indirect and consequential damages.
24  *
25  * The author should like to be notified if changes have been made to the
26  * routine.  Response will only be guaranteed when a VMS version of the
27  * program is available.
28  *
29  * Toneclock. Peter Schat (1937-2003) was a Dutch composer. Het invented
30  * the toneclock, a garphical representation of the tonesystem.
31  *
32  * Revision History:
33  * 20-Dec-2004: Initial release
34  * 23-Dec-2004: -size determines size of the clock
35  *              -original ignores all options and displays original clock
36  *              -pulsate make the clock pulsating
37  * 24-Dec-2004: -fill num
38  *               polygon filling chance implemented
39  * 04-Jan-2005: -move allow moving for small clocks
40  * 16-Feb-2005: -Number of hours according to "count" option
41  *              -Random polygons
42  *
43  */
44 #if 0
45 #define NO_DBUF
46 #endif
47 #ifdef STANDALONE
48 #define MODE_toneclock
49 #define DEFAULTS "*delay: 60000 \n" \
50 	"*count: -20 \n" \
51 	"*cycles: 200 \n" \
52 	"*size: -1000 \n" \
53 	"*ncolors: 64 \n" \
54 	"*fullrandom: True \n" \
55 	"*verbose: False \n" \
56 
57 # define free_toneclock 0
58 # define reshape_toneclock 0
59 # define toneclock_handle_event 0
60 #include "xlockmore.h"		/* in xscreensaver distribution */
61 #else /* STANDALONE */
62 #include "xlock.h"		/* in xlockmore distribution */
63 #include "color.h"
64 #endif /* STANDALONE */
65 
66 #ifdef MODE_toneclock
67 
68 #define DEF_NUM_hour 12
69 
70 #define DEF_CYCLE "True"
71 #define DEF_ORIGINAL "False"
72 #define DEF_PULSATING "False"
73 #define DEF_MOVE "True"
74 #define DEF_FILL "0"
75 
76 static Bool cycle_p , original , pulsating , move_clock;
77 static int fill;
78 
79 static XrmOptionDescRec opts[] =
80 {
81 	{(char *) "-fill", (char *) "tomecloc.fill", XrmoptionSepArg, (caddr_t) NULL},
82 	{(char *) "-cycle", (char *) ".toneclock.cycle", XrmoptionNoArg, (caddr_t) "on"},
83 	{(char *) "+cycle", (char *) ".toneclock.cycle", XrmoptionNoArg, (caddr_t) "off"},
84 	{(char *) "-original", (char *) ".toneclock.original", XrmoptionNoArg, (caddr_t) "on"},
85 	{(char *) "+original", (char *) ".toneclock.original", XrmoptionNoArg, (caddr_t) "off"},
86 	{(char *) "-move", (char *) ".toneclock.move", XrmoptionNoArg, (caddr_t) "on"},
87 	{(char *) "+move", (char *) ".toneclock.move", XrmoptionNoArg, (caddr_t) "off"},
88 	{(char *) "-pulsating", (char *) ".toneclock.pulsating", XrmoptionNoArg, (caddr_t) "on"},
89 	{(char *) "+pulsating", (char *) ".toneclock.pulsating", XrmoptionNoArg, (caddr_t) "off"}
90 };
91 
92 static argtype vars[] =
93 {
94 	{(void *) & fill, (char *) "fill", (char *) "Fill", (char *) DEF_FILL, t_Int},
95 	{(void *) & cycle_p, (char *) "cycle", (char *) "Cycle", (char *) DEF_CYCLE, t_Bool},
96 	{(void *) & original, (char *) "original", (char *) "Original", (char *) DEF_ORIGINAL, t_Bool},
97 	{(void *) & move_clock, (char *) "move", (char *) "Move", (char *) DEF_MOVE, t_Bool},
98 	{(void *) & pulsating, (char *) "pulsating", (char *) "Pulsating", (char *) DEF_PULSATING, t_Bool}
99 };
100 static OptionStruct desc[] =
101 {
102 	{(char *) "-fill num", (char *) "polygon filling chance in %"},
103 	{(char *) "-/+cycle", (char *) "turn on/off colour cycling"},
104 	{(char *) "-/+original", (char *) "turn on/off displaying original clock only"},
105 	{(char *) "-/+move", (char *) "turn on/off moving small clocks"},
106 	{(char *) "-/+pulsating", (char *) "turn on/off pulsating clock"}
107 };
108 
109 ENTRYPOINT ModeSpecOpt toneclock_opts =
110 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
111 
112 #ifdef USE_MODULES
113 ModStruct   toneclock_description =
114 {"toneclock", "init_toneclock", "draw_toneclock", "release_toneclock",
115  "refresh_toneclock", "init_toneclock", (char *) NULL, &toneclock_opts,
116  60000, -20, 200, -1000, 64, 1.0, "",
117  "Shows Peter Schat's toneclock", 0, NULL};
118 
119 #endif
120 
121 #define PI_RAD (M_PI / 180.0)
122 
123 typedef struct {
124 	unsigned long colour;
125 	float       angle, velocity , radius;
126 	int         num_point , num_point1;
127         int*        point_numbers;
128    	Bool draw;
129 } toneclockhour;
130 
131 typedef struct {
132 	Pixmap      dbuf;
133 	GC          dbuf_gc;
134 	GC          gc;
135 	Colormap    cmap;
136 	XColor     *colors;
137 	Bool        painted;
138 	int         win_width, win_height, num_hour, x0, y0 , fill;
139         float       angle , velocity , radius , phase , ph_vel;
140         float       vx , vy , anglex , angley , max_radius;
141         int         a_x , a_y;
142 	int         ncolors;
143 	Bool        cycle_p, mono_p, no_colors, original, pulsating , moving;
144         Bool        randomhour;
145 	unsigned long blackpixel, whitepixel, fg, bg;
146 	int         direction;
147 	int         hexadecimal_clock[512];
148 	toneclockhour *hour;
149 
150 } toneclockstruct;
151 
152 static int original_clock[12][16] = {
153      { 1 , 1 , 5 , 9 , 2 , 2 , 6  , 10 , 3 , 3 , 7 , 11 , 4 , 4 , 8 , 12 } ,
154      { 1 , 1 , 2 , 3 , 4 , 4 , 5  , 6 , 7 , 7 , 8 , 9 , 10 , 10 , 11 , 12 } ,
155      { 1 , 1 , 2 , 4 , 3 , 3 , 5  , 6 , 7 , 7 , 8 , 10 , 9 , 9 , 11 , 12 } ,
156      { 1 , 1 , 2 , 5 , 3 , 3 , 4  , 7 , 6 , 6 , 9 , 10 , 8 , 8 , 11 , 12 } ,
157      { 1 , 1 , 2 , 6 , 3 , 3 , 4  , 8 , 5 , 5 , 9 , 10 , 7 , 7 , 11 , 12 } ,
158      { 1 , 1 , 2 , 7 , 3 , 3 , 8  , 9 , 4 , 4 , 5 , 10 , 6 , 6 , 11 , 12 } ,
159      { 1 , 1 , 3 , 5 , 2 , 2 , 10 , 12 , 4 , 4 , 6 , 8 , 7 , 7 , 9 , 11 } ,
160      { 1 , 1 , 3 , 6 , 2 , 2 , 4  , 11 , 5 , 5 , 8 , 10 , 7 , 7 , 9 , 12 } ,
161      { 1 , 1 , 3 , 7 , 2 , 2 , 4  , 8 , 5 , 5 , 10 , 11 , 6 , 6 , 10 , 12 } ,
162      { 1 , 1 , 3 , 8 , 2 , 2 , 7  , 9 , 4 , 4 , 6 , 11 , 5 , 5 , 10 , 12 } ,
163      { 1 , 4 , 7 , 10 , 2 , 5 , 8  , 11 , 3 , 6 , 9 , 12 , 1 , 1 , 1 , 1 } ,
164      { 1 , 1 , 4 , 8 , 2 , 2 , 7  , 11 , 3 , 3 , 6 , 10 , 5 , 5 , 9 , 12 }
165 };
166 
167 static toneclockstruct *toneclocks = (toneclockstruct *) NULL;
168 
169 static void
toneclock_drawhour(ModeInfo * mi,toneclockhour * hour0,int x0,int y0)170 toneclock_drawhour(ModeInfo * mi, toneclockhour * hour0 ,
171 		   int x0 , int y0 )
172 {
173 	Display    *display = MI_DISPLAY(mi);
174    	toneclockstruct *tclock;
175 	int i;
176 #ifdef NO_DBUF
177 	Window drawable = MI_WINDOW(mi);
178 #else
179 #define drawable (Drawable) tclock->dbuf
180 #endif
181 	tclock = &toneclocks[MI_SCREEN(mi)];
182 
183    for (i = 0; i < hour0->num_point1; i = i + 4)
184      {
185 	int x , y , x1 , y1 , x2 , y2 , x3 , y3;
186 
187 	x = (int) (hour0->radius * sin( hour0->angle + PI_RAD *
188 					hour0->point_numbers[ i ] * 360.0 /
189 					hour0->num_point ) ) + x0;
190 	y = (int) (hour0->radius * cos( hour0->angle + PI_RAD *
191 					hour0->point_numbers[ i ] * 360.0 /
192 					hour0->num_point ) ) + y0;
193 	x1 = (int) (hour0->radius * sin( hour0->angle + PI_RAD *
194 					hour0->point_numbers[ i + 1 ] * 360.0 /
195 					hour0->num_point ) ) + x0;
196 	y1 = (int) (hour0->radius * cos( hour0->angle + PI_RAD *
197 					hour0->point_numbers[ i + 1 ] * 360.0 /
198 					hour0->num_point ) ) + y0;
199 	x2 = (int) (hour0->radius * sin( hour0->angle + PI_RAD *
200 					hour0->point_numbers[ i + 2 ] * 360.0 /
201 					hour0->num_point ) ) + x0;
202 	y2 = (int) (hour0->radius * cos( hour0->angle + PI_RAD *
203 					hour0->point_numbers[ i + 2 ] * 360.0 /
204 					hour0->num_point ) ) + y0;
205 	x3 = (int) (hour0->radius * sin( hour0->angle + PI_RAD *
206 					hour0->point_numbers[ i + 3 ] * 360.0 /
207 					hour0->num_point ) ) + x0;
208 	y3 = (int) (hour0->radius * cos( hour0->angle + PI_RAD *
209 					hour0->point_numbers[ i + 3 ] * 360.0 /
210 					hour0->num_point ) ) + y0;
211 	if ( hour0->draw )
212 	  {
213 	     XDrawLine(display, drawable, tclock->gc, x , y , x1 , y1 );
214 	     XDrawLine(display, drawable, tclock->gc, x1 , y1 , x2 , y2 );
215 	     XDrawLine(display, drawable, tclock->gc, x2 , y2 , x3 , y3 );
216 	     XDrawLine(display, drawable, tclock->gc, x , y , x3 , y3 );
217 	  }
218 	else
219 	  {
220 	     XPoint xy[4];
221 
222 	     xy[0].x = x;
223 	     xy[0].y = y;
224 	     xy[1].x = x1;
225 	     xy[1].y = y1;
226 	     xy[2].x = x2;
227 	     xy[2].y = y2;
228 	     xy[3].x = x3;
229 	     xy[3].y = y3;
230 	     XFillPolygon(display, drawable, tclock->gc, xy, 4 , Convex,
231 			  CoordModeOrigin);
232 	  }
233      }
234 }
235 
236 static void
free_hour(toneclockstruct * tclock)237 free_hour(toneclockstruct *tclock)
238 {
239 	if (tclock->hour != NULL) {
240 		free(tclock->hour);
241 		tclock->hour = (toneclockhour *) NULL;
242 	}
243 }
244 
245 static void
free_toneclock_screen(ModeInfo * mi,toneclockstruct * tclock)246 free_toneclock_screen(ModeInfo *mi, toneclockstruct *tclock)
247 {
248 	Display    *display = MI_DISPLAY(mi);
249 
250 	if (tclock == NULL) {
251 		return;
252 	}
253 	if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
254 		MI_WHITE_PIXEL(mi) = tclock->whitepixel;
255 		MI_BLACK_PIXEL(mi) = tclock->blackpixel;
256 #ifndef STANDALONE
257 		MI_FG_PIXEL(mi) = tclock->fg;
258 		MI_BG_PIXEL(mi) = tclock->bg;
259 #endif
260 		if (tclock->colors != NULL) {
261 #ifdef STANDALONE
262 			Screen *screen = MI_SCREENPTR(mi);
263 #endif
264 			if (tclock->ncolors && !tclock->no_colors)
265 				free_colors(
266 #ifdef STANDALONE
267 					screen,
268 #else
269 					display,
270 #endif
271 					tclock->cmap, tclock->colors, tclock->ncolors);
272 			free(tclock->colors);
273 			tclock->colors = (XColor *) NULL;
274 		}
275 		if (tclock->cmap != None) {
276 			XFreeColormap(display, tclock->cmap);
277 			tclock->cmap = None;
278 		}
279 	}
280 	if (tclock->gc != None) {
281 		XFreeGC(display, tclock->gc);
282 		tclock->gc = None;
283 	}
284 	free_hour(tclock);
285 #ifndef NO_DBUF
286 	if (tclock->dbuf != None) {
287 		XFreePixmap(display, tclock->dbuf);
288 		tclock->dbuf = None;
289 	}
290 	if (tclock->dbuf_gc != None) {
291 		XFreeGC(display, tclock->dbuf_gc);
292 		tclock->dbuf_gc = None;
293 	}
294 #endif
295 	tclock = NULL;
296 }
297 
298 #ifndef STANDALONE
299 extern char *background;
300 extern char *foreground;
301 #endif
302 
303 ENTRYPOINT void
init_toneclock(ModeInfo * mi)304 init_toneclock(ModeInfo * mi)
305 {
306 	Display    *display = MI_DISPLAY(mi);
307 	Window      window = MI_WINDOW(mi);
308 	int         i, size_hour, istart;
309 	toneclockstruct *tclock;
310 
311 /* initialize */
312 	MI_INIT(mi, toneclocks);
313 	tclock = &toneclocks[MI_SCREEN(mi)];
314 
315 	if (tclock->gc == None) {
316 		if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
317 			XColor      color;
318 
319 #ifndef STANDALONE
320 			tclock->fg = MI_FG_PIXEL(mi);
321 			tclock->bg = MI_BG_PIXEL(mi);
322 #endif
323 			tclock->blackpixel = MI_BLACK_PIXEL(mi);
324 			tclock->whitepixel = MI_WHITE_PIXEL(mi);
325 			if ((tclock->cmap = XCreateColormap(display, window,
326 					MI_VISUAL(mi), AllocNone)) == None) {
327 				free_toneclock_screen(mi, tclock);
328 				return;
329 			}
330 			XSetWindowColormap(display, window, tclock->cmap);
331 			(void) XParseColor(display, tclock->cmap, "black", &color);
332 			(void) XAllocColor(display, tclock->cmap, &color);
333 			MI_BLACK_PIXEL(mi) = color.pixel;
334 			(void) XParseColor(display, tclock->cmap, "white", &color);
335 			(void) XAllocColor(display, tclock->cmap, &color);
336 			MI_WHITE_PIXEL(mi) = color.pixel;
337 #ifndef STANDALONE
338 			(void) XParseColor(display, tclock->cmap, background, &color);
339 			(void) XAllocColor(display, tclock->cmap, &color);
340 			MI_BG_PIXEL(mi) = color.pixel;
341 			(void) XParseColor(display, tclock->cmap, foreground, &color);
342 			(void) XAllocColor(display, tclock->cmap, &color);
343 			MI_FG_PIXEL(mi) = color.pixel;
344 #endif
345 			tclock->colors = (XColor *) NULL;
346 			tclock->ncolors = 0;
347 		}
348 		if ((tclock->gc = XCreateGC(display, MI_WINDOW(mi),
349 			     (unsigned long) 0, (XGCValues *) NULL)) == None) {
350 			free_toneclock_screen(mi, tclock);
351 			return;
352 		}
353 	}
354 /* Clear Display */
355 	MI_CLEARWINDOW(mi);
356 	tclock->painted = False;
357 	XSetFunction(display, tclock->gc, GXxor);
358 
359 
360 /*Set up toneclock data */
361 	if (MI_IS_FULLRANDOM(mi)) {
362 	   if (NRAND(10))
363 	     tclock->original = False;
364 	   else
365 	     tclock->original = True;
366 	} else {
367 	   tclock->original = original;
368 	}
369 	tclock->direction = (LRAND() & 1) ? 1 : -1;
370 	tclock->win_width = MI_WIDTH(mi);
371 	tclock->win_height = MI_HEIGHT(mi);
372 	if (tclock->hour != NULL)
373 		free_hour(tclock);
374 	if ( tclock->original )
375           {
376 	     tclock->num_hour = 12;
377 	  }
378         else
379           {
380 	     tclock->num_hour = MI_COUNT(mi);
381 	  }
382         tclock->x0 = tclock->win_width / 2;
383         tclock->y0 = tclock->win_height / 2;
384 	if (tclock->num_hour == 0) {
385 		tclock->num_hour = DEF_NUM_hour;
386 	} else if (tclock->num_hour < 0) {
387 		tclock->num_hour = NRAND(-tclock->num_hour) + 1;
388 	}
389         if ( tclock->num_hour < 12 )
390           istart = NRAND( 12 - tclock->num_hour );
391         else
392           istart = 0;
393 	if ((tclock->hour = (toneclockhour *) calloc(tclock->num_hour,
394 			sizeof (toneclockhour))) == NULL) {
395 		free_toneclock_screen(mi, tclock);
396 		return;
397 	}
398 	if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
399 #ifdef STANDALONE
400 		Screen *screen = MI_SCREENPTR(mi);
401 #endif
402 /* Set up colour map */
403 		if (tclock->colors != NULL) {
404 			if (tclock->ncolors && !tclock->no_colors)
405 				free_colors(
406 #ifdef STANDALONE
407 					screen,
408 #else
409 					display,
410 #endif
411 					tclock->cmap, tclock->colors, tclock->ncolors);
412 			free(tclock->colors);
413 			tclock->colors = (XColor *) NULL;
414 		}
415 		tclock->ncolors = MI_NCOLORS(mi);
416 		if (tclock->ncolors < 2)
417 			tclock->ncolors = 2;
418 		if (tclock->ncolors <= 2)
419 			tclock->mono_p = True;
420 		else
421 			tclock->mono_p = False;
422 
423 		if (tclock->mono_p)
424 			tclock->colors = (XColor *) NULL;
425 		else
426 			if ((tclock->colors = (XColor *) malloc(sizeof (*tclock->colors) *
427 					(tclock->ncolors + 1))) == NULL) {
428 				free_toneclock_screen(mi, tclock);
429 				return;
430 			}
431 		tclock->cycle_p = has_writable_cells(
432 #ifdef STANDALONE
433 			screen, MI_VISUAL(mi)
434 #else
435 			mi
436 #endif
437 			);
438 		if (tclock->cycle_p) {
439 			if (MI_IS_FULLRANDOM(mi)) {
440 				if (!NRAND(8))
441 					tclock->cycle_p = False;
442 				else
443 					tclock->cycle_p = True;
444 			} else {
445 				tclock->cycle_p = cycle_p;
446 			}
447 		}
448 		if (!tclock->mono_p) {
449 			if (!(LRAND() % 10))
450 				make_random_colormap(
451 #ifdef STANDALONE
452 					screen, MI_VISUAL(mi),
453 					tclock->cmap, tclock->colors, &tclock->ncolors,
454 					True, True, &tclock->cycle_p, True
455 #else
456 					mi,
457 					tclock->cmap, tclock->colors, &tclock->ncolors,
458 					True, True, &tclock->cycle_p
459 #endif
460 					);
461 			else if (!(LRAND() % 2))
462 				make_uniform_colormap(
463 #ifdef STANDALONE
464 					screen, MI_VISUAL(mi),
465 					tclock->cmap, tclock->colors, &tclock->ncolors,
466 					True, &tclock->cycle_p, True
467 #else
468 					mi,
469 					tclock->cmap, tclock->colors, &tclock->ncolors,
470 					True, &tclock->cycle_p
471 #endif
472 					);
473 			else
474 				make_smooth_colormap(
475 #ifdef STANDALONE
476 					screen, MI_VISUAL(mi),
477 					tclock->cmap, tclock->colors, &tclock->ncolors,
478 					True, &tclock->cycle_p, True
479 #else
480 					mi,
481 					tclock->cmap, tclock->colors, &tclock->ncolors,
482 					True, &tclock->cycle_p
483 #endif
484 					);
485 		}
486 		XInstallColormap(display, tclock->cmap);
487 		if (tclock->ncolors < 2) {
488 			tclock->ncolors = 2;
489 			tclock->no_colors = True;
490 		} else
491 			tclock->no_colors = False;
492 		if (tclock->ncolors <= 2)
493 			tclock->mono_p = True;
494 
495 		if (tclock->mono_p)
496 			tclock->cycle_p = False;
497 
498 	}
499 #ifndef NO_DBUF
500 	if (tclock->dbuf != None)
501 		XFreePixmap(display, tclock->dbuf);
502 	tclock->dbuf = XCreatePixmap(display, window,
503 		tclock->win_width,
504 		tclock->win_height,
505 		MI_DEPTH(mi));
506 	/* Allocation checked */
507 	if (tclock->dbuf != None) {
508 		XGCValues   gcv;
509 
510 		gcv.foreground = 0;
511 		gcv.background = 0;
512 		gcv.graphics_exposures = False;
513 		gcv.function = GXcopy;
514 
515 		if (tclock->dbuf_gc != None)
516 			XFreeGC(display, tclock->dbuf_gc);
517 		if ((tclock->dbuf_gc = XCreateGC(display, (Drawable) tclock->dbuf,
518 			GCForeground | GCBackground | GCGraphicsExposures | GCFunction,
519 				&gcv)) == None) {
520 			XFreePixmap(display, tclock->dbuf);
521 			tclock->dbuf = None;
522 		} else {
523 			XFillRectangle(display, (Drawable) tclock->dbuf, tclock->dbuf_gc,
524 				0, 0, tclock->win_width, tclock->win_height);
525 			/*XSetBackground(display, MI_GC(mi), MI_BLACK_PIXEL(mi));
526 			XSetFunction(display, MI_GC(mi), GXcopy);*/
527 		}
528 	}
529 #endif
530 	tclock->angle = NRAND(360) * PI_RAD;
531 	tclock->velocity = (NRAND(7) - 3) * PI_RAD;
532 	size_hour = MIN( tclock->win_width , tclock->win_height) / 3;
533    tclock->pulsating = False;
534    tclock->moving = False;
535    tclock->anglex = 0.0;
536    tclock->angley = 0.0;
537    tclock->fill = 0;
538    tclock->radius = size_hour;
539    tclock->max_radius =0.0;
540    if ( ( !tclock->original && NRAND( 15 ) == 3 ) || tclock->num_hour > 12 )
541      tclock->randomhour = True;
542    else
543      tclock->randomhour = False;
544    if ( !tclock->original && tclock->win_width > 20 )
545      {
546 	if ( abs( MI_SIZE(mi) ) > size_hour ) {
547 	   if ( MI_SIZE( mi ) < 0 )
548 	     {
549 		size_hour = -size_hour;
550 	     }
551 	}
552 	else
553 	  {
554 	     size_hour = MI_SIZE(mi);
555           }
556     	if ( size_hour < 0 )
557           {
558 	     tclock->radius = MIN(NRAND( -size_hour - 10) + 10,
559 		tclock->radius );
560           }
561         else
562           {
563   	     tclock->radius = MIN( size_hour , tclock->radius );
564           }
565 	if ( MI_IS_FULLRANDOM( mi ) )
566 	  {
567 	     if ( NRAND(2) )
568 	       tclock->pulsating = True;
569 	     else
570 	       tclock->pulsating = False;
571 	     tclock->fill = NRAND( 101 );
572 	  }
573 	else
574 	  {
575 	     tclock->pulsating = pulsating;
576 	     tclock->fill = fill;
577 	  }
578      }
579    tclock->phase = 0.0;
580    if ( tclock->pulsating )
581 	tclock->ph_vel = (NRAND(7) - 3) * PI_RAD;
582    for (i = 0; i < tclock->num_hour; i++) {
583 		toneclockhour *hour0;
584 
585 		hour0 = &tclock->hour[i];
586 		if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
587 			if (tclock->ncolors > 2)
588 				hour0->colour = NRAND(tclock->ncolors - 2) + 2;
589 			else
590 				hour0->colour = 1;	/* Just in case */
591 			XSetForeground(display, tclock->gc, tclock->colors[hour0->colour].pixel);
592 		} else {
593 			if (MI_NPIXELS(mi) > 2)
594 				hour0->colour = MI_PIXEL(mi, NRAND(MI_NPIXELS(mi)));
595 			else
596 				hour0->colour = 1;	/*Xor'red so WHITE may not be appropriate */
597 			XSetForeground(display, tclock->gc, hour0->colour);
598 		}
599 		hour0->angle = NRAND(360) * PI_RAD;
600 		hour0->velocity = (NRAND(7) - 3) * PI_RAD;
601 	        hour0->radius = tclock->radius / 5.0;
602       		tclock->max_radius = MAX( tclock->max_radius , hour0->radius );
603 	        hour0->num_point = 12;
604 		hour0->num_point1 = 16;
605                 if ( tclock->randomhour )
606 	          {
607 		     int j;
608 
609 		     hour0->point_numbers = tclock->hexadecimal_clock + i *
610 			     hour0->num_point1;
611 		     if ( NRAND( 14 ) == 4 )
612 		       {
613 			  for (j = 0; j < ( hour0->num_point1 / 4 ) - 1 ; j++)
614 			    {
615 			       hour0->point_numbers[ j * 4 ] = NRAND( 12 ) + 1;
616 			       hour0->point_numbers[ j * 4 + 1 ] = NRAND( 12 )
617 				 + 1;
618 			       hour0->point_numbers[ j * 4 + 2 ] = NRAND( 12 )
619 				 + 1;
620 			       hour0->point_numbers[ j * 4 + 3 ] = NRAND( 12 )
621 				 + 1;
622 			    }
623 			  hour0->point_numbers[ hour0->num_point1 / 4 ] = 1;
624 			  hour0->point_numbers[ 1 + hour0->num_point1 / 4 ] =
625 			    1;
626 			  hour0->point_numbers[ 2 + hour0->num_point1 / 4 ] =
627 			    1;
628 			  hour0->point_numbers[ 3 + hour0->num_point1 / 4 ] =
629 			    1;
630 		       }
631 		     else
632 		       {
633 			  for (j = 0; j < hour0->num_point1 / 4 ; j++)
634 			    {
635 			       hour0->point_numbers[ j * 4 ] = NRAND( 12 ) + 1;
636 			       hour0->point_numbers[ j * 4 + 1 ] =
637 				 hour0->point_numbers[ j * 4 ];
638 			       hour0->point_numbers[ j * 4 + 2 ] = NRAND( 12 )
639 				 + 1;
640 			       hour0->point_numbers[ j * 4 + 3 ] = NRAND( 12 )
641 				 + 1;
642 			    }
643 		       }
644 	          }
645                 else
646 	          hour0->point_numbers = original_clock[i+istart];
647 		if ( NRAND( 100 ) >= tclock->fill )
648 			hour0->draw = True;
649 		else
650 			hour0->draw = False;
651 #ifdef NO_DBUF
652 		{
653 		  int x0 , y0;
654 
655 		  x0 = (int) (tclock->radius * sin( -tclock->angle - PI_RAD * i *
656 			360.0 / tclock->num_hour ) *
657 			0.5 * ( 1 + cos( tclock->phase ) ) + tclock->x0 +
658 			tclock->a_x * sin( tclock->anglex ) );
659 		  y0 = (int) (tclock->radius * cos( -tclock->angle - PI_RAD * i *
660 			360.0 / tclock->num_hour ) *
661 			0.5 * ( 1 + cos( tclock->phase ) ) + tclock->y0 +
662 			tclock->a_y * sin( tclock->angley ) );
663 	 	  toneclock_drawhour(mi , hour0 , x0 , y0 );
664 		}
665 #endif
666 	}
667    tclock->a_x = 0;
668    tclock->a_y = 0;
669    if ( !tclock->original && tclock->win_width > 20 )
670      {
671 	if ( tclock->radius < MIN( tclock->win_width , tclock->win_height) /
672 	     4 )
673 	  {
674 	     if ( MI_IS_FULLRANDOM( mi ) )
675 	       {
676 		  if ( NRAND(2) )
677 		    tclock->moving = True;
678 	       }
679 	     else
680 	       {
681 		    tclock->moving = move_clock;
682 	       }
683 	     if ( tclock->moving )
684 	       {
685 		  tclock->a_x = (int) floor( ( tclock->win_width / 2 ) - 1.05 *
686 					( tclock->radius + tclock->max_radius )
687 					);
688 		  tclock->a_y = (int) floor( ( tclock->win_height / 2 ) - 1.05 *
689 					( tclock->radius + tclock->max_radius )
690 					);
691 		  tclock->vx = (NRAND(15) - 7) * PI_RAD;
692 		  tclock->vy = (NRAND(15) - 7) * PI_RAD;
693 	       }
694 	  }
695      }
696 	XFlush(display);
697 	XSetFunction(display, tclock->gc, GXcopy);
698 }
699 
700 ENTRYPOINT void
draw_toneclock(ModeInfo * mi)701 draw_toneclock(ModeInfo * mi)
702 {
703 	Display    *display = MI_DISPLAY(mi);
704 	Window      window = MI_WINDOW(mi);
705 	int         i;
706 	toneclockstruct *tclock;
707 
708 	if (toneclocks == NULL)
709 		return;
710 	tclock = &toneclocks[MI_SCREEN(mi)];
711 	if (tclock->hour == NULL)
712 		return;
713 
714 	if (tclock->no_colors) {
715 		free_toneclock_screen(mi, tclock);
716 		init_toneclock(mi);
717 		return;
718 	}
719 	XSetFunction(display, tclock->gc, GXxor);
720 #ifndef NO_DBUF
721         XSetForeground(display,tclock->dbuf_gc,MI_BLACK_PIXEL(mi));
722 	XFillRectangle(display, (Drawable) tclock->dbuf, tclock->dbuf_gc,
723 		0, 0, tclock->win_width, tclock->win_height);
724 #endif
725 	tclock->painted = True;
726 	MI_IS_DRAWN(mi) = True;
727 /* Rotate colours */
728 	if (tclock->cycle_p) {
729 		rotate_colors(
730 #ifdef STANDALONE
731 			MI_SCREENPTR(mi),
732 #else
733 			display,
734 #endif
735 			tclock->cmap, tclock->colors, tclock->ncolors, tclock->direction);
736 		if (!(LRAND() % 1000))
737 			tclock->direction = -tclock->direction;
738 	}
739 	for (i = 0; i < tclock->num_hour; i++) {
740 		toneclockhour *hour0;
741 	   int x0 , y0;
742 
743 	   x0 = (int) (tclock->radius * sin( -tclock->angle - PI_RAD * i *
744 					     360.0 / tclock->num_hour ) *
745 	     0.5 * ( 1 + cos( tclock->phase ) ) + tclock->x0 +
746 		       tclock->a_x * sin( tclock->anglex ) );
747 	   y0 = (int) (tclock->radius * cos( -tclock->angle - PI_RAD * i *
748 					     360.0 / tclock->num_hour ) *
749 	       0.5 * ( 1 + cos( tclock->phase ) ) + tclock->y0 +
750 		       tclock->a_y * sin( tclock->angley ) );
751 		hour0 = &tclock->hour[i];
752 		if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
753 			XSetForeground(display, tclock->gc, tclock->colors[hour0->colour].pixel);
754 		} else {
755 			XSetForeground(display, tclock->gc, hour0->colour);
756 		}
757 		toneclock_drawhour(mi, hour0 , x0 , y0);
758 		hour0->velocity += ((float) NRAND(1001) - 500.0) / 200000.0;
759 		hour0->angle += hour0->velocity;
760 	}
761    tclock->velocity += ((float) NRAND(1001) - 500.0) / 200000.0;
762    tclock->angle += tclock->velocity;
763 	       if ( tclock->pulsating )
764 	       tclock->phase += tclock->ph_vel;
765    if ( tclock->moving )
766      {
767 	tclock->anglex += tclock->vx;
768 	tclock->angley += tclock->vy;
769      }
770 #ifdef NO_DBUF
771 	for (i = 0; i < tclock->num_hour; i++) {
772 		toneclockhour *hour0;
773 	   int x0 , y0;
774 
775 	   x0 = (int) (tclock->radius * sin( -tclock->angle - PI_RAD * i *
776 					     360.0 / tclock->num_hour ) *
777 	     0.5 * ( 1 + cos( tclock->phase ) ) + tclock->x0 +
778 		       tclock->a_x * sin( tclock->anglex ) );
779 	   y0 = (int) (tclock->radius * cos( -tclock->angle - PI_RAD * i *
780 					     360.0 / tclock->num_hour ) *
781 	       0.5 * ( 1 + cos( tclock->phase ) ) + tclock->y0 +
782 		       tclock->a_y * sin( tclock->angley ) );
783 		hour0 = &tclock->hour[i];
784 		if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
785 			XSetForeground(display, tclock->gc, tclock->colors[hour0->colour].pixel);
786 		} else {
787 			XSetForeground(display, tclock->gc, hour0->colour);
788 		}
789 		toneclock_drawhour(mi, hour0 , x0 , y0);
790 	}
791 #else
792      XFlush(display);
793      XCopyArea (display, (Drawable) tclock->dbuf, window, tclock->dbuf_gc, 0, 0,
794 		     tclock->win_width, tclock->win_height, 0, 0);
795      XFlush(display);
796      XSetForeground(display,tclock->dbuf_gc,MI_BLACK_PIXEL(mi));
797      XFillRectangle(display, (Drawable) tclock->dbuf, tclock->dbuf_gc,
798 		0, 0, tclock->win_width, tclock->win_height);
799 #endif
800 	XSetFunction(display, tclock->gc, GXcopy);
801 }
802 
803 ENTRYPOINT void
release_toneclock(ModeInfo * mi)804 release_toneclock(ModeInfo * mi)
805 {
806 	if (toneclocks != NULL) {
807 		int         screen;
808 
809 		for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
810 			free_toneclock_screen(mi, &toneclocks[screen]);
811 		free(toneclocks);
812 		toneclocks = (toneclockstruct *) NULL;
813 	}
814 }
815 
816 #ifndef STANDALONE
817 ENTRYPOINT void
refresh_toneclock(ModeInfo * mi)818 refresh_toneclock(ModeInfo * mi)
819 {
820 	toneclockstruct *tclock;
821 
822 	if (toneclocks == NULL)
823 		return;
824 	tclock = &toneclocks[MI_SCREEN(mi)];
825 	if (tclock->hour == NULL)
826 		return;
827 
828 	if (!tclock->painted)
829 		return;
830 	MI_CLEARWINDOW(mi);
831 #ifdef NO_DBUF
832 	{
833 	  Display    *display = MI_DISPLAY(mi);
834 	  int i;
835 
836 	  XSetFunction(display, tclock->gc, GXxor);
837 	  for (i = 0; i < tclock->num_hour; i++) {
838 		toneclockhour *hour0;
839 	   int x0 , y0;
840 
841 	   x0 = (int) (tclock->radius * sin( -tclock->angle - PI_RAD * i *
842 					     360.0 / tclock->num_hour ) +
843 	     tclock->x0 + tclock->a_x * sin( tclock->anglex ) );
844 	   y0 = (int) (tclock->radius * cos( -tclock->angle - PI_RAD * i *
845 					     360.0 / tclock->num_hour ) +
846 	     tclock->y0 + tclock->a_y * sin( tclock->angley ) );
847 		hour0 = &tclock->hour[i];
848 		if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
849 			XSetForeground(display, tclock->gc, tclock->colors[hour0->colour].pixel);
850 		} else {
851 			XSetForeground(display, tclock->gc, hour0->colour);
852 		}
853 		toneclock_drawhour(mi, hour0 , x0 , y0 );
854 	   }
855 	  XSetFunction(display, tclock->gc, GXcopy);
856 	}
857 #endif
858 }
859 #endif
860 
861 XSCREENSAVER_MODULE ("Toneclock", toneclock)
862 
863 #endif /* MODE_toneclock */
864