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