http://www.jwz.org/xscreensaver/xscreensaver-5.10.tar.gz
[xscreensaver] / hacks / decayscreen.c
1 /* xscreensaver, Copyright (c) 1992-2008 Jamie Zawinski <jwz@jwz.org>
2  *
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 
9  * implied warranty.
10  */
11
12 /* decayscreen
13  *
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
16  * file:
17
18  * 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.
21  *
22  *   by David Wald, 1988
23  *        rewritten by Natuerlich!
24  *   based on a similar "utility" on the Apollo ring at Yale.
25
26  * X version by
27  *
28  *  Vivek Khera <khera@cs.duke.edu>
29  *  5-AUG-1993
30  *
31  *  Hacked by jwz, 28-Nov-97 (sped up and added new motion directions)
32  
33  *  R. Schultz
34  *  Added "melt" & "stretch" modes 28-Mar-1999
35  *
36  */
37
38 #include "screenhack.h"
39
40 struct state {
41   Display *dpy;
42   Window window;
43
44   int sizex, sizey;
45   int delay;
46   int duration;
47   GC gc;
48   int mode;
49   int random_p;
50   time_t start_time;
51
52   int fuzz_toggle;
53   const int *current_bias;
54
55   async_load_state *img_loader;
56 };
57
58
59 #define SHUFFLE         0
60 #define UP              1
61 #define LEFT            2
62 #define RIGHT           3
63 #define DOWN            4
64 #define UPLEFT          5
65 #define DOWNLEFT        6
66 #define UPRIGHT         7
67 #define DOWNRIGHT       8
68 #define IN              9
69 #define OUT             10
70 #define MELT            11
71 #define STRETCH         12
72 #define FUZZ            13
73
74 static void
75 decayscreen_load_image (struct state *st)
76 {
77   XWindowAttributes xgwa;
78   XGetWindowAttributes (st->dpy, st->window, &xgwa);
79   st->sizex = xgwa.width;
80   st->sizey = xgwa.height;
81   if (st->img_loader) abort();
82   st->img_loader = load_image_async_simple (0, xgwa.screen, st->window,
83                                             st->window, 0, 0);
84 }
85
86 static void *
87 decayscreen_init (Display *dpy, Window window)
88 {
89   struct state *st = (struct state *) calloc (1, sizeof(*st));
90   XGCValues gcv;
91   XWindowAttributes xgwa;
92   long gcflags;
93   unsigned long bg;
94   char *s;
95
96   st->dpy = dpy;
97   st->window = window;
98   st->random_p = 0;
99
100   s = get_string_resource(st->dpy, "mode", "Mode");
101   if      (s && !strcmp(s, "shuffle")) st->mode = SHUFFLE;
102   else if (s && !strcmp(s, "up")) st->mode = UP;
103   else if (s && !strcmp(s, "left")) st->mode = LEFT;
104   else if (s && !strcmp(s, "right")) st->mode = RIGHT;
105   else if (s && !strcmp(s, "down")) st->mode = DOWN;
106   else if (s && !strcmp(s, "upleft")) st->mode = UPLEFT;
107   else if (s && !strcmp(s, "downleft")) st->mode = DOWNLEFT;
108   else if (s && !strcmp(s, "upright")) st->mode = UPRIGHT;
109   else if (s && !strcmp(s, "downright")) st->mode = DOWNRIGHT;
110   else if (s && !strcmp(s, "in")) st->mode = IN;
111   else if (s && !strcmp(s, "out")) st->mode = OUT;
112   else if (s && !strcmp(s, "melt")) st->mode = MELT;
113   else if (s && !strcmp(s, "stretch")) st->mode = STRETCH;
114   else if (s && !strcmp(s, "fuzz")) st->mode = FUZZ;
115   else {
116     if (s && *s && !!strcmp(s, "random"))
117       fprintf(stderr, "%s: unknown mode %s\n", progname, s);
118     st->random_p = 1;
119     st->mode = random() % (FUZZ+1);
120   }
121
122   st->delay = get_integer_resource (st->dpy, "delay", "Integer");
123   if (st->delay < 0) st->delay = 0;
124
125   st->duration = get_integer_resource (st->dpy, "duration", "Seconds");
126   if (st->duration < 1) st->duration = 1;
127
128   XGetWindowAttributes (st->dpy, st->window, &xgwa);
129
130   gcv.function = GXcopy;
131   gcv.subwindow_mode = IncludeInferiors;
132   bg = get_pixel_resource (st->dpy, xgwa.colormap, "background", "Background");
133   gcv.foreground = bg;
134
135   gcflags = GCForeground | GCFunction;
136   if (use_subwindow_mode_p(xgwa.screen, st->window)) /* see grabscreen.c */
137     gcflags |= GCSubwindowMode;
138   st->gc = XCreateGC (st->dpy, st->window, gcflags, &gcv);
139
140   st->start_time = time ((time_t) 0);
141   decayscreen_load_image (st);
142
143   return st;
144 }
145
146
147 /*
148  * perform one iteration of decay
149  */
150 static unsigned long
151 decayscreen_draw (Display *dpy, Window window, void *closure)
152 {
153     struct state *st = (struct state *) closure;
154     int left, top, width, height, toleft, totop;
155
156 #define L 101
157 #define R 102
158 #define U 103
159 #define D 104
160     static const int no_bias[]        = { L,L,L,L, R,R,R,R, U,U,U,U, D,D,D,D };
161     static const int up_bias[]        = { L,L,L,L, R,R,R,R, U,U,U,U, U,U,D,D };
162     static const int down_bias[]      = { L,L,L,L, R,R,R,R, U,U,D,D, D,D,D,D };
163     static const int left_bias[]      = { L,L,L,L, L,L,R,R, U,U,U,U, D,D,D,D };
164     static const int right_bias[]     = { L,L,R,R, R,R,R,R, U,U,U,U, D,D,D,D };
165
166     static const int upleft_bias[]    = { L,L,L,L, L,R,R,R, U,U,U,U, U,D,D,D };
167     static const int downleft_bias[]  = { L,L,L,L, L,R,R,R, U,U,U,D, D,D,D,D };
168     static const int upright_bias[]   = { L,L,L,R, R,R,R,R, U,U,U,U, U,D,D,D };
169     static const int downright_bias[] = { L,L,L,R, R,R,R,R, U,U,U,D, D,D,D,D };
170
171     if (st->img_loader)   /* still loading */
172       {
173         st->img_loader = load_image_async_simple (st->img_loader, 
174                                                   0, 0, 0, 0, 0);
175         if (! st->img_loader) {  /* just finished */
176
177           st->start_time = time ((time_t) 0);
178           if (st->random_p)
179             st->mode = random() % (FUZZ+1);
180
181           if (st->mode == MELT || st->mode == STRETCH)
182             /* make sure screen eventually turns background color */
183             XDrawLine (st->dpy, st->window, st->gc, 0, 0, st->sizex, 0); 
184         }
185       return st->delay;
186     }
187
188     if (!st->img_loader &&
189         st->start_time + st->duration < time ((time_t) 0)) {
190       decayscreen_load_image (st);
191     }
192
193     switch (st->mode) {
194       case SHUFFLE:     st->current_bias = no_bias; break;
195       case UP:          st->current_bias = up_bias; break;
196       case LEFT:        st->current_bias = left_bias; break;
197       case RIGHT:       st->current_bias = right_bias; break;
198       case DOWN:        st->current_bias = down_bias; break;
199       case UPLEFT:      st->current_bias = upleft_bias; break;
200       case DOWNLEFT:    st->current_bias = downleft_bias; break;
201       case UPRIGHT:     st->current_bias = upright_bias; break;
202       case DOWNRIGHT:   st->current_bias = downright_bias; break;
203       case IN:          st->current_bias = no_bias; break;
204       case OUT:         st->current_bias = no_bias; break;
205       case MELT:        st->current_bias = no_bias; break;
206       case STRETCH:     st->current_bias = no_bias; break;
207       case FUZZ:        st->current_bias = no_bias; break;
208      default: abort();
209     }
210
211 #define nrnd(x) ((x) ? random() % (x) : x)
212
213     if (st->mode == MELT || st->mode == STRETCH) {
214       left = nrnd(st->sizex/2);
215       top = nrnd(st->sizey);
216       width = nrnd( st->sizex/2 ) + st->sizex/2 - left;
217       height = nrnd(st->sizey - top);
218       toleft = left;
219       totop = top+1;
220
221     } else if (st->mode == FUZZ) {  /* By Vince Levey <vincel@vincel.org>;
222                                    inspired by the "melt" mode of the
223                                    "scrhack" IrisGL program by Paul Haeberli
224                                    circa 1991. */
225       left = nrnd(st->sizex - 1);
226       top  = nrnd(st->sizey - 1);
227       st->fuzz_toggle = !st->fuzz_toggle;
228       if (st->fuzz_toggle)
229         {
230           totop = top;
231           height = 1;
232           toleft = nrnd(st->sizex - 1);
233           if (toleft > left)
234             {
235               width = toleft-left;
236               toleft = left;
237               left++;
238             }
239           else
240             {
241               width = left-toleft;
242               left = toleft;
243               toleft++;
244             }
245         }
246       else
247         {
248           toleft = left;
249           width = 1;
250           totop  = nrnd(st->sizey - 1);
251           if (totop > top)
252             {
253               height = totop-top;
254               totop = top;
255               top++;
256             }
257           else
258             {
259               height = top-totop;
260               top = totop;
261               totop++;
262             }
263         }
264
265     } else {
266
267       left = nrnd(st->sizex - 1);
268       top = nrnd(st->sizey);
269       width = nrnd(st->sizex - left);
270       height = nrnd(st->sizey - top);
271       
272       toleft = left;
273       totop = top;
274       if (st->mode == IN || st->mode == OUT) {
275         int x = left+(width/2);
276         int y = top+(height/2);
277         int cx = st->sizex/2;
278         int cy = st->sizey/2;
279         if (st->mode == IN) {
280           if      (x > cx && y > cy)   st->current_bias = upleft_bias;
281           else if (x < cx && y > cy)   st->current_bias = upright_bias;
282           else if (x < cx && y < cy)   st->current_bias = downright_bias;
283           else /* (x > cx && y < cy)*/ st->current_bias = downleft_bias;
284         } else {
285           if      (x > cx && y > cy)   st->current_bias = downright_bias;
286           else if (x < cx && y > cy)   st->current_bias = downleft_bias;
287           else if (x < cx && y < cy)   st->current_bias = upleft_bias;
288           else /* (x > cx && y < cy)*/ st->current_bias = upright_bias;
289         }
290       }
291       
292       switch (st->current_bias[random() % (sizeof(no_bias)/sizeof(*no_bias))]) {
293       case L: toleft = left-1; break;
294       case R: toleft = left+1; break;
295       case U: totop = top-1; break;
296       case D: totop = top+1; break;
297       default: abort(); break;
298       }
299     }
300     
301     if (st->mode == STRETCH) {
302       XCopyArea (st->dpy, st->window, st->window, st->gc, 0, st->sizey-top-2, st->sizex, top+1, 
303                  0, st->sizey-top-1); 
304     } else {
305       XCopyArea (st->dpy, st->window, st->window, st->gc, left, top, width, height,
306                  toleft, totop);
307     }
308
309 #undef nrnd
310
311     return st->delay;
312 }
313
314 static void
315 decayscreen_reshape (Display *dpy, Window window, void *closure, 
316                  unsigned int w, unsigned int h)
317 {
318   struct state *st = (struct state *) closure;
319   st->sizex = w;
320   st->sizey = h;
321 }
322
323 static Bool
324 decayscreen_event (Display *dpy, Window window, void *closure, XEvent *event)
325 {
326   return False;
327 }
328
329 static void
330 decayscreen_free (Display *dpy, Window window, void *closure)
331 {
332   struct state *st = (struct state *) closure;
333   free (st);
334 }
335
336 \f
337
338 static const char *decayscreen_defaults [] = {
339   ".background:                 Black",
340   ".foreground:                 Yellow",
341   "*dontClearRoot:              True",
342   "*fpsSolid:                   True",
343
344 #ifdef __sgi    /* really, HAVE_READ_DISPLAY_EXTENSION */
345   "*visualID:                   Best",
346 #endif
347
348   "*delay:                      10000",
349   "*mode:                       random",
350   "*duration:                   120",
351   0
352 };
353
354 static XrmOptionDescRec decayscreen_options [] = {
355   { "-delay",           ".delay",               XrmoptionSepArg, 0 },
356   { "-mode",            ".mode",                XrmoptionSepArg, 0 },
357   { "-duration",        ".duration",            XrmoptionSepArg, 0 },
358   { 0, 0, 0, 0 }
359 };
360
361
362 XSCREENSAVER_MODULE ("DecayScreen", decayscreen)