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