ftp://ftp.uni-heidelberg.de/pub/X11/contrib/applications/xscreensaver-2.07.tar.gz
[xscreensaver] / hacks / slidescreen.c
1 /* xscreensaver, Copyright (c) 1992, 1993, 1994, 1996, 1997 
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 int max_width, max_height;
24
25 static void
26 init_slide (Display *dpy, Window window)
27 {
28   int i;
29   XGCValues gcv;
30   XWindowAttributes xgwa;
31   int border;
32   unsigned long fg;
33   Drawable d;
34   Colormap cmap;
35   Visual *visual;
36
37   XGetWindowAttributes (dpy, window, &xgwa);
38   cmap = xgwa.colormap;
39   visual = xgwa.visual;
40   max_width = xgwa.width;
41   max_height = xgwa.height;
42
43   delay = get_integer_resource ("delay", "Integer");
44   delay2 = get_integer_resource ("delay2", "Integer");
45   grid_size = get_integer_resource ("gridSize", "Integer");
46   pix_inc = get_integer_resource ("pixelIncrement", "Integer");
47   border = get_integer_resource ("internalBorderWidth", "InternalBorderWidth");
48   fg = get_pixel_resource ("background", "Background", dpy, cmap);
49
50   grab_screen_image (xgwa.screen, window);
51
52
53   /* Total kludge -- if grab_screen_image() installed a new colormap, assume
54      that pixel 0 is the one we should use.  This further assumes that the
55      pixel is black, which overrides the user's -background setting, alas.
56    */
57   XGetWindowAttributes (dpy, window, &xgwa);
58   if (cmap != xgwa.colormap) fg = 0;
59
60
61   if (delay < 0) delay = 0;
62   if (delay2 < 0) delay2 = 0;
63   if (pix_inc < 1) pix_inc = 1;
64   if (grid_size < 1) grid_size = 1;
65
66   gcv.foreground = fg;
67   gcv.function = GXcopy;
68   gcv.subwindow_mode = IncludeInferiors;
69   gc = XCreateGC (dpy, window, GCForeground |GCFunction | GCSubwindowMode,
70                   &gcv);
71
72   XGetWindowAttributes (dpy, window, &xgwa);
73   bitmap_w = xgwa.width;
74   bitmap_h = xgwa.height;
75
76   grid_w = bitmap_w / grid_size;
77   grid_h = bitmap_h / grid_size;
78   hole_x = random () % grid_w;
79   hole_y = random () % grid_h;
80   xoff = (bitmap_w - (grid_w * grid_size)) / 2;
81   yoff = (bitmap_h - (grid_h * grid_size)) / 2;
82
83   d = window;
84
85   if (border)
86     {
87       for (i = 0; i <= bitmap_w; i += grid_size)
88         XFillRectangle (dpy, d, gc, xoff+i-border/2, yoff, border, bitmap_h);
89       for (i = 0; i <= bitmap_h; i += grid_size)
90         XFillRectangle (dpy, d, gc, xoff, yoff+i-border/2, bitmap_w, border);
91     }
92
93   if (xoff)
94     {
95       XFillRectangle (dpy, d, gc, 0, 0, xoff, bitmap_h);
96       XFillRectangle (dpy, d, gc, bitmap_w - xoff, 0, xoff, bitmap_h);
97     }
98   if (yoff)
99     {
100       XFillRectangle (dpy, d, gc, 0, 0, bitmap_w, yoff);
101       XFillRectangle (dpy, d, gc, 0, bitmap_h - yoff, bitmap_w, yoff);
102     }
103
104   XSync (dpy, True);
105   if (delay2) usleep (delay2 * 2);
106  for (i = 0; i < grid_size; i += pix_inc)
107    {
108      XPoint points [3];
109      points[0].x = xoff + grid_size * hole_x;
110      points[0].y = yoff + grid_size * hole_y;
111      points[1].x = points[0].x + grid_size;
112      points[1].y = points[0].y;
113      points[2].x = points[0].x;
114      points[2].y = points[0].y + i;
115      XFillPolygon (dpy, window, gc, points, 3, Convex, CoordModeOrigin);
116
117      points[1].x = points[0].x;
118      points[1].y = points[0].y + grid_size;
119      points[2].x = points[0].x + i;
120      points[2].y = points[0].y + grid_size;
121      XFillPolygon (dpy, window, gc, points, 3, Convex, CoordModeOrigin);
122
123      points[0].x = points[1].x + grid_size;
124      points[0].y = points[1].y;
125      points[2].x = points[0].x;
126      points[2].y = points[0].y - i;
127      XFillPolygon (dpy, window, gc, points, 3, Convex, CoordModeOrigin);
128
129      points[1].x = points[0].x;
130      points[1].y = points[0].y - grid_size;
131      points[2].x = points[1].x - i;
132      points[2].y = points[1].y;
133      XFillPolygon (dpy, window, gc, points, 3, Convex, CoordModeOrigin);
134
135      XSync (dpy, True);
136      if (delay) usleep (delay);
137    }
138
139   XFillRectangle (dpy, window, gc,
140                   xoff + grid_size * hole_x,
141                   yoff + grid_size * hole_y,
142                   grid_size, grid_size);
143 }
144
145 static void
146 slide1 (Display *dpy, Window window)
147 {
148   /* this code is a total kludge, but who cares, it works... */
149  int i, x, y, ix, iy, dx, dy, dir, w, h, size, inc;
150  static int last = -1;
151  do {
152    dir = random () % 4;
153    switch (dir)
154      {
155      case 0: dx = 0,  dy = 1;  break;
156      case 1: dx = -1, dy = 0;  break;
157      case 2: dx = 0,  dy = -1; break;
158      case 3: dx = 1,  dy = 0;  break;
159      default: abort ();
160      }
161  } while (dir == last ||
162           hole_x + dx < 0 || hole_x + dx >= grid_w ||
163           hole_y + dy < 0 || hole_y + dy >= grid_h);
164  if (grid_w > 1 && grid_h > 1)
165    last = (dir == 0 ? 2 : dir == 2 ? 0 : dir == 1 ? 3 : 1);
166
167  switch (dir)
168    {
169    case 0: size = 1 + (random()%(grid_h - hole_y - 1)); h = size; w = 1; break;
170    case 1: size = 1 + (random()%hole_x);                w = size; h = 1; break;
171    case 2: size = 1 + (random()%hole_y);                h = size; w = 1; break;
172    case 3: size = 1 + (random()%(grid_w - hole_x - 1)); w = size; h = 1; break;
173    default: abort ();
174    }
175
176  if (dx == -1) hole_x -= (size - 1);
177  else if (dy == -1) hole_y -= (size - 1);
178
179  ix = x = xoff + (hole_x + dx) * grid_size;
180  iy = y = yoff + (hole_y + dy) * grid_size;
181  inc = pix_inc;
182  for (i = 0; i < grid_size; i += inc)
183    {
184      int fx, fy, tox, toy;
185      if (inc + i > grid_size)
186        inc = grid_size - i;
187      tox = x - dx * inc;
188      toy = y - dy * inc;
189
190      fx = (x < 0 ? 0 : x > max_width  ? max_width  : x);
191      fy = (y < 0 ? 0 : y > max_height ? max_height : y);
192      tox = (tox < 0 ? 0 : tox > max_width  ? max_width  : tox);
193      toy = (toy < 0 ? 0 : toy > max_height ? max_height : toy);
194
195      XCopyArea (dpy, window, window, gc,
196                 fx, fy,
197                 grid_size * w, grid_size * h,
198                 tox, toy);
199
200      x -= dx * inc;
201      y -= dy * inc;
202      switch (dir)
203        {
204        case 0: XFillRectangle (dpy, window, gc,
205                                ix, y + grid_size * h, grid_size * w, iy - y);
206          break;
207        case 1: XFillRectangle (dpy, window, gc, ix, iy, x - ix, grid_size * h);
208          break;
209        case 2: XFillRectangle (dpy, window, gc, ix, iy, grid_size * w, y - iy);
210          break;
211        case 3: XFillRectangle (dpy, window, gc,
212                                x + grid_size * w, iy, ix - x, grid_size * h);
213          break;
214        }
215
216      XSync (dpy, True);
217      if (delay) usleep (delay);
218    }
219  switch (dir)
220    {
221    case 0: hole_y += size; break;
222    case 1: hole_x--; break;
223    case 2: hole_y--; break;
224    case 3: hole_x += size; break;
225    }
226 }
227
228 \f
229 char *progclass = "SlidePuzzle";
230
231 char *defaults [] = {
232   "*dontClearRoot:              True",
233
234 #ifdef __sgi    /* really, HAVE_READ_DISPLAY_EXTENSION */
235   "*visualID:                   Best",
236 #endif
237
238   "*background:                 Black",
239   "*gridSize:                   70",
240   "*pixelIncrement:             10",
241   "*internalBorderWidth:        1",
242   "*delay:                      50000",
243   "*delay2:                     1000000",
244   0
245 };
246
247 XrmOptionDescRec options [] = {
248   { "-grid-size",       ".gridSize",            XrmoptionSepArg, 0 },
249   { "-ibw",             ".internalBorderWidth", XrmoptionSepArg, 0 },
250   { "-increment",       ".pixelIncrement",      XrmoptionSepArg, 0 },
251   { "-delay",           ".delay",               XrmoptionSepArg, 0 },
252   { "-delay2",          ".delay2",              XrmoptionSepArg, 0 },
253   { 0, 0, 0, 0 }
254 };
255
256 void
257 screenhack (Display *dpy, Window window)
258 {
259   init_slide (dpy, window);
260   while (1)
261     {
262       slide1 (dpy, window);
263       if (delay2) usleep (delay2);
264     }
265 }