1 /* xscreensaver, Copyright (c) 1992, 1993, 1994, 1996, 1997, 1998, 2001, 2003
2 * Jamie Zawinski <jwz@jwz.org>
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
13 #include "screenhack.h"
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;
23 static int max_width, max_height;
26 init_slide (Display *dpy, Window window)
30 XWindowAttributes xgwa;
38 XGetWindowAttributes (dpy, window, &xgwa);
39 load_random_image (xgwa.screen, window, window, NULL);
42 max_width = xgwa.width;
43 max_height = xgwa.height;
45 delay = get_integer_resource ("delay", "Integer");
46 delay2 = get_integer_resource ("delay2", "Integer");
47 grid_size = get_integer_resource ("gridSize", "Integer");
48 pix_inc = get_integer_resource ("pixelIncrement", "Integer");
49 border = get_integer_resource ("internalBorderWidth", "InternalBorderWidth");
51 /* Don't let the grid be smaller than 3x3 */
52 if (grid_size > xgwa.width / 3)
53 grid_size = xgwa.width / 3;
54 if (grid_size > xgwa.height / 3)
55 grid_size = xgwa.height / 3;
59 char *fgs = get_string_resource("background", "Background");
60 char *bgs = get_string_resource("foreground", "Foreground");
62 if (!XParseColor (dpy, cmap, fgs, &fgc))
63 XParseColor (dpy, cmap, "black", &bgc);
64 if (!XParseColor (dpy, cmap, bgs, &bgc))
65 XParseColor (dpy, cmap, "gray", &fgc);
67 fg_ok = XAllocColor (dpy, cmap, &fgc);
68 bg_ok = XAllocColor (dpy, cmap, &bgc);
70 /* If we weren't able to allocate the two colors we want from the
71 colormap (which is likely if the screen has been grabbed on an
72 8-bit SGI visual -- don't ask) then just go through the map
73 and find the closest color to the ones we wanted, and use those
74 pixels without actually allocating them.
88 unsigned long fgd = ~0;
89 unsigned long bgd = ~0;
90 int max = visual_cells (xgwa.screen, visual);
91 XColor *all = (XColor *) calloc(sizeof (*all), max);
92 for (i = 0; i < max; i++)
94 all[i].flags = DoRed|DoGreen|DoBlue;
97 XQueryColors (dpy, cmap, all, max);
98 for(i = 0; i < max; i++)
104 rd = (all[i].red >> 8) - (fgc.red >> 8);
105 gd = (all[i].green >> 8) - (fgc.green >> 8);
106 bd = (all[i].blue >> 8) - (fgc.blue >> 8);
107 if (rd < 0) rd = -rd;
108 if (gd < 0) gd = -gd;
109 if (bd < 0) bd = -bd;
110 dd = (rd << 1) + (gd << 2) + bd;
122 rd = (all[i].red >> 8) - (bgc.red >> 8);
123 gd = (all[i].green >> 8) - (bgc.green >> 8);
124 bd = (all[i].blue >> 8) - (bgc.blue >> 8);
125 if (rd < 0) rd = -rd;
126 if (gd < 0) gd = -gd;
127 if (bd < 0) bd = -bd;
128 dd = (rd << 1) + (gd << 2) + bd;
146 if (delay < 0) delay = 0;
147 if (delay2 < 0) delay2 = 0;
148 if (pix_inc < 1) pix_inc = 1;
149 if (grid_size < 1) grid_size = 1;
152 gcv.function = GXcopy;
153 gcv.subwindow_mode = IncludeInferiors;
154 gcflags = GCForeground |GCFunction;
155 if (use_subwindow_mode_p(xgwa.screen, window)) /* see grabscreen.c */
156 gcflags |= GCSubwindowMode;
157 gc = XCreateGC (dpy, window, gcflags, &gcv);
159 XGetWindowAttributes (dpy, window, &xgwa);
160 bitmap_w = xgwa.width;
161 bitmap_h = xgwa.height;
163 grid_w = bitmap_w / grid_size;
164 grid_h = bitmap_h / grid_size;
165 hole_x = random () % grid_w;
166 hole_y = random () % grid_h;
167 xoff = (bitmap_w - (grid_w * grid_size)) / 2;
168 yoff = (bitmap_h - (grid_h * grid_size)) / 2;
175 int half2 = (border & 1 ? half+1 : half);
176 XSetForeground(dpy, gc, bg);
177 for (i = 0; i < bitmap_w; i += grid_size)
180 for (j = 0; j < bitmap_h; j += grid_size)
181 XDrawRectangle (dpy, d, gc,
182 xoff+i+half2, yoff+j+half2,
183 grid_size-border-1, grid_size-border-1);
186 XSetForeground(dpy, gc, fg);
187 for (i = 0; i <= bitmap_w; i += grid_size)
188 XFillRectangle (dpy, d, gc, xoff+i-half, yoff, border, bitmap_h);
189 for (i = 0; i <= bitmap_h; i += grid_size)
190 XFillRectangle (dpy, d, gc, xoff, yoff+i-half, bitmap_w, border);
195 XFillRectangle (dpy, d, gc, 0, 0, xoff, bitmap_h);
196 XFillRectangle (dpy, d, gc, bitmap_w - xoff, 0, xoff, bitmap_h);
200 XFillRectangle (dpy, d, gc, 0, 0, bitmap_w, yoff);
201 XFillRectangle (dpy, d, gc, 0, bitmap_h - yoff, bitmap_w, yoff);
205 if (delay2) usleep (delay2 * 2);
206 for (i = 0; i < grid_size; i += pix_inc)
209 points[0].x = xoff + grid_size * hole_x;
210 points[0].y = yoff + grid_size * hole_y;
211 points[1].x = points[0].x + grid_size;
212 points[1].y = points[0].y;
213 points[2].x = points[0].x;
214 points[2].y = points[0].y + i;
215 XFillPolygon (dpy, window, gc, points, 3, Convex, CoordModeOrigin);
217 points[1].x = points[0].x;
218 points[1].y = points[0].y + grid_size;
219 points[2].x = points[0].x + i;
220 points[2].y = points[0].y + grid_size;
221 XFillPolygon (dpy, window, gc, points, 3, Convex, CoordModeOrigin);
223 points[0].x = points[1].x + grid_size;
224 points[0].y = points[1].y;
225 points[2].x = points[0].x;
226 points[2].y = points[0].y - i;
227 XFillPolygon (dpy, window, gc, points, 3, Convex, CoordModeOrigin);
229 points[1].x = points[0].x;
230 points[1].y = points[0].y - grid_size;
231 points[2].x = points[1].x - i;
232 points[2].y = points[1].y;
233 XFillPolygon (dpy, window, gc, points, 3, Convex, CoordModeOrigin);
236 if (delay) usleep (delay);
239 XFillRectangle (dpy, window, gc,
240 xoff + grid_size * hole_x,
241 yoff + grid_size * hole_y,
242 grid_size, grid_size);
246 slide1 (Display *dpy, Window window)
248 /* this code is a total kludge, but who cares, it works... */
249 int i, x, y, ix, iy, dx, dy, dir, w, h, size, inc;
250 static int last = -1;
255 case 0: dx = 0, dy = 1; break;
256 case 1: dx = -1, dy = 0; break;
257 case 2: dx = 0, dy = -1; break;
258 case 3: dx = 1, dy = 0; break;
261 } while (dir == last ||
262 hole_x + dx < 0 || hole_x + dx >= grid_w ||
263 hole_y + dy < 0 || hole_y + dy >= grid_h);
264 if (grid_w > 1 && grid_h > 1)
265 last = (dir == 0 ? 2 : dir == 2 ? 0 : dir == 1 ? 3 : 1);
269 case 0: size = 1 + (random()%(grid_h - hole_y - 1)); h = size; w = 1; break;
270 case 1: size = 1 + (random()%hole_x); w = size; h = 1; break;
271 case 2: size = 1 + (random()%hole_y); h = size; w = 1; break;
272 case 3: size = 1 + (random()%(grid_w - hole_x - 1)); w = size; h = 1; break;
276 if (dx == -1) hole_x -= (size - 1);
277 else if (dy == -1) hole_y -= (size - 1);
279 ix = x = xoff + (hole_x + dx) * grid_size;
280 iy = y = yoff + (hole_y + dy) * grid_size;
282 for (i = 0; i < grid_size; i += inc)
284 int fx, fy, tox, toy;
285 if (inc + i > grid_size)
290 fx = (x < 0 ? 0 : x > max_width ? max_width : x);
291 fy = (y < 0 ? 0 : y > max_height ? max_height : y);
292 tox = (tox < 0 ? 0 : tox > max_width ? max_width : tox);
293 toy = (toy < 0 ? 0 : toy > max_height ? max_height : toy);
295 XCopyArea (dpy, window, window, gc,
297 grid_size * w, grid_size * h,
304 case 0: XFillRectangle (dpy, window, gc,
305 ix, y + grid_size * h, grid_size * w, iy - y);
307 case 1: XFillRectangle (dpy, window, gc, ix, iy, x - ix, grid_size * h);
309 case 2: XFillRectangle (dpy, window, gc, ix, iy, grid_size * w, y - iy);
311 case 3: XFillRectangle (dpy, window, gc,
312 x + grid_size * w, iy, ix - x, grid_size * h);
317 if (delay) usleep (delay);
321 case 0: hole_y += size; break;
322 case 1: hole_x--; break;
323 case 2: hole_y--; break;
324 case 3: hole_x += size; break;
329 char *progclass = "SlidePuzzle";
331 char *defaults [] = {
332 "*dontClearRoot: True",
334 #ifdef __sgi /* really, HAVE_READ_DISPLAY_EXTENSION */
338 ".background: Black",
341 "*pixelIncrement: 10",
342 "*internalBorderWidth: 4",
348 XrmOptionDescRec options [] = {
349 { "-grid-size", ".gridSize", XrmoptionSepArg, 0 },
350 { "-ibw", ".internalBorderWidth", XrmoptionSepArg, 0 },
351 { "-increment", ".pixelIncrement", XrmoptionSepArg, 0 },
352 { "-delay", ".delay", XrmoptionSepArg, 0 },
353 { "-delay2", ".delay2", XrmoptionSepArg, 0 },
358 screenhack (Display *dpy, Window window)
360 init_slide (dpy, window);
363 slide1 (dpy, window);
364 screenhack_handle_events (dpy);
365 if (delay2) usleep (delay2);