http://packetstormsecurity.org/UNIX/admin/xscreensaver-4.14.tar.gz
[xscreensaver] / hacks / decayscreen.c
1 /* xscreensaver, Copyright (c) 1992, 1993, 1994, 1996, 1997 
2  * Jamie Zawinski <jwz@jwz.org>
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation.  No representations are made about the suitability of this
9  * software for any purpose.  It is provided "as is" without express or 
10  * implied warranty.
11  */
12
13 /* decayscreen
14  *
15  * Based on slidescreen program from the xscreensaver application and the
16  * decay program for Sun framebuffers.  This is the comment from the decay.c
17  * file:
18
19  * decay.c
20  *   find the screen bitmap for the console and make it "decay" by
21  *   randomly shifting random rectangles by one pixelwidth at a time.
22  *
23  *   by David Wald, 1988
24  *        rewritten by Natuerlich!
25  *   based on a similar "utility" on the Apollo ring at Yale.
26
27  * X version by
28  *
29  *  Vivek Khera <khera@cs.duke.edu>
30  *  5-AUG-1993
31  *
32  *  Hacked by jwz, 28-Nov-97 (sped up and added new motion directions)
33  
34  *  R. Schultz
35  *  Added "melt" & "stretch" modes 28-Mar-1999
36  *
37  */
38
39 #include "screenhack.h"
40
41 static int sizex, sizey;
42 static int delay;
43 static GC gc;
44 static int mode;
45 static int iterations=100;
46
47 #define SHUFFLE 0
48 #define UP 1
49 #define LEFT 2
50 #define RIGHT 3
51 #define DOWN 4
52 #define UPLEFT 5
53 #define DOWNLEFT 6
54 #define UPRIGHT 7
55 #define DOWNRIGHT 8
56 #define IN 9
57 #define OUT 10
58 #define MELT 11
59 #define STRETCH 12
60 #define FUZZ 13
61
62 static void
63 init_decay (Display *dpy, Window window)
64 {
65   XGCValues gcv;
66   XWindowAttributes xgwa;
67   long gcflags;
68   unsigned long bg;
69
70   char *s = get_string_resource("mode", "Mode");
71   if      (s && !strcmp(s, "shuffle")) mode = SHUFFLE;
72   else if (s && !strcmp(s, "up")) mode = UP;
73   else if (s && !strcmp(s, "left")) mode = LEFT;
74   else if (s && !strcmp(s, "right")) mode = RIGHT;
75   else if (s && !strcmp(s, "down")) mode = DOWN;
76   else if (s && !strcmp(s, "upleft")) mode = UPLEFT;
77   else if (s && !strcmp(s, "downleft")) mode = DOWNLEFT;
78   else if (s && !strcmp(s, "upright")) mode = UPRIGHT;
79   else if (s && !strcmp(s, "downright")) mode = DOWNRIGHT;
80   else if (s && !strcmp(s, "in")) mode = IN;
81   else if (s && !strcmp(s, "out")) mode = OUT;
82   else if (s && !strcmp(s, "melt")) mode = MELT;
83   else if (s && !strcmp(s, "stretch")) mode = STRETCH;
84   else if (s && !strcmp(s, "fuzz")) mode = FUZZ;
85   else {
86     if (s && *s && !!strcmp(s, "random"))
87       fprintf(stderr, "%s: unknown mode %s\n", progname, s);
88     mode = random() % (FUZZ+1);
89   }
90
91   delay = get_integer_resource ("delay", "Integer");
92
93   if (delay < 0) delay = 0;
94
95   XGetWindowAttributes (dpy, window, &xgwa);
96
97   gcv.function = GXcopy;
98   gcv.subwindow_mode = IncludeInferiors;
99
100   if (mode == MELT || mode == STRETCH) {
101     bg = get_pixel_resource ("background", "Background", dpy, xgwa.colormap);
102     gcv.foreground = bg;
103   }
104
105   gcflags = GCForeground |GCFunction;
106   if (use_subwindow_mode_p(xgwa.screen, window)) /* see grabscreen.c */
107     gcflags |= GCSubwindowMode;
108   gc = XCreateGC (dpy, window, gcflags, &gcv);
109
110   sizex = xgwa.width;
111   sizey = xgwa.height;
112
113   load_random_image (xgwa.screen, window, window, NULL);
114   
115   if (mode == MELT || mode == STRETCH) {
116     /* make sure screen eventually turns background color */
117     XDrawLine(dpy, window, gc, 0, 0, sizex, 0); 
118
119     /* slow down for smoother melting*/
120     iterations = 1;
121   }
122
123 }
124
125
126 /*
127  * perform one iteration of decay
128  */
129 static void
130 decay1 (Display *dpy, Window window)
131 {
132     int left, top, width, height, toleft, totop;
133
134 #define L 101
135 #define R 102
136 #define U 103
137 #define D 104
138     static int no_bias[]        = { L,L,L,L, R,R,R,R, U,U,U,U, D,D,D,D };
139     static int up_bias[]        = { L,L,L,L, R,R,R,R, U,U,U,U, U,U,D,D };
140     static int down_bias[]      = { L,L,L,L, R,R,R,R, U,U,D,D, D,D,D,D };
141     static int left_bias[]      = { L,L,L,L, L,L,R,R, U,U,U,U, D,D,D,D };
142     static int right_bias[]     = { L,L,R,R, R,R,R,R, U,U,U,U, D,D,D,D };
143
144     static int upleft_bias[]    = { L,L,L,L, L,R,R,R, U,U,U,U, U,D,D,D };
145     static int downleft_bias[]  = { L,L,L,L, L,R,R,R, U,U,U,D, D,D,D,D };
146     static int upright_bias[]   = { L,L,L,R, R,R,R,R, U,U,U,U, U,D,D,D };
147     static int downright_bias[] = { L,L,L,R, R,R,R,R, U,U,U,D, D,D,D,D };
148     static int *bias;
149
150     switch (mode) {
151       case SHUFFLE:     bias = no_bias; break;
152       case UP:          bias = up_bias; break;
153       case LEFT:        bias = left_bias; break;
154       case RIGHT:       bias = right_bias; break;
155       case DOWN:        bias = down_bias; break;
156       case UPLEFT:      bias = upleft_bias; break;
157       case DOWNLEFT:    bias = downleft_bias; break;
158       case UPRIGHT:     bias = upright_bias; break;
159       case DOWNRIGHT:   bias = downright_bias; break;
160       case IN:          bias = no_bias; break;
161       case OUT:         bias = no_bias; break;
162       case MELT:        bias = no_bias; break;
163       case STRETCH:     bias = no_bias; break;
164       case FUZZ:        bias = no_bias; break;
165      default: abort();
166     }
167
168 #define nrnd(x) (random() % (x))
169
170     if (mode == MELT || mode == STRETCH) {
171       left = nrnd(sizex/2);
172       top = nrnd(sizey);
173       width = nrnd( sizex/2 ) + sizex/2 - left;
174       height = nrnd(sizey - top);
175       toleft = left;
176       totop = top+1;
177
178     } else if (mode == FUZZ) {  /* By Vince Levey <vincel@vincel.org>;
179                                    inspired by the "melt" mode of the
180                                    "scrhack" IrisGL program by Paul Haeberli
181                                    circa 1991. */
182       static int toggle = 0;
183
184       left = nrnd(sizex - 1);
185       top  = nrnd(sizey - 1);
186       toggle = !toggle;
187       if (toggle)
188         {
189           totop = top;
190           height = 1;
191           toleft = nrnd(sizex - 1);
192           if (toleft > left)
193             {
194               width = toleft-left;
195               toleft = left;
196               left++;
197             }
198           else
199             {
200               width = left-toleft;
201               left = toleft;
202               toleft++;
203             }
204         }
205       else
206         {
207           toleft = left;
208           width = 1;
209           totop  = nrnd(sizey - 1);
210           if (totop > top)
211             {
212               height = totop-top;
213               totop = top;
214               top++;
215             }
216           else
217             {
218               height = top-totop;
219               top = totop;
220               totop++;
221             }
222         }
223
224     } else {
225
226       left = nrnd(sizex - 1);
227       top = nrnd(sizey);
228       width = nrnd(sizex - left);
229       height = nrnd(sizey - top);
230       
231       toleft = left;
232       totop = top;
233       if (mode == IN || mode == OUT) {
234         int x = left+(width/2);
235         int y = top+(height/2);
236         int cx = sizex/2;
237         int cy = sizey/2;
238         if (mode == IN) {
239           if      (x > cx && y > cy)   bias = upleft_bias;
240           else if (x < cx && y > cy)   bias = upright_bias;
241           else if (x < cx && y < cy)   bias = downright_bias;
242           else /* (x > cx && y < cy)*/ bias = downleft_bias;
243         } else {
244           if      (x > cx && y > cy)   bias = downright_bias;
245           else if (x < cx && y > cy)   bias = downleft_bias;
246           else if (x < cx && y < cy)   bias = upleft_bias;
247           else /* (x > cx && y < cy)*/ bias = upright_bias;
248         }
249       }
250       
251       switch (bias[random() % (sizeof(no_bias)/sizeof(*no_bias))]) {
252       case L: toleft = left-1; break;
253       case R: toleft = left+1; break;
254       case U: totop = top-1; break;
255       case D: totop = top+1; break;
256       default: abort(); break;
257       }
258     }
259     
260     if (mode == STRETCH) {
261       XCopyArea (dpy, window, window, gc, 0, sizey-top-2, sizex, top+1, 
262                  0, sizey-top-1); 
263     } else {
264       XCopyArea (dpy, window, window, gc, left, top, width, height,
265                  toleft, totop);
266     }
267
268 #undef nrnd
269 }
270
271 \f
272 char *progclass = "DecayScreen";
273
274 char *defaults [] = {
275   "*dontClearRoot:              True",
276
277 #ifdef __sgi    /* really, HAVE_READ_DISPLAY_EXTENSION */
278   "*visualID:                   Best",
279 #endif
280
281   "*delay:                      10000",
282   "*mode:                       random",
283   0
284 };
285
286 XrmOptionDescRec options [] = {
287   { "-delay",           ".delay",               XrmoptionSepArg, 0 },
288   { "-mode",            ".mode",                XrmoptionSepArg, 0 },
289   { 0, 0, 0, 0 }
290 };
291
292 void
293 screenhack (Display *dpy, Window window)
294 {
295     init_decay (dpy, window);
296     while (1) {
297       int i;
298       for (i = 0; i < iterations; i++)
299         decay1 (dpy, window);
300       XSync(dpy, False);
301       screenhack_handle_events (dpy);
302       if (delay) usleep (delay);
303     }
304 }