1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* decay --- decayscreen */
3 
4 #if 0
5 static const char sccsid[] = "@(#)decay.c	5.00 2000/11/01 xlockmore";
6 
7 #endif
8 
9 /* xscreensaver, Copyright (c) 1992, 1993, 1994, 1996, 1997
10  * Jamie Zawinski <jwz AT jwz.org>
11  *
12  * Permission to use, copy, modify, distribute, and sell this software and its
13  * documentation for any purpose is hereby granted without fee, provided that
14  * the above copyright notice appear in all copies and that both that
15  * copyright notice and this permission notice appear in supporting
16  * documentation.  No representations are made about the suitability of this
17  * software for any purpose.  It is provided "as is" without express or
18  * implied warranty.
19  */
20 
21 /*
22  * Revision History:
23  * 01-Nov-2000: Allocation checks
24  * 17-Mar-1999: Converted from xscreensaver's decayscreen
25  *
26  * decayscreen
27  *
28  * Based on slidescreen program from the xscreensaver application and the
29  * decay program for Sun framebuffers.  This is the comment from the decay.c
30  * file:
31 
32  * decay.c
33  *   find the screen bitmap for the console and make it "decay" by
34  *   randomly shifting random rectangles by one pixelwidth at a time.
35  *
36  *   by David Wald, 1988
37  *        rewritten by Natuerlich!
38  *   based on a similar "utility" on the Apollo ring at Yale.
39 
40  * X version by
41  *
42  *  Vivek Khera <khera@cs.duke.edu>
43  *  5-AUG-1993
44  *
45  *  Hacked by jwz, 28-Nov-97 (sped up and added new motion directions)
46  */
47 
48 #ifdef STANDALONE
49 # define MODE_decay
50 # define DEFAULTS "*delay: 200000 \n" \
51  "*count: 6 \n" \
52  "*cycles: 30 \n" \
53  "*ncolors: 64 \n"
54 
55 # define free_decay 0
56 # define reshape_decay 0
57 # define decay_handle_event 0
58 # define UNIFORM_COLORS
59 # include "xlockmore.h"    /* in xscreensaver distribution */
60 static XImage blogo =
61 {
62 	0, 0,			/* width, height */
63 	0, XYBitmap, 0,		/* xoffset, format, data */
64 	LSBFirst, 8,		/* byte-order, bitmap-unit */
65 	LSBFirst, 8, 1		/* bitmap-bit-order, bitmap-pad, depth */
66 };
67 #else /* STANDALONE */
68 # include "xlock.h"    /* in xlockmore distribution */
69 # include "color.h"
70 # include "iostuff.h"
71 #endif /* STANDALONE */
72 
73 #ifdef MODE_decay
74 
75 #ifndef STANDALONE
76 extern Bool hide;
77 #endif
78 
79 ENTRYPOINT ModeSpecOpt decay_opts =
80 {0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
81 
82 #ifdef USE_MODULES
83 ModStruct   decay_description =
84 {"decay", "init_decay", "draw_decay", "release_decay",
85  "refresh_decay", "init_decay", (char *) NULL, &decay_opts,
86  200000, 6, 30, 1, 64, 0.3, "",
87  "Shows a decaying screen", 0, NULL};
88 
89 #endif
90 
91 #ifdef STANDALONE
92 #define DECAY_WIDTH	xscreensaver_width
93 #define DECAY_HEIGHT	xscreensaver_height
94 #define DECAY_BITS	xscreensaver_bits
95 #include "bitmaps/xscreensaver.xbm"
96 #else
97 #define DECAY_WIDTH	image_width
98 #define DECAY_HEIGHT	image_height
99 #define DECAY_BITS	image_bits
100 #include "decay.xbm"
101 #endif
102 
103 #ifdef HAVE_XPM
104 #include <X11/xpm.h>
105 #ifdef STANDALONE
106 #define DECAY_NAME	xscreensaver
107 #include "pixmaps/xscreensaver.xpm"
108 #else
109 #define DECAY_NAME	image_name
110 #include "decay.xpm"
111 #endif
112 #define DEFAULT_XPM 1
113 #endif
114 
115 typedef struct
116 {
117 	XPoint   windowsize;
118 	int      mode;
119 
120 	XPoint   randompos, randpos;
121 	XImage  *logo;
122 	GC       backGC;
123 	Colormap cmap;
124 	int      graphics_format;
125 	unsigned long black;
126 	Bool     hide;
127 } decaystruct;
128 
129 static decaystruct *decay_info = (decaystruct *) NULL;
130 
131 #define SHUFFLE 0
132 #define UP 1
133 #define LEFT 2
134 #define RIGHT 3
135 #define DOWN 4
136 #define UPLEFT 5
137 #define DOWNLEFT 6
138 #define UPRIGHT 7
139 #define DOWNRIGHT 8
140 #define INSIDE 9
141 #define OUTSIDE 10
142 #define	DEGREE	1
143 
144 static void
free_decay_screen(Display * display,decaystruct * dp)145 free_decay_screen(Display * display, decaystruct * dp)
146 {
147 	if (dp == NULL) {
148 		return;
149 	}
150 	if (dp->cmap != None) {
151 		XFreeColormap(display, dp->cmap);
152 		if (dp->backGC != None) {
153 			XFreeGC(display, dp->backGC);
154 			dp->backGC = None;
155 		}
156 		dp->cmap = None;
157 	} else
158 		dp->backGC = None;
159 #ifndef STANDALONE
160 	if (dp->hide && (dp->logo != None)) {
161 		destroyImage(&dp->logo, &dp->graphics_format);
162 		dp->logo = None;
163 	}
164 #endif
165 	dp = NULL;
166 }
167 
168 static void
alloc_decay(ModeInfo * mi)169 alloc_decay(ModeInfo * mi)
170 {
171 	decaystruct *dp = &decay_info[MI_SCREEN(mi)];
172 #ifdef STANDALONE
173 #ifdef HAVE_XPM
174 	XpmAttributes attrib;
175 	attrib.visual = MI_VISUAL(mi);
176 	attrib.colormap = MI_COLORMAP(mi);
177 	attrib.depth = MI_DEPTH(mi);
178 	attrib.valuemask = XpmVisual | XpmColormap | XpmDepth;
179 	if (MI_NPIXELS(mi) > 2 &&
180 			(XpmSuccess == XpmCreateImageFromData(MI_DISPLAY(mi),
181 			DECAY_NAME, &(dp->logo), (XImage **) NULL, &attrib))) {
182 		dp->graphics_format = IS_XPM;
183 	} else
184 #endif
185 	{
186 		int default_width = DECAY_WIDTH;
187 		int default_height = DECAY_HEIGHT;
188 		unsigned char * default_bits = DECAY_BITS;
189 		if (!blogo.data) {
190 			blogo.data = (char *) default_bits;
191 			blogo.width = default_width;
192 			blogo.height = default_height;
193 			blogo.bytes_per_line = (blogo.width + 7) / 8;
194 		}
195 		dp->logo = &blogo;
196 		dp->graphics_format = IS_XBM;
197 	}
198 	dp->hide = True;
199 #else
200 	Display    *display = MI_DISPLAY(mi);
201 	Window      window = MI_WINDOW(mi);
202 
203 	if (dp->hide) {
204 		if (dp->logo == None) {
205 			getImage(mi, &dp->logo, DECAY_WIDTH, DECAY_HEIGHT, DECAY_BITS,
206 #ifdef HAVE_XPM
207 				DEFAULT_XPM, DECAY_NAME,
208 #endif
209 				&dp->graphics_format, &dp->cmap, &dp->black);
210 			if (dp->logo == None) {
211 				free_decay_screen(display, dp);
212 				return;
213 			}
214 		}
215 		if (dp->cmap != None) {
216 			setColormap(display, window, dp->cmap, MI_IS_INWINDOW(mi));
217 			if (dp->backGC == None) {
218 				XGCValues   xgcv;
219 
220 				xgcv.background = dp->black;
221 				dp->backGC = XCreateGC(display, window, GCBackground, &xgcv);
222 				if (dp->backGC == None) {
223 					free_decay_screen(display, dp);
224 					return;
225 				}
226 			}
227 		} else
228 #endif /* STANDALONE */
229 		{
230 			dp->black = MI_BLACK_PIXEL(mi);
231 			dp->backGC = MI_GC(mi);
232 		}
233 #ifndef STANDALONE
234 	} else {
235 		setColormap(display, window, DefaultColormapOfScreen(MI_SCREENPTR(mi)), MI_IS_INWINDOW(mi));
236 		dp->backGC = MI_GC(mi);
237 	}
238 #endif /* STANDALONE */
239 }
240 
241 ENTRYPOINT void
init_decay(ModeInfo * mi)242 init_decay(ModeInfo * mi)
243 {
244 	Display *display = MI_DISPLAY(mi);
245 	Window window = MI_WINDOW(mi);
246 	decaystruct *dp;
247 
248 	char *s = (char*) "random";
249 
250 	MI_INIT(mi, decay_info);
251 	dp = &decay_info[MI_SCREEN(mi)];
252 
253 	if      (s && !strcmp(s, "shuffle")) dp->mode = SHUFFLE;
254 	else if (s && !strcmp(s, "up")) dp->mode = UP;
255 	else if (s && !strcmp(s, "left")) dp->mode = LEFT;
256 	else if (s && !strcmp(s, "right")) dp->mode = RIGHT;
257 	else if (s && !strcmp(s, "down")) dp->mode = DOWN;
258 	else if (s && !strcmp(s, "upleft")) dp->mode = UPLEFT;
259 	else if (s && !strcmp(s, "downleft")) dp->mode = DOWNLEFT;
260 	else if (s && !strcmp(s, "upright")) dp->mode = UPRIGHT;
261 	else if (s && !strcmp(s, "downright")) dp->mode = DOWNRIGHT;
262 	else if (s && !strcmp(s, "in")) dp->mode = INSIDE;
263 	else if (s && !strcmp(s, "out")) dp->mode = OUTSIDE;
264 #ifndef STANDALONE
265 	else {
266 		if (s && *s && !!strcmp(s, "random"))
267 			(void) fprintf(stderr, "%s: unknown mode %s\n", ProgramName, s);
268 		dp->mode = (int) (LRAND() % (OUTSIDE+1));
269 	}
270 
271 	if (MI_IS_FULLRANDOM(mi) && !hide)
272 		dp->hide = (Bool) (LRAND() & 1);
273 	else
274 		dp->hide = hide;
275 #endif
276 
277 	dp->windowsize.x = MI_WIDTH(mi);
278 	dp->windowsize.y = MI_HEIGHT(mi);
279 	alloc_decay(mi);
280 	if (!dp->backGC)
281 		return;
282 	if (dp->hide) {
283   		/* do not want any exposure events from XCopyArea */
284   		XSetGraphicsExposures(display, dp->backGC, False);
285 		MI_CLEARWINDOWCOLORMAP(mi, dp->backGC, dp->black);
286 		dp->randompos.x =
287 			NRAND(MAX((dp->windowsize.x - dp->logo->width), 1));
288                 dp->randompos.y =
289 			NRAND(MAX((dp->windowsize.y - dp->logo->height), 1));
290 		if (MI_NPIXELS(mi) <= 2)
291 			XSetForeground(display, dp->backGC, MI_WHITE_PIXEL(mi));
292 		else
293 			XSetForeground(display, dp->backGC, MI_PIXEL(mi, NRAND(MI_NPIXELS(mi))));
294 		(void) XPutImage(display, window, dp->backGC, dp->logo,
295 			(int) (NRAND(MAX(1, (dp->logo->width - dp->windowsize.x)))),
296 			(int) (NRAND(MAX(1, (dp->logo->height - dp->windowsize.y)))),
297                                  dp->randompos.x, dp->randompos.y,
298                                  dp->windowsize.x, dp->windowsize.y);
299 	}
300 #ifndef STANDALONE
301 	else {
302 		XCopyArea (MI_DISPLAY(mi), MI_ROOT_PIXMAP(mi), MI_WINDOW(mi),
303 		       dp->backGC, 0, 0, MI_WIDTH(mi), MI_HEIGHT(mi),
304 		       0, 0);
305 		XFlush(MI_DISPLAY(mi));
306 	}
307 #endif
308 }
309 
310 /*
311  * perform one iteration of decay
312  */
313 ENTRYPOINT void
draw_decay(ModeInfo * mi)314 draw_decay (ModeInfo * mi)
315 {
316     int left, top, width, height, toleft, totop;
317 
318 #define L 101
319 #define R 102
320 #define U 103
321 #define D 104
322     static int no_bias[]        = { L,L,L,L, R,R,R,R, U,U,U,U, D,D,D,D };
323     static int up_bias[]        = { L,L,L,L, R,R,R,R, U,U,U,U, U,U,D,D };
324     static int down_bias[]      = { L,L,L,L, R,R,R,R, U,U,D,D, D,D,D,D };
325     static int left_bias[]      = { L,L,L,L, L,L,R,R, U,U,U,U, D,D,D,D };
326     static int right_bias[]     = { L,L,R,R, R,R,R,R, U,U,U,U, D,D,D,D };
327 
328     static int upleft_bias[]    = { L,L,L,L, L,R,R,R, U,U,U,U, U,D,D,D };
329     static int downleft_bias[]  = { L,L,L,L, L,R,R,R, U,U,U,D, D,D,D,D };
330     static int upright_bias[]   = { L,L,L,R, R,R,R,R, U,U,U,U, U,D,D,D };
331     static int downright_bias[] = { L,L,L,R, R,R,R,R, U,U,U,D, D,D,D,D };
332     int *bias, side;
333     decaystruct * dp;
334 
335 	if (decay_info == NULL)
336 		return;
337 	dp = &decay_info[MI_SCREEN(mi)];
338 	if (dp->backGC == None)
339 		return;
340 
341 	MI_IS_DRAWN(mi) = True;
342 
343     switch (dp->mode) {
344       case SHUFFLE:	bias = no_bias; break;
345       case UP:		bias = up_bias; break;
346       case LEFT:	bias = left_bias; break;
347       case RIGHT:	bias = right_bias; break;
348       case DOWN:	bias = down_bias; break;
349       case UPLEFT:	bias = upleft_bias; break;
350       case DOWNLEFT:	bias = downleft_bias; break;
351       case UPRIGHT:	bias = upright_bias; break;
352       case DOWNRIGHT:	bias = downright_bias; break;
353       case INSIDE:	bias = no_bias; break;
354       case OUTSIDE:	bias = no_bias; break;
355       default: bias = no_bias;
356 	 if (MI_IS_VERBOSE(mi)) {
357              (void) fprintf(stderr, "Weirdness in draw_decay()\n");
358              (void) fprintf(stderr, "dp->mode = %d\n", dp->mode);
359          }
360     }
361 
362     left = NRAND(dp->windowsize.x);
363     top = NRAND(dp->windowsize.y);
364     width = NRAND(dp->windowsize.x - left);
365     height = NRAND(dp->windowsize.y - top);
366 
367     toleft = left;
368     totop = top;
369 
370     if (dp->mode == INSIDE || dp->mode == OUTSIDE) {
371       int x = left+(width/2);
372       int y = top+(height/2);
373       int cx = dp->windowsize.x/2;
374       int cy = dp->windowsize.y/2;
375       if (dp->mode == INSIDE) {
376 	if      (x > cx && y > cy)   bias = upleft_bias;
377 	else if (x < cx && y > cy)   bias = upright_bias;
378 	else if (x < cx && y < cy)   bias = downright_bias;
379 	else /* (x > cx && y < cy)*/ bias = downleft_bias;
380       } else {
381 	if      (x > cx && y > cy)   bias = downright_bias;
382 	else if (x < cx && y > cy)   bias = downleft_bias;
383 	else if (x < cx && y < cy)   bias = upleft_bias;
384 	else /* (x > cx && y < cy)*/ bias = upright_bias;
385       }
386     }
387 
388     side = bias[LRAND() % (sizeof(no_bias)/sizeof(*no_bias))];
389     switch (side) {
390       case L: toleft = left-DEGREE; break;
391       case R: toleft = left+DEGREE; break;
392       case U: totop = top-DEGREE; break;
393       case D: totop = top+DEGREE; break;
394       default:
395 	 if (MI_IS_VERBOSE(mi)) {
396              (void) fprintf(stderr, "Weirdness in draw_decay()\n");
397              (void) fprintf(stderr, "side = %d\n", side);
398          }
399     }
400 
401     XCopyArea (MI_DISPLAY(mi), MI_WINDOW(mi), MI_WINDOW(mi),
402 	       dp->backGC, left, top, width, height,
403 	       toleft, totop);
404     XFlush(MI_DISPLAY(mi));
405 
406 }
407 
408 ENTRYPOINT void
release_decay(ModeInfo * mi)409 release_decay(ModeInfo * mi)
410 {
411 	if (decay_info != NULL) {
412 		int	screen;
413 
414 		for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
415 			free_decay_screen(MI_DISPLAY(mi), &decay_info[screen]);
416 		free(decay_info);
417 		decay_info = (decaystruct *) NULL;
418 	}
419 }
420 
421 #ifndef STANDALONE
422 ENTRYPOINT void
refresh_decay(ModeInfo * mi)423 refresh_decay(ModeInfo * mi)
424 {
425 #ifdef HAVE_XPM
426 	decaystruct *dp;
427 
428 	if (decay_info == NULL)
429 		return;
430 	dp = &decay_info[MI_SCREEN(mi)];
431 
432 	if (dp->graphics_format >= IS_XPM) {
433 		/* This is needed when another program changes the colormap. */
434 		free_decay_screen(MI_DISPLAY(mi), dp);
435 		init_decay(mi);
436 		return;
437 	}
438 #endif
439 }
440 #endif
441 
442 XSCREENSAVER_MODULE ("Decay", decay)
443 
444 #endif /* MODE_decay */
445