1 /* xscreensaver, Copyright (c) 1992, 1993 Jamie Zawinski <jwz@lucid.com>
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
12 #include "screenhack.h"
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;
24 MapNotify_event_p (dpy, event, window)
29 return (event->xany.type == MapNotify &&
30 event->xvisibility.window == (Window) window);
35 screensaver_window_p (dpy, window)
41 unsigned long nitems, bytesafter;
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)
56 init_slide (dpy, window)
63 XWindowAttributes xgwa;
71 XGetWindowAttributes (dpy, window, &xgwa);
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");
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;
88 gcv.function = GXcopy;
89 gcv.subwindow_mode = IncludeInferiors;
90 gc = XCreateGC (dpy, window, GCForeground |GCFunction | GCSubwindowMode,
93 if (screensaver_window_p (dpy, window))
95 /* note: this assumes vroot.h didn't encapsulate the XRootWindowOfScreen
96 function, only the RootWindowOfScreen macro... */
97 Window real_root = XRootWindowOfScreen (DefaultScreenOfDisplay (dpy));
99 XSetWindowBackgroundPixmap (dpy, window, None);
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,
109 XUnmapWindow (dpy, window);
111 sleep (5); /* wait for everyone to swap in and handle exposes... */
112 XMapWindow (dpy, window);
114 XUngrabPointer (dpy, CurrentTime);
115 XUngrabKeyboard (dpy, CurrentTime);
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);
128 XSetWindowBackgroundPixmap (dpy, window, None);
129 XMapWindow (dpy, window);
131 XIfEvent (dpy, &event, MapNotify_event_p, (XPointer) window);
135 XGetWindowAttributes (dpy, window, &xgwa);
136 bitmap_w = xgwa.width;
137 bitmap_h = xgwa.height;
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;
146 d = (pixmap ? pixmap : window);
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);
159 XFillRectangle (dpy, d, gc, 0, 0, xoff, bitmap_h);
160 XFillRectangle (dpy, d, gc, bitmap_w - xoff, 0, xoff, bitmap_h);
164 XFillRectangle (dpy, d, gc, 0, 0, bitmap_w, yoff);
165 XFillRectangle (dpy, d, gc, 0, bitmap_h - yoff, bitmap_w, yoff);
168 if (pixmap) XClearWindow (dpy, window);
170 if (delay2) usleep (delay2 * 2);
171 for (i = 0; i < grid_size; i += pix_inc)
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);
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);
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);
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);
201 if (delay) usleep (delay);
204 XFillRectangle (dpy, window, gc,
205 xoff + grid_size * hole_x,
206 yoff + grid_size * hole_y,
207 grid_size, grid_size);
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;
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;
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);
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;
241 if (dx == -1) hole_x -= (size - 1);
242 else if (dy == -1) hole_y -= (size - 1);
244 ix = x = xoff + (hole_x + dx) * grid_size;
245 iy = y = yoff + (hole_y + dy) * grid_size;
247 for (i = 0; i < grid_size; i += inc)
249 if (inc + i > grid_size)
251 XCopyArea (dpy, window, window, gc, x, y, grid_size * w, grid_size * h,
252 x - dx * inc, y - dy * inc);
257 case 0: XFillRectangle (dpy, window, gc,
258 ix, y + grid_size * h, grid_size * w, iy - y);
260 case 1: XFillRectangle (dpy, window, gc, ix, iy, x - ix, grid_size * h);
262 case 2: XFillRectangle (dpy, window, gc, ix, iy, grid_size * w, y - iy);
264 case 3: XFillRectangle (dpy, window, gc,
265 x + grid_size * w, iy, ix - x, grid_size * h);
270 if (delay) usleep (delay);
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;
282 char *progclass = "SlidePuzzle";
284 char *defaults [] = {
285 "SlidePuzzle.mappedWhenManaged:false",
286 "SlidePuzzle.dontClearWindow: true",
287 "*background: black",
289 "*pixelIncrement: 10",
290 "*internalBorderWidth: 1",
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 },
304 int options_size = (sizeof (options) / sizeof (options[0]));
307 screenhack (dpy, window)
311 init_slide (dpy, window);
314 slide1 (dpy, window);
315 if (delay2) usleep (delay2);