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