ftp://ftp.ntnu.no/old/pub/X11/R5contrib/xscreensaver-1.17.tar.gz
[xscreensaver] / hacks / slidescreen.c
1 /* xscreensaver, Copyright (c) 1992, 1993 Jamie Zawinski <jwz@lucid.com>
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 #include "screenhack.h"
13
14 static int grid_size;
15 static int pix_inc;
16 static int hole_x, hole_y;
17 static int bitmap_w, bitmap_h;
18 static int xoff, yoff;
19 static int grid_w, grid_h;
20 static int delay, delay2;
21 static GC gc;
22
23 static Bool
24 MapNotify_event_p (dpy, event, window)
25      Display *dpy;
26      XEvent *event;
27      XPointer window;
28 {
29   return (event->xany.type == MapNotify &&
30           event->xvisibility.window == (Window) window);
31 }
32
33
34 static Bool
35 screensaver_window_p (dpy, window)
36      Display *dpy;
37      Window window;
38 {
39   Atom type;
40   int format;
41   unsigned long nitems, bytesafter;
42   char *version;
43   Pixmap pixmap;
44   if (XGetWindowProperty (dpy, window,
45                           XInternAtom (dpy, "_SCREENSAVER_VERSION", False),
46                           0, 1, False, XA_STRING,
47                           &type, &format, &nitems, &bytesafter,
48                           (unsigned char **) &version)
49       == Success
50       && type != None)
51     return True;
52   return False;
53 }
54
55 static void
56 init_slide (dpy, window)
57      Display *dpy;
58      Window window;
59 {
60   int i;
61   XEvent event;
62   XGCValues gcv;
63   XWindowAttributes xgwa;
64   int border;
65   int root_p;
66   unsigned long fg;
67   Pixmap pixmap = 0;
68   Drawable d;
69   Colormap cmap;
70
71   XGetWindowAttributes (dpy, window, &xgwa);
72   cmap = xgwa.colormap;
73
74   delay = get_integer_resource ("delay", "Integer");
75   delay2 = get_integer_resource ("delay2", "Integer");
76   grid_size = get_integer_resource ("gridSize", "Integer");
77   pix_inc = get_integer_resource ("pixelIncrement", "Integer");
78   border = get_integer_resource ("internalBorderWidth", "InternalBorderWidth");
79   fg = get_pixel_resource ("background", "Background", dpy, cmap);
80   root_p = get_boolean_resource ("root", "Boolean");
81
82   if (delay < 0) delay = 0;
83   if (delay2 < 0) delay2 = 0;
84   if (pix_inc < 1) pix_inc = 1;
85   if (grid_size < 1) grid_size = 1;
86
87   gcv.foreground = fg;
88   gcv.function = GXcopy;
89   gcv.subwindow_mode = IncludeInferiors;
90   gc = XCreateGC (dpy, window, GCForeground |GCFunction | GCSubwindowMode,
91                   &gcv);
92
93   if (screensaver_window_p (dpy, window))
94     {
95       /* note: this assumes vroot.h didn't encapsulate the XRootWindowOfScreen
96          function, only the RootWindowOfScreen macro... */
97       Window real_root = XRootWindowOfScreen (DefaultScreenOfDisplay (dpy));
98
99       XSetWindowBackgroundPixmap (dpy, window, None);
100
101       /* prevent random viewer of the screen saver (locker) from messing
102          with windows.   We don't check whether it succeeded, because what
103          are our options, really... */
104       XGrabPointer (dpy, real_root, True, ButtonPressMask|ButtonReleaseMask,
105                     GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
106       XGrabKeyboard (dpy, real_root, True, GrabModeSync, GrabModeAsync,
107                      CurrentTime);
108
109       XUnmapWindow (dpy, window);
110       XSync (dpy, True);
111       sleep (5);     /* wait for everyone to swap in and handle exposes... */
112       XMapWindow (dpy, window);
113
114       XUngrabPointer (dpy, CurrentTime);
115       XUngrabKeyboard (dpy, CurrentTime);
116
117       XSync (dpy, True);
118     }
119   else if (root_p)
120     {
121       pixmap = XCreatePixmap(dpy, window, xgwa.width, xgwa.height, xgwa.depth);
122       XCopyArea (dpy, RootWindowOfScreen (xgwa.screen), pixmap, gc,
123                  xgwa.x, xgwa.y, xgwa.width, xgwa.height, 0, 0);
124       XSetWindowBackgroundPixmap (dpy, window, pixmap);
125     }
126   else
127     {
128       XSetWindowBackgroundPixmap (dpy, window, None);
129       XMapWindow (dpy, window);
130       XFlush (dpy);
131       XIfEvent (dpy, &event, MapNotify_event_p, (XPointer) window);
132       XSync (dpy, True);
133     }
134
135   XGetWindowAttributes (dpy, window, &xgwa);
136   bitmap_w = xgwa.width;
137   bitmap_h = xgwa.height;
138
139   grid_w = bitmap_w / grid_size;
140   grid_h = bitmap_h / grid_size;
141   hole_x = random () % grid_w;
142   hole_y = random () % grid_h;
143   xoff = (bitmap_w - (grid_w * grid_size)) / 2;
144   yoff = (bitmap_h - (grid_h * grid_size)) / 2;
145
146   d = (pixmap ? pixmap : window);
147
148   if (border)
149     {
150       int i;
151       for (i = 0; i <= bitmap_w; i += grid_size)
152         XFillRectangle (dpy, d, gc, xoff+i-border/2, yoff, border, bitmap_h);
153       for (i = 0; i <= bitmap_h; i += grid_size)
154         XFillRectangle (dpy, d, gc, xoff, yoff+i-border/2, bitmap_w, border);
155     }
156
157   if (xoff)
158     {
159       XFillRectangle (dpy, d, gc, 0, 0, xoff, bitmap_h);
160       XFillRectangle (dpy, d, gc, bitmap_w - xoff, 0, xoff, bitmap_h);
161     }
162   if (yoff)
163     {
164       XFillRectangle (dpy, d, gc, 0, 0, bitmap_w, yoff);
165       XFillRectangle (dpy, d, gc, 0, bitmap_h - yoff, bitmap_w, yoff);
166     }
167
168   if (pixmap) XClearWindow (dpy, window);
169   XSync (dpy, True);
170   if (delay2) usleep (delay2 * 2);
171  for (i = 0; i < grid_size; i += pix_inc)
172    {
173      XPoint points [3];
174      points[0].x = xoff + grid_size * hole_x;
175      points[0].y = yoff + grid_size * hole_y;
176      points[1].x = points[0].x + grid_size;
177      points[1].y = points[0].y;
178      points[2].x = points[0].x;
179      points[2].y = points[0].y + i;
180      XFillPolygon (dpy, window, gc, points, 3, Convex, CoordModeOrigin);
181
182      points[1].x = points[0].x;
183      points[1].y = points[0].y + grid_size;
184      points[2].x = points[0].x + i;
185      points[2].y = points[0].y + grid_size;
186      XFillPolygon (dpy, window, gc, points, 3, Convex, CoordModeOrigin);
187
188      points[0].x = points[1].x + grid_size;
189      points[0].y = points[1].y;
190      points[2].x = points[0].x;
191      points[2].y = points[0].y - i;
192      XFillPolygon (dpy, window, gc, points, 3, Convex, CoordModeOrigin);
193
194      points[1].x = points[0].x;
195      points[1].y = points[0].y - grid_size;
196      points[2].x = points[1].x - i;
197      points[2].y = points[1].y;
198      XFillPolygon (dpy, window, gc, points, 3, Convex, CoordModeOrigin);
199
200      XSync (dpy, True);
201      if (delay) usleep (delay);
202    }
203
204   XFillRectangle (dpy, window, gc,
205                   xoff + grid_size * hole_x,
206                   yoff + grid_size * hole_y,
207                   grid_size, grid_size);
208 }
209
210 static void
211 slide1 (dpy, window)
212      Display *dpy;
213      Window window;
214 {
215   /* this code is a total kludge, but who cares, it works... */
216  int i, x, y, ix, iy, dx, dy, dir, w, h, size, inc;
217  static int last = -1;
218  do {
219    dir = random () % 4;
220    switch (dir)
221      {
222      case 0: dx = 0,  dy = 1;  break;
223      case 1: dx = -1, dy = 0;  break;
224      case 2: dx = 0,  dy = -1; break;
225      case 3: dx = 1,  dy = 0;  break;
226      }
227  } while (dir == last ||
228           hole_x + dx < 0 || hole_x + dx >= grid_w ||
229           hole_y + dy < 0 || hole_y + dy >= grid_h);
230  if (grid_w > 1 && grid_h > 1)
231    last = (dir == 0 ? 2 : dir == 2 ? 0 : dir == 1 ? 3 : 1);
232
233  switch (dir)
234    {
235    case 0: size = 1 + (random()%(grid_h - hole_y - 1)); h = size; w = 1; break;
236    case 1: size = 1 + (random()%hole_x);                w = size; h = 1; break;
237    case 2: size = 1 + (random()%hole_y);                h = size; w = 1; break;
238    case 3: size = 1 + (random()%(grid_w - hole_x - 1)); w = size; h = 1; break;
239    }
240
241  if (dx == -1) hole_x -= (size - 1);
242  else if (dy == -1) hole_y -= (size - 1);
243
244  ix = x = xoff + (hole_x + dx) * grid_size;
245  iy = y = yoff + (hole_y + dy) * grid_size;
246  inc = pix_inc;
247  for (i = 0; i < grid_size; i += inc)
248    {
249      if (inc + i > grid_size)
250        inc = grid_size - i;
251      XCopyArea (dpy, window, window, gc, x, y, grid_size * w, grid_size * h,
252                 x - dx * inc, y - dy * inc);
253      x -= dx * inc;
254      y -= dy * inc;
255      switch (dir)
256        {
257        case 0: XFillRectangle (dpy, window, gc,
258                                ix, y + grid_size * h, grid_size * w, iy - y);
259          break;
260        case 1: XFillRectangle (dpy, window, gc, ix, iy, x - ix, grid_size * h);
261          break;
262        case 2: XFillRectangle (dpy, window, gc, ix, iy, grid_size * w, y - iy);
263          break;
264        case 3: XFillRectangle (dpy, window, gc,
265                                x + grid_size * w, iy, ix - x, grid_size * h);
266          break;
267        }
268
269      XSync (dpy, True);
270      if (delay) usleep (delay);
271    }
272  switch (dir)
273    {
274    case 0: hole_y += size; break;
275    case 1: hole_x--; break;
276    case 2: hole_y--; break;
277    case 3: hole_x += size; break;
278    }
279 }
280
281 \f
282 char *progclass = "SlidePuzzle";
283
284 char *defaults [] = {
285   "SlidePuzzle.mappedWhenManaged:false",
286   "SlidePuzzle.dontClearWindow:  true",
287   "*background:                 black",
288   "*gridSize:                   70",
289   "*pixelIncrement:             10",
290   "*internalBorderWidth:        1",
291   "*delay:                      50000",
292   "*delay2:                     1000000",
293   0
294 };
295
296 XrmOptionDescRec options [] = {
297   { "-grid-size",       ".gridSize",            XrmoptionSepArg, 0 },
298   { "-ibw",             ".internalBorderWidth", XrmoptionSepArg, 0 },
299   { "-increment",       ".pixelIncrement",      XrmoptionSepArg, 0 },
300   { "-delay",           ".delay",               XrmoptionSepArg, 0 },
301   { "-delay2",          ".delay2",              XrmoptionSepArg, 0 },
302 };
303
304 int options_size = (sizeof (options) / sizeof (options[0]));
305
306 void
307 screenhack (dpy, window)
308      Display *dpy;
309      Window window;
310 {
311   init_slide (dpy, window);
312   while (1)
313     {
314       slide1 (dpy, window);
315       if (delay2) usleep (delay2);
316     }
317 }