http://www.ibiblio.org/pub/historic-linux/ftp-archives/sunsite.unc.edu/Sep-29-1996...
[xscreensaver] / hacks / slidescreen.c
1 /* xscreensaver, Copyright (c) 1992, 1993, 1994 
2  * Jamie Zawinski <jwz@netscape.com>
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 #include "screenhack.h"
14
15 static int grid_size;
16 static int pix_inc;
17 static int hole_x, hole_y;
18 static int bitmap_w, bitmap_h;
19 static int xoff, yoff;
20 static int grid_w, grid_h;
21 static int delay, delay2;
22 static GC gc;
23
24 static void
25 init_slide (dpy, window)
26      Display *dpy;
27      Window window;
28 {
29   int i;
30   XGCValues gcv;
31   XWindowAttributes xgwa;
32   int border;
33   int root_p;
34   unsigned long fg;
35   Pixmap pixmap;
36   Drawable d;
37   Colormap cmap;
38   Visual *visual;
39
40   XGetWindowAttributes (dpy, window, &xgwa);
41   cmap = xgwa.colormap;
42   visual = xgwa.visual;
43
44   copy_default_colormap_contents (dpy, cmap, visual);
45
46   delay = get_integer_resource ("delay", "Integer");
47   delay2 = get_integer_resource ("delay2", "Integer");
48   grid_size = get_integer_resource ("gridSize", "Integer");
49   pix_inc = get_integer_resource ("pixelIncrement", "Integer");
50   border = get_integer_resource ("internalBorderWidth", "InternalBorderWidth");
51   fg = get_pixel_resource ("background", "Background", dpy,
52                            /* Pixels always come out of default map. */
53                            XDefaultColormapOfScreen (xgwa.screen));
54   root_p = get_boolean_resource ("root", "Boolean");
55
56   if (delay < 0) delay = 0;
57   if (delay2 < 0) delay2 = 0;
58   if (pix_inc < 1) pix_inc = 1;
59   if (grid_size < 1) grid_size = 1;
60
61   gcv.foreground = fg;
62   gcv.function = GXcopy;
63   gcv.subwindow_mode = IncludeInferiors;
64   gc = XCreateGC (dpy, window, GCForeground |GCFunction | GCSubwindowMode,
65                   &gcv);
66
67   pixmap = grab_screen_image (dpy, window, root_p);
68
69   XGetWindowAttributes (dpy, window, &xgwa);
70   bitmap_w = xgwa.width;
71   bitmap_h = xgwa.height;
72
73   grid_w = bitmap_w / grid_size;
74   grid_h = bitmap_h / grid_size;
75   hole_x = random () % grid_w;
76   hole_y = random () % grid_h;
77   xoff = (bitmap_w - (grid_w * grid_size)) / 2;
78   yoff = (bitmap_h - (grid_h * grid_size)) / 2;
79
80   d = (pixmap ? pixmap : window);
81
82   if (border)
83     {
84       int i;
85       for (i = 0; i <= bitmap_w; i += grid_size)
86         XFillRectangle (dpy, d, gc, xoff+i-border/2, yoff, border, bitmap_h);
87       for (i = 0; i <= bitmap_h; i += grid_size)
88         XFillRectangle (dpy, d, gc, xoff, yoff+i-border/2, bitmap_w, border);
89     }
90
91   if (xoff)
92     {
93       XFillRectangle (dpy, d, gc, 0, 0, xoff, bitmap_h);
94       XFillRectangle (dpy, d, gc, bitmap_w - xoff, 0, xoff, bitmap_h);
95     }
96   if (yoff)
97     {
98       XFillRectangle (dpy, d, gc, 0, 0, bitmap_w, yoff);
99       XFillRectangle (dpy, d, gc, 0, bitmap_h - yoff, bitmap_w, yoff);
100     }
101
102   if (pixmap) XClearWindow (dpy, window);
103   XSync (dpy, True);
104   if (delay2) usleep (delay2 * 2);
105  for (i = 0; i < grid_size; i += pix_inc)
106    {
107      XPoint points [3];
108      points[0].x = xoff + grid_size * hole_x;
109      points[0].y = yoff + grid_size * hole_y;
110      points[1].x = points[0].x + grid_size;
111      points[1].y = points[0].y;
112      points[2].x = points[0].x;
113      points[2].y = points[0].y + i;
114      XFillPolygon (dpy, window, gc, points, 3, Convex, CoordModeOrigin);
115
116      points[1].x = points[0].x;
117      points[1].y = points[0].y + grid_size;
118      points[2].x = points[0].x + i;
119      points[2].y = points[0].y + grid_size;
120      XFillPolygon (dpy, window, gc, points, 3, Convex, CoordModeOrigin);
121
122      points[0].x = points[1].x + grid_size;
123      points[0].y = points[1].y;
124      points[2].x = points[0].x;
125      points[2].y = points[0].y - i;
126      XFillPolygon (dpy, window, gc, points, 3, Convex, CoordModeOrigin);
127
128      points[1].x = points[0].x;
129      points[1].y = points[0].y - grid_size;
130      points[2].x = points[1].x - i;
131      points[2].y = points[1].y;
132      XFillPolygon (dpy, window, gc, points, 3, Convex, CoordModeOrigin);
133
134      XSync (dpy, True);
135      if (delay) usleep (delay);
136    }
137
138   XFillRectangle (dpy, window, gc,
139                   xoff + grid_size * hole_x,
140                   yoff + grid_size * hole_y,
141                   grid_size, grid_size);
142 }
143
144 static void
145 slide1 (dpy, window)
146      Display *dpy;
147      Window window;
148 {
149   /* this code is a total kludge, but who cares, it works... */
150  int i, x, y, ix, iy, dx, dy, dir, w, h, size, inc;
151  static int last = -1;
152  do {
153    dir = random () % 4;
154    switch (dir)
155      {
156      case 0: dx = 0,  dy = 1;  break;
157      case 1: dx = -1, dy = 0;  break;
158      case 2: dx = 0,  dy = -1; break;
159      case 3: dx = 1,  dy = 0;  break;
160      default: abort ();
161      }
162  } while (dir == last ||
163           hole_x + dx < 0 || hole_x + dx >= grid_w ||
164           hole_y + dy < 0 || hole_y + dy >= grid_h);
165  if (grid_w > 1 && grid_h > 1)
166    last = (dir == 0 ? 2 : dir == 2 ? 0 : dir == 1 ? 3 : 1);
167
168  switch (dir)
169    {
170    case 0: size = 1 + (random()%(grid_h - hole_y - 1)); h = size; w = 1; break;
171    case 1: size = 1 + (random()%hole_x);                w = size; h = 1; break;
172    case 2: size = 1 + (random()%hole_y);                h = size; w = 1; break;
173    case 3: size = 1 + (random()%(grid_w - hole_x - 1)); w = size; h = 1; break;
174    default: abort ();
175    }
176
177  if (dx == -1) hole_x -= (size - 1);
178  else if (dy == -1) hole_y -= (size - 1);
179
180  ix = x = xoff + (hole_x + dx) * grid_size;
181  iy = y = yoff + (hole_y + dy) * grid_size;
182  inc = pix_inc;
183  for (i = 0; i < grid_size; i += inc)
184    {
185      if (inc + i > grid_size)
186        inc = grid_size - i;
187      XCopyArea (dpy, window, window, gc, x, y, grid_size * w, grid_size * h,
188                 x - dx * inc, y - dy * inc);
189      x -= dx * inc;
190      y -= dy * inc;
191      switch (dir)
192        {
193        case 0: XFillRectangle (dpy, window, gc,
194                                ix, y + grid_size * h, grid_size * w, iy - y);
195          break;
196        case 1: XFillRectangle (dpy, window, gc, ix, iy, x - ix, grid_size * h);
197          break;
198        case 2: XFillRectangle (dpy, window, gc, ix, iy, grid_size * w, y - iy);
199          break;
200        case 3: XFillRectangle (dpy, window, gc,
201                                x + grid_size * w, iy, ix - x, grid_size * h);
202          break;
203        }
204
205      XSync (dpy, True);
206      if (delay) usleep (delay);
207    }
208  switch (dir)
209    {
210    case 0: hole_y += size; break;
211    case 1: hole_x--; break;
212    case 2: hole_y--; break;
213    case 3: hole_x += size; break;
214    }
215 }
216
217 \f
218 char *progclass = "SlidePuzzle";
219
220 char *defaults [] = {
221   "SlidePuzzle.mappedWhenManaged:false",
222   "SlidePuzzle.dontClearWindow:  true",
223   "*background:                 black",
224   "*gridSize:                   70",
225   "*pixelIncrement:             10",
226   "*internalBorderWidth:        1",
227   "*delay:                      50000",
228   "*delay2:                     1000000",
229   0
230 };
231
232 XrmOptionDescRec options [] = {
233   { "-grid-size",       ".gridSize",            XrmoptionSepArg, 0 },
234   { "-ibw",             ".internalBorderWidth", XrmoptionSepArg, 0 },
235   { "-increment",       ".pixelIncrement",      XrmoptionSepArg, 0 },
236   { "-delay",           ".delay",               XrmoptionSepArg, 0 },
237   { "-delay2",          ".delay2",              XrmoptionSepArg, 0 },
238 };
239
240 int options_size = (sizeof (options) / sizeof (options[0]));
241
242 void
243 screenhack (dpy, window)
244      Display *dpy;
245      Window window;
246 {
247   init_slide (dpy, window);
248   while (1)
249     {
250       slide1 (dpy, window);
251       if (delay2) usleep (delay2);
252     }
253 }