1 /* xscreensaver, Copyright (c) 1992-2018 Jamie Zawinski <jwz@jwz.org>
3 * Permission to use, copy, modify, distribute, and sell this software and its
4 * documentation for any purpose is hereby granted without fee, provided that
5 * the above copyright notice appear in all copies and that both that
6 * copyright notice and this permission notice appear in supporting
7 * documentation. No representations are made about the suitability of this
8 * software for any purpose. It is provided "as is" without express or
14 * Based on slidescreen program from the xscreensaver application and the
15 * decay program for Sun framebuffers. This is the comment from the decay.c
19 * find the screen bitmap for the console and make it "decay" by
20 * randomly shifting random rectangles by one pixelwidth at a time.
23 * rewritten by Natuerlich!
24 * based on a similar "utility" on the Apollo ring at Yale.
28 * Vivek Khera <khera@cs.duke.edu>
31 * Hacked by jwz, 28-Nov-97 (sped up and added new motion directions)
34 * Added "melt" & "stretch" modes 28-Mar-1999
38 #include "screenhack.h"
44 XWindowAttributes xgwa;
57 const int *current_bias;
59 async_load_state *img_loader;
79 decayscreen_load_image (struct state *st)
81 XWindowAttributes xgwa;
82 XGetWindowAttributes (st->dpy, st->window, &xgwa);
83 st->sizex = xgwa.width;
84 st->sizey = xgwa.height;
85 if (st->img_loader) abort();
87 st->img_loader = load_image_async_simple (0, xgwa.screen, st->window,
92 decayscreen_init (Display *dpy, Window window)
94 struct state *st = (struct state *) calloc (1, sizeof(*st));
104 s = get_string_resource(st->dpy, "mode", "Mode");
105 if (s && !strcmp(s, "shuffle")) st->mode = SHUFFLE;
106 else if (s && !strcmp(s, "up")) st->mode = UP;
107 else if (s && !strcmp(s, "left")) st->mode = LEFT;
108 else if (s && !strcmp(s, "right")) st->mode = RIGHT;
109 else if (s && !strcmp(s, "down")) st->mode = DOWN;
110 else if (s && !strcmp(s, "upleft")) st->mode = UPLEFT;
111 else if (s && !strcmp(s, "downleft")) st->mode = DOWNLEFT;
112 else if (s && !strcmp(s, "upright")) st->mode = UPRIGHT;
113 else if (s && !strcmp(s, "downright")) st->mode = DOWNRIGHT;
114 else if (s && !strcmp(s, "in")) st->mode = IN;
115 else if (s && !strcmp(s, "out")) st->mode = OUT;
116 else if (s && !strcmp(s, "melt")) st->mode = MELT;
117 else if (s && !strcmp(s, "stretch")) st->mode = STRETCH;
118 else if (s && !strcmp(s, "fuzz")) st->mode = FUZZ;
120 if (s && *s && !!strcmp(s, "random"))
121 fprintf(stderr, "%s: unknown mode %s\n", progname, s);
123 st->mode = random() % (FUZZ+1);
126 st->delay = get_integer_resource (st->dpy, "delay", "Integer");
127 if (st->delay < 0) st->delay = 0;
129 st->duration = get_integer_resource (st->dpy, "duration", "Seconds");
130 if (st->duration < 1) st->duration = 1;
132 XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
134 gcv.function = GXcopy;
135 gcv.subwindow_mode = IncludeInferiors;
136 bg = get_pixel_resource (st->dpy, st->xgwa.colormap, "background", "Background");
139 gcflags = GCForeground | GCFunction;
140 if (use_subwindow_mode_p(st->xgwa.screen, st->window)) /* see grabscreen.c */
141 gcflags |= GCSubwindowMode;
142 st->gc = XCreateGC (st->dpy, st->window, gcflags, &gcv);
144 st->start_time = time ((time_t *) 0);
145 decayscreen_load_image (st);
152 * perform one iteration of decay
155 decayscreen_draw (Display *dpy, Window window, void *closure)
157 struct state *st = (struct state *) closure;
158 int left, top, width, height, toleft, totop;
164 static const int no_bias[] = { L,L,L,L, R,R,R,R, U,U,U,U, D,D,D,D };
165 static const int up_bias[] = { L,L,L,L, R,R,R,R, U,U,U,U, U,U,D,D };
166 static const int down_bias[] = { L,L,L,L, R,R,R,R, U,U,D,D, D,D,D,D };
167 static const int left_bias[] = { L,L,L,L, L,L,R,R, U,U,U,U, D,D,D,D };
168 static const int right_bias[] = { L,L,R,R, R,R,R,R, U,U,U,U, D,D,D,D };
170 static const int upleft_bias[] = { L,L,L,L, L,R,R,R, U,U,U,U, U,D,D,D };
171 static const int downleft_bias[] = { L,L,L,L, L,R,R,R, U,U,U,D, D,D,D,D };
172 static const int upright_bias[] = { L,L,L,R, R,R,R,R, U,U,U,U, U,D,D,D };
173 static const int downright_bias[] = { L,L,L,R, R,R,R,R, U,U,U,D, D,D,D,D };
176 if (st->sizex > 2560) off *= 2; /* Retina displays */
178 if (st->img_loader) /* still loading */
180 st->img_loader = load_image_async_simple (st->img_loader,
182 if (! st->img_loader) { /* just finished */
184 st->start_time = time ((time_t *) 0);
186 st->mode = random() % (FUZZ+1);
188 if (st->mode == MELT || st->mode == STRETCH)
189 /* make sure screen eventually turns background color */
190 XDrawLine (st->dpy, st->window, st->gc, 0, 0, st->sizex, 0);
193 st->saved = XCreatePixmap (st->dpy, st->window,
194 st->sizex, st->sizey,
196 st->saved_w = st->sizex;
197 st->saved_h = st->sizey;
199 XCopyArea (st->dpy, st->window, st->saved, st->gc, 0, 0,
200 st->sizex, st->sizey, 0, 0);
205 if (!st->img_loader &&
206 st->start_time + st->duration < time ((time_t *) 0)) {
207 decayscreen_load_image (st);
211 case SHUFFLE: st->current_bias = no_bias; break;
212 case UP: st->current_bias = up_bias; break;
213 case LEFT: st->current_bias = left_bias; break;
214 case RIGHT: st->current_bias = right_bias; break;
215 case DOWN: st->current_bias = down_bias; break;
216 case UPLEFT: st->current_bias = upleft_bias; break;
217 case DOWNLEFT: st->current_bias = downleft_bias; break;
218 case UPRIGHT: st->current_bias = upright_bias; break;
219 case DOWNRIGHT: st->current_bias = downright_bias; break;
220 case IN: st->current_bias = no_bias; break;
221 case OUT: st->current_bias = no_bias; break;
222 case MELT: st->current_bias = no_bias; break;
223 case STRETCH: st->current_bias = no_bias; break;
224 case FUZZ: st->current_bias = no_bias; break;
228 #define nrnd(x) ((x) ? random() % (x) : x)
230 if (st->mode == MELT || st->mode == STRETCH) {
231 left = nrnd(st->sizex/2);
232 top = nrnd(st->sizey);
233 width = nrnd( st->sizex/2 ) + st->sizex/2 - left;
234 height = nrnd(st->sizey - top);
238 } else if (st->mode == FUZZ) { /* By Vince Levey <vincel@vincel.org>;
239 inspired by the "melt" mode of the
240 "scrhack" IrisGL program by Paul Haeberli
242 left = nrnd(st->sizex - 1);
243 top = nrnd(st->sizey - 1);
244 st->fuzz_toggle = !st->fuzz_toggle;
249 toleft = nrnd(st->sizex - 1);
267 totop = nrnd(st->sizey - 1);
284 left = nrnd(st->sizex - 1);
285 top = nrnd(st->sizey);
286 width = nrnd(st->sizex - left);
287 height = nrnd(st->sizey - top);
291 if (st->mode == IN || st->mode == OUT) {
292 int x = left+(width/2);
293 int y = top+(height/2);
294 int cx = st->sizex/2;
295 int cy = st->sizey/2;
296 if (st->mode == IN) {
297 if (x > cx && y > cy) st->current_bias = upleft_bias;
298 else if (x < cx && y > cy) st->current_bias = upright_bias;
299 else if (x < cx && y < cy) st->current_bias = downright_bias;
300 else /* (x > cx && y < cy)*/ st->current_bias = downleft_bias;
302 if (x > cx && y > cy) st->current_bias = downright_bias;
303 else if (x < cx && y > cy) st->current_bias = downleft_bias;
304 else if (x < cx && y < cy) st->current_bias = upleft_bias;
305 else /* (x > cx && y < cy)*/ st->current_bias = upright_bias;
309 switch (st->current_bias[random() % (sizeof(no_bias)/sizeof(*no_bias))]) {
310 case L: toleft = left-off; break;
311 case R: toleft = left+off; break;
312 case U: totop = top-off; break;
313 case D: totop = top+off; break;
314 default: abort(); break;
318 if (st->mode == STRETCH) {
319 XCopyArea (st->dpy, st->window, st->window, st->gc,
320 0, st->sizey-top-off*2, st->sizex, top+off,
321 0, st->sizey-top-off);
323 XCopyArea (st->dpy, st->window, st->window, st->gc,
324 left, top, width, height,
334 decayscreen_reshape (Display *dpy, Window window, void *closure,
335 unsigned int w, unsigned int h)
337 struct state *st = (struct state *) closure;
338 if (! st->saved) return; /* Image might not be loaded yet */
339 XClearWindow (st->dpy, st->window);
340 XCopyArea (st->dpy, st->saved, st->window, st->gc,
341 0, 0, st->saved_w, st->saved_h,
342 ((int)w - st->saved_w) / 2,
343 ((int)h - st->saved_h) / 2);
349 decayscreen_event (Display *dpy, Window window, void *closure, XEvent *event)
351 struct state *st = (struct state *) closure;
352 if (screenhack_event_helper (dpy, window, event))
361 decayscreen_free (Display *dpy, Window window, void *closure)
363 struct state *st = (struct state *) closure;
369 static const char *decayscreen_defaults [] = {
370 ".background: Black",
371 ".foreground: Yellow",
372 "*dontClearRoot: True",
375 #ifdef __sgi /* really, HAVE_READ_DISPLAY_EXTENSION */
383 "*ignoreRotation: True",
384 "*rotateImages: True",
389 static XrmOptionDescRec decayscreen_options [] = {
390 { "-delay", ".delay", XrmoptionSepArg, 0 },
391 { "-mode", ".mode", XrmoptionSepArg, 0 },
392 { "-duration", ".duration", XrmoptionSepArg, 0 },
397 XSCREENSAVER_MODULE ("DecayScreen", decayscreen)