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