1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* tube --- animated tube */
3
4 #if 0
5 static const char sccsid[] = "@(#)tube.c 5.09 2003/06/30 xlockmore";
6
7 #endif
8
9 /*-
10 * Copyright (c) 1997 Dan Stromberg <strombrg AT nis.acs.uci.edu>
11 *
12 * Permission to use, copy, modify, and distribute this software and its
13 * documentation for any purpose and without fee is hereby granted,
14 * provided that the above copyright notice appear in all copies and that
15 * both that copyright notice and this permission notice appear in
16 * supporting documentation.
17 *
18 * This file is provided AS IS with no warranties of any kind. The author
19 * shall have no liability with respect to the infringement of copyrights,
20 * trade secrets or any patents by this file or any part thereof. In no
21 * event will the author be liable for any lost revenue or profits or
22 * other special, indirect and consequential damages.
23 *
24 * Revision History:
25 * 30-Jun-2003: Changed writeable mode to be more consistent with
26 * xscreensaver's starfish
27 * 01-Nov-2000: Allocation checks
28 * 10-May-1997: Compatible with xscreensaver
29 * 04-Mar-1997: Memory leak fix by Tom Schmidt <tschmidt AT micron.com>
30 * 07-Feb-1997: Written by Dan Stromberg <strombrg AT nis.acs.uci.edu>
31 */
32
33
34 #ifdef STANDALONE
35 #define MODE_tube
36 #define DEFAULTS "*delay: 25000 \n" \
37 "*cycles: 20000 \n" \
38 "*size: -200 \n" \
39 "*ncolors: 200 \n" \
40
41 # define free_tube 0
42 # define reshape_tube 0
43 # define tube_handle_event 0
44 #define SMOOTH_COLORS
45 #define WRITABLE_COLORS
46 #include "xlockmore.h" /* from the xscreensaver distribution */
47 #else /* !STANDALONE */
48 #include "xlock.h" /* from the xlockmore distribution */
49 #include "color.h"
50 #endif /* !STANDALONE */
51
52 #ifdef MODE_tube
53
54 #define DEF_CYCLE "True"
55
56 static Bool cycle_p;
57
58 static XrmOptionDescRec opts[] =
59 {
60 {(char *) "-cycle", (char *) ".tube.cycle", XrmoptionNoArg, (caddr_t) "on"},
61 {(char *) "+cycle", (char *) ".tube.cycle", XrmoptionNoArg, (caddr_t) "off"}
62 };
63
64 static argtype vars[] =
65 {
66 {(void *) & cycle_p, (char *) "cycle", (char *) "Cycle", (char *) DEF_CYCLE, t_Bool}
67 };
68 static OptionStruct desc[] =
69 {
70 {(char *) "-/+cycle", (char *) "turn on/off colour cycling"}
71 };
72
73 ENTRYPOINT ModeSpecOpt tube_opts =
74 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
75
76 #ifdef USE_MODULES
77 ModStruct tube_description =
78 {"tube", "init_tube", "draw_tube", "release_tube",
79 (char *) NULL, "init_tube", (char *) NULL, &tube_opts,
80 25000, -9, 20000, -200, 64, 1.0, "",
81 "Shows an animated tube", 0, NULL};
82
83 #endif
84
85 #define MINSIZE 3
86 #define MINSHAPE 1
87
88 typedef struct {
89 int dx1, dy1;
90 int x1, y1;
91 int width, height, average, linewidth;
92 int shape;
93 XPoint *pts, *proto_pts;
94 unsigned int cur_color;
95 GC gc;
96 Colormap cmap;
97 unsigned long blackpixel, whitepixel, fg, bg;
98 int direction;
99 XColor *colors;
100 int counter;
101 int ncolors;
102 Bool cycle_p, mono_p, no_colors, reverse;
103 } tubestruct;
104
105 static tubestruct *tubes = (tubestruct *) NULL;
106
107 static void
free_pts(tubestruct * tp)108 free_pts(tubestruct *tp)
109 {
110 if (tp->pts != NULL) {
111 free(tp->pts);
112 tp->pts = (XPoint *) NULL;
113 }
114 if (tp->proto_pts != NULL) {
115 free(tp->proto_pts);
116 tp->proto_pts = (XPoint *) NULL;
117 }
118 }
119
120 static void
free_tube_screen(ModeInfo * mi,tubestruct * tp)121 free_tube_screen(ModeInfo *mi, tubestruct *tp)
122 {
123 Display *display = MI_DISPLAY(mi);
124
125 if (tp == NULL) {
126 return;
127 }
128 free_pts(tp);
129
130 if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
131 MI_WHITE_PIXEL(mi) = tp->whitepixel;
132 MI_BLACK_PIXEL(mi) = tp->blackpixel;
133 #ifndef STANDALONE
134 MI_FG_PIXEL(mi) = tp->fg;
135 MI_BG_PIXEL(mi) = tp->bg;
136 #endif
137 if (tp->colors != NULL) {
138 #ifdef STANDALONE
139 Screen *screen = MI_SCREENPTR(mi);
140 #endif
141 if (tp->ncolors && !tp->no_colors)
142 free_colors(
143 #ifdef STANDALONE
144 screen,
145 #else
146 display,
147 #endif
148 tp->cmap, tp->colors, tp->ncolors);
149 free(tp->colors);
150 tp->colors = (XColor *) NULL;
151 }
152 if (tp->cmap != None) {
153 XFreeColormap(display, tp->cmap);
154 tp->cmap = None;
155 }
156 }
157 if (tp->gc != None) {
158 XFreeGC(display, tp->gc);
159 tp->gc = None;
160 }
161 tp = NULL;
162 }
163
164 #ifndef STANDALONE
165 extern char *background;
166 extern char *foreground;
167 #endif
168
169 ENTRYPOINT void
init_tube(ModeInfo * mi)170 init_tube(ModeInfo * mi)
171 {
172 Display *display = MI_DISPLAY(mi);
173 Window window = MI_WINDOW(mi);
174 int screen_width, screen_height;
175 int size = MI_SIZE(mi);
176 int star = 1, lw;
177 tubestruct *tp;
178
179 MI_INIT(mi, tubes);
180 tp = &tubes[MI_SCREEN(mi)];
181
182 screen_width = MI_WIDTH(mi);
183 screen_height = MI_HEIGHT(mi);
184
185 if (size < -MINSIZE) {
186 tp->width = NRAND(MIN(-size, MAX(MINSIZE, screen_width / 2)) -
187 MINSIZE + 1) + MINSIZE;
188 tp->height = NRAND(MIN(-size, MAX(MINSIZE, screen_height / 2)) -
189 MINSIZE + 1) + MINSIZE;
190 } else if (size < MINSIZE) {
191 if (!size) {
192 tp->width = MAX(MINSIZE, screen_width / 2);
193 tp->height = MAX(MINSIZE, screen_height / 2);
194 } else {
195 tp->width = MINSIZE;
196 tp->height = MINSIZE;
197 }
198 } else {
199 tp->width = MIN(size, MAX(MINSIZE, screen_width / 2));
200 tp->height = MIN(size, MAX(MINSIZE, screen_height / 2));
201 }
202 tp->average = (tp->width + tp->height) / 2;
203 tp->reverse = (Bool) (LRAND() & 1);
204 tp->dx1 = LRAND() & 1;
205 if (tp->dx1 == 0)
206 tp->dx1 = -1;
207 tp->dy1 = LRAND() & 1;
208 if (tp->dy1 == 0)
209 tp->dy1 = -1;
210 free_pts(tp);
211 tp->shape = MI_COUNT(mi);
212 if (tp->shape < -MINSHAPE) {
213 tp->shape = NRAND(-tp->shape - MINSHAPE + 1) + MINSHAPE;
214 } else if (tp->shape < MINSHAPE)
215 tp->shape = MINSHAPE;
216
217 if (tp->shape >= 3) {
218 int i;
219 float start;
220
221 tp->width = tp->height = tp->average;
222 if (((tp->pts = (XPoint *) malloc((tp->shape + 1) *
223 sizeof (XPoint))) == NULL) ||
224 ((tp->proto_pts = (XPoint *) malloc((tp->shape + 1) *
225 sizeof (XPoint))) == NULL)) {
226 free_tube_screen(mi, tp);
227 return;
228 }
229 start = (float) NRAND(360);
230 do {
231 star = NRAND(tp->shape / 2) + 1; /* Not always a star but that's ok. */
232 } while ((star != 1) && (!(tp->shape % star)));
233 for (i = 0; i < tp->shape; i++) {
234 tp->proto_pts[i].x = tp->average / 2 +
235 (int) (cos((double) start * 2.0 * M_PI / 360.0) * tp->average / 2.0);
236 tp->proto_pts[i].y = tp->average / 2 +
237 (int) (sin((double) start * 2.0 * M_PI / 360.0) * tp->average / 2.0);
238 start += star * 360 / tp->shape;
239 }
240 tp->proto_pts[tp->shape] = tp->proto_pts[0];
241 }
242 tp->linewidth = NRAND(tp->average / 6 + 1) + 1;
243 if (star > 1) /* Make the width less */
244 tp->linewidth = NRAND(tp->linewidth / 2 + 1) + 1;
245 lw = tp->linewidth / 2;
246 tp->x1 = NRAND(screen_width - tp->width - 2 * lw) + lw;
247 tp->y1 = NRAND(screen_height - tp->height - 2 * lw) + lw;
248
249 tp->counter = 0;
250
251 if (!tp->gc) {
252 if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
253 XColor color;
254
255 #ifndef STANDALONE
256 tp->fg = MI_FG_PIXEL(mi);
257 tp->bg = MI_BG_PIXEL(mi);
258 #endif
259 tp->blackpixel = MI_BLACK_PIXEL(mi);
260 tp->whitepixel = MI_WHITE_PIXEL(mi);
261 if ((tp->cmap = XCreateColormap(display, window,
262 MI_VISUAL(mi), AllocNone)) == None) {
263 free_tube_screen(mi, tp);
264 return;
265 }
266 XSetWindowColormap(display, window, tp->cmap);
267 (void) XParseColor(display, tp->cmap, "black", &color);
268 (void) XAllocColor(display, tp->cmap, &color);
269 MI_BLACK_PIXEL(mi) = color.pixel;
270 (void) XParseColor(display, tp->cmap, "white", &color);
271 (void) XAllocColor(display, tp->cmap, &color);
272 MI_WHITE_PIXEL(mi) = color.pixel;
273 #ifndef STANDALONE
274 (void) XParseColor(display, tp->cmap, background, &color);
275 (void) XAllocColor(display, tp->cmap, &color);
276 MI_BG_PIXEL(mi) = color.pixel;
277 (void) XParseColor(display, tp->cmap, foreground, &color);
278 (void) XAllocColor(display, tp->cmap, &color);
279 MI_FG_PIXEL(mi) = color.pixel;
280 #endif
281 tp->colors = (XColor *) NULL;
282 tp->ncolors = 0;
283 }
284 if ((tp->gc = XCreateGC(display, MI_WINDOW(mi),
285 (unsigned long) 0, (XGCValues *) NULL)) == None) {
286 free_tube_screen(mi, tp);
287 return;
288 }
289 }
290 MI_CLEARWINDOW(mi);
291
292 /* Set up colour map */
293 tp->direction = (LRAND() & 1) ? 1 : -1;
294 if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
295 #ifdef STANDALONE
296 Screen *screen = MI_SCREENPTR(mi);
297 #endif
298 if (tp->colors != NULL) {
299 if (tp->ncolors && !tp->no_colors)
300 free_colors(
301 #ifdef STANDALONE
302 screen,
303 #else
304 display,
305 #endif
306 tp->cmap, tp->colors, tp->ncolors);
307 free(tp->colors);
308 tp->colors = (XColor *) NULL;
309 }
310 tp->ncolors = MI_NCOLORS(mi);
311 if (tp->ncolors < 2)
312 tp->ncolors = 2;
313 if (tp->ncolors <= 2)
314 tp->mono_p = True;
315 else
316 tp->mono_p = False;
317
318 if (tp->mono_p)
319 tp->colors = (XColor *) NULL;
320 else
321 if ((tp->colors = (XColor *) malloc(sizeof (*tp->colors) *
322 (tp->ncolors + 1))) == NULL) {
323 free_tube_screen(mi, tp);
324 return;
325 }
326 tp->cycle_p = has_writable_cells(
327 #ifdef STANDALONE
328 screen, MI_VISUAL(mi)
329 #else
330 mi
331 #endif
332 );
333 if (tp->cycle_p) {
334 if (MI_IS_FULLRANDOM(mi)) {
335 if (!NRAND(8))
336 tp->cycle_p = False;
337 else
338 tp->cycle_p = True;
339 } else {
340 tp->cycle_p = cycle_p;
341 }
342 }
343 if (!tp->mono_p) {
344 if (!(LRAND() % 10))
345 make_random_colormap(
346 #ifdef STANDALONE
347 screen, MI_VISUAL(mi),
348 tp->cmap, tp->colors, &tp->ncolors,
349 True, True, &tp->cycle_p, True
350 #else
351 mi,
352 tp->cmap, tp->colors, &tp->ncolors,
353 True, True, &tp->cycle_p
354 #endif
355 );
356 else if (!(LRAND() % 2))
357 make_uniform_colormap(
358 #ifdef STANDALONE
359 screen, MI_VISUAL(mi),
360 tp->cmap, tp->colors, &tp->ncolors,
361 True, &tp->cycle_p, True
362 #else
363 mi,
364 tp->cmap, tp->colors, &tp->ncolors,
365 True, &tp->cycle_p
366 #endif
367 );
368 else
369 make_smooth_colormap(
370 #ifdef STANDALONE
371 screen, MI_VISUAL(mi),
372 tp->cmap, tp->colors, &tp->ncolors,
373 True, &tp->cycle_p, True
374 #else
375 mi,
376 tp->cmap, tp->colors, &tp->ncolors,
377 True, &tp->cycle_p
378 #endif
379 );
380 }
381 XInstallColormap(display, tp->cmap);
382 if (tp->ncolors < 2) {
383 tp->ncolors = 2;
384 tp->no_colors = True;
385 } else
386 tp->no_colors = False;
387 if (tp->ncolors <= 2)
388 tp->mono_p = True;
389
390 if (tp->mono_p)
391 tp->cycle_p = False;
392
393 }
394 if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
395 if (tp->mono_p) {
396 tp->cur_color = MI_BLACK_PIXEL(mi);
397 }
398 }
399 }
400
401 ENTRYPOINT void
draw_tube(ModeInfo * mi)402 draw_tube(ModeInfo * mi)
403 {
404 Display *display = MI_DISPLAY(mi);
405 Window window = MI_WINDOW(mi);
406 unsigned int i;
407 int lw;
408 tubestruct *tp;
409
410 if (tubes == NULL)
411 return;
412 tp = &tubes[MI_SCREEN(mi)];
413
414 if (tp->no_colors) {
415 init_tube(mi);
416 return;
417 }
418 if (tp->shape >= 3 && tp->pts == NULL)
419 return;
420
421 MI_IS_DRAWN(mi) = True;
422 lw = tp->linewidth / 2;
423
424 if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
425 if (tp->mono_p) {
426 XSetForeground(display, tp->gc, tp->cur_color);
427 } else {
428 tp->cur_color = (tp->cur_color + 1) % tp->ncolors;
429 XSetForeground(display, tp->gc, tp->colors[tp->cur_color].pixel);
430 }
431 } else {
432 if (MI_NPIXELS(mi) > 2)
433 XSetForeground(display, tp->gc, MI_PIXEL(mi, tp->cur_color));
434 else if (tp->cur_color)
435 XSetForeground(display, tp->gc, MI_BLACK_PIXEL(mi));
436 else
437 XSetForeground(display, tp->gc, MI_WHITE_PIXEL(mi));
438 if (++tp->cur_color >= (unsigned int) MI_NPIXELS(mi))
439 tp->cur_color = 0;
440 }
441
442 /* Rotate colours */
443 if (tp->cycle_p) {
444 rotate_colors(
445 #ifdef STANDALONE
446 MI_SCREENPTR(mi),
447 #else
448 display,
449 #endif
450 tp->cmap, tp->colors, tp->ncolors, tp->direction);
451 if (!(LRAND() % 1000))
452 tp->direction = -tp->direction;
453 }
454
455 /* move rectangle forward, horiz */
456 tp->x1 += tp->dx1;
457 if (tp->x1 < lw) {
458 tp->x1 = lw;
459 tp->dx1 = -tp->dx1;
460 }
461 if (tp->x1 + tp->width + lw >= MI_WIDTH(mi)) {
462 tp->x1 = MI_WIDTH(mi) - tp->width - 1 - lw;
463 tp->dx1 = -tp->dx1;
464 }
465 /* move rectangle forward, vert */
466 tp->y1 += tp->dy1;
467 if (tp->y1 < lw) {
468 tp->y1 = lw;
469 tp->dy1 = -tp->dy1;
470 }
471 if (tp->y1 + tp->height + lw >= MI_HEIGHT(mi)) {
472 tp->y1 = MI_HEIGHT(mi) - tp->height - 1 - lw;
473 tp->dy1 = -tp->dy1;
474 }
475 XSetLineAttributes(display, tp->gc, tp->linewidth + (tp->shape >= 2),
476 LineSolid, CapNotLast, JoinRound);
477 if (tp->shape < 2)
478 XDrawRectangle(display, window, tp->gc,
479 tp->x1, tp->y1, tp->width, tp->height);
480 else if (tp->shape == 2)
481 XDrawArc(display, window, tp->gc,
482 tp->x1, tp->y1, tp->width, tp->height, 0, 23040);
483 else {
484 for (i = 0; i <= (unsigned int) tp->shape; i++) {
485 tp->pts[i].x = tp->x1 + tp->proto_pts[i].x;
486 tp->pts[i].y = tp->y1 + tp->proto_pts[i].y;
487 }
488 XDrawLines(display, window, tp->gc, tp->pts, tp->shape + 1,
489 CoordModeOrigin);
490 }
491 XSetLineAttributes(display, tp->gc, 1, LineSolid, CapNotLast, JoinRound);
492
493 tp->counter++;
494 if (tp->counter > MI_CYCLES(mi)) {
495 init_tube(mi);
496 }
497 }
498
499 ENTRYPOINT void
release_tube(ModeInfo * mi)500 release_tube(ModeInfo * mi)
501 {
502 if (tubes != NULL) {
503 int screen;
504
505 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
506 free_tube_screen(mi, &tubes[screen]);
507 free(tubes);
508 tubes = (tubestruct *) NULL;
509 }
510 }
511
512 XSCREENSAVER_MODULE ("Tube", tube)
513
514 #endif /* MODE_tube */
515