1 /* xscreensaver, Copyright (c) 1992-2005 Jamie Zawinski <jwz@jwz.org>
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"
14 enum { DOWN = 0, LEFT, UP, RIGHT };
15 enum { VERTICAL, HORIZONTAL };
19 static int hole_x, hole_y;
20 static int bitmap_w, bitmap_h;
21 static int xoff, yoff;
22 static int grid_w, grid_h;
23 static int delay, delay2;
25 static int max_width, max_height;
28 init_slide (Display *dpy, Window window)
32 XWindowAttributes xgwa;
40 XGetWindowAttributes (dpy, window, &xgwa);
41 load_random_image (xgwa.screen, window, window, NULL, NULL);
44 max_width = xgwa.width;
45 max_height = xgwa.height;
47 delay = get_integer_resource ("delay", "Integer");
48 delay2 = get_integer_resource ("delay2", "Integer");
49 grid_size = get_integer_resource ("gridSize", "Integer");
50 pix_inc = get_integer_resource ("pixelIncrement", "Integer");
51 border = get_integer_resource ("internalBorderWidth", "InternalBorderWidth");
53 /* Don't let the grid be smaller than 3x3 */
54 if (grid_size > xgwa.width / 3)
55 grid_size = xgwa.width / 3;
56 if (grid_size > xgwa.height / 3)
57 grid_size = xgwa.height / 3;
61 char *fgs = get_string_resource("background", "Background");
62 char *bgs = get_string_resource("foreground", "Foreground");
64 if (!XParseColor (dpy, cmap, fgs, &fgc))
65 XParseColor (dpy, cmap, "black", &bgc);
66 if (!XParseColor (dpy, cmap, bgs, &bgc))
67 XParseColor (dpy, cmap, "gray", &fgc);
69 fg_ok = XAllocColor (dpy, cmap, &fgc);
70 bg_ok = XAllocColor (dpy, cmap, &bgc);
72 /* If we weren't able to allocate the two colors we want from the
73 colormap (which is likely if the screen has been grabbed on an
74 8-bit SGI visual -- don't ask) then just go through the map
75 and find the closest color to the ones we wanted, and use those
76 pixels without actually allocating them.
90 unsigned long fgd = ~0;
91 unsigned long bgd = ~0;
92 int max = visual_cells (xgwa.screen, visual);
93 XColor *all = (XColor *) calloc(sizeof (*all), max);
94 for (i = 0; i < max; i++)
96 all[i].flags = DoRed|DoGreen|DoBlue;
99 XQueryColors (dpy, cmap, all, max);
100 for(i = 0; i < max; i++)
106 rd = (all[i].red >> 8) - (fgc.red >> 8);
107 gd = (all[i].green >> 8) - (fgc.green >> 8);
108 bd = (all[i].blue >> 8) - (fgc.blue >> 8);
109 if (rd < 0) rd = -rd;
110 if (gd < 0) gd = -gd;
111 if (bd < 0) bd = -bd;
112 dd = (rd << 1) + (gd << 2) + bd;
124 rd = (all[i].red >> 8) - (bgc.red >> 8);
125 gd = (all[i].green >> 8) - (bgc.green >> 8);
126 bd = (all[i].blue >> 8) - (bgc.blue >> 8);
127 if (rd < 0) rd = -rd;
128 if (gd < 0) gd = -gd;
129 if (bd < 0) bd = -bd;
130 dd = (rd << 1) + (gd << 2) + bd;
148 if (delay < 0) delay = 0;
149 if (delay2 < 0) delay2 = 0;
150 if (pix_inc < 1) pix_inc = 1;
151 if (grid_size < 1) grid_size = 1;
154 gcv.function = GXcopy;
155 gcv.subwindow_mode = IncludeInferiors;
156 gcflags = GCForeground |GCFunction;
157 if (use_subwindow_mode_p(xgwa.screen, window)) /* see grabscreen.c */
158 gcflags |= GCSubwindowMode;
159 gc = XCreateGC (dpy, window, gcflags, &gcv);
161 XGetWindowAttributes (dpy, window, &xgwa);
162 bitmap_w = xgwa.width;
163 bitmap_h = xgwa.height;
165 grid_w = bitmap_w / grid_size;
166 grid_h = bitmap_h / grid_size;
167 hole_x = random () % grid_w;
168 hole_y = random () % grid_h;
169 xoff = (bitmap_w - (grid_w * grid_size)) / 2;
170 yoff = (bitmap_h - (grid_h * grid_size)) / 2;
177 int half2 = (border & 1 ? half+1 : half);
178 XSetForeground(dpy, gc, bg);
179 for (i = 0; i < bitmap_w; i += grid_size)
182 for (j = 0; j < bitmap_h; j += grid_size)
183 XDrawRectangle (dpy, d, gc,
184 xoff+i+half2, yoff+j+half2,
185 grid_size-border-1, grid_size-border-1);
188 XSetForeground(dpy, gc, fg);
189 for (i = 0; i <= bitmap_w; i += grid_size)
190 XFillRectangle (dpy, d, gc, xoff+i-half, yoff, border, bitmap_h);
191 for (i = 0; i <= bitmap_h; i += grid_size)
192 XFillRectangle (dpy, d, gc, xoff, yoff+i-half, bitmap_w, border);
197 XFillRectangle (dpy, d, gc, 0, 0, xoff, bitmap_h);
198 XFillRectangle (dpy, d, gc, bitmap_w - xoff, 0, xoff, bitmap_h);
202 XFillRectangle (dpy, d, gc, 0, 0, bitmap_w, yoff);
203 XFillRectangle (dpy, d, gc, 0, bitmap_h - yoff, bitmap_w, yoff);
207 if (delay2) usleep (delay2);
208 for (i = 0; i < grid_size; i += pix_inc)
211 points[0].x = xoff + grid_size * hole_x;
212 points[0].y = yoff + grid_size * hole_y;
213 points[1].x = points[0].x + grid_size;
214 points[1].y = points[0].y;
215 points[2].x = points[0].x;
216 points[2].y = points[0].y + i;
217 XFillPolygon (dpy, window, gc, points, 3, Convex, CoordModeOrigin);
219 points[1].x = points[0].x;
220 points[1].y = points[0].y + grid_size;
221 points[2].x = points[0].x + i;
222 points[2].y = points[0].y + grid_size;
223 XFillPolygon (dpy, window, gc, points, 3, Convex, CoordModeOrigin);
225 points[0].x = points[1].x + grid_size;
226 points[0].y = points[1].y;
227 points[2].x = points[0].x;
228 points[2].y = points[0].y - i;
229 XFillPolygon (dpy, window, gc, points, 3, Convex, CoordModeOrigin);
231 points[1].x = points[0].x;
232 points[1].y = points[0].y - grid_size;
233 points[2].x = points[1].x - i;
234 points[2].y = points[1].y;
235 XFillPolygon (dpy, window, gc, points, 3, Convex, CoordModeOrigin);
238 if (delay) usleep (delay);
241 XFillRectangle (dpy, window, gc,
242 xoff + grid_size * hole_x,
243 yoff + grid_size * hole_y,
244 grid_size, grid_size);
247 if (delay2) usleep (delay2);
251 slide1 (Display *dpy, Window window)
253 /* this code is a total kludge, but who cares, it works... */
254 int rnd, i, x, y, ix, iy, dx, dy, dir, w, h, size, inc;
255 static int last = -1;
257 if (last == -1) last = random () % 2;
259 /* alternate between horizontal and vertical slides */
260 /* note that dir specifies the direction the _hole_ moves, not the tiles */
261 if (last == VERTICAL) {
262 if ((rnd = random () % (grid_w - 1)) < hole_x) {
263 dx = -1; dir = LEFT; hole_x -= rnd;
265 dx = 1; dir = RIGHT; rnd -= hole_x;
267 dy = 0; w = size = rnd + 1; h = 1;
270 if ((rnd = random () % (grid_h - 1)) < hole_y) {
271 dy = -1; dir = UP; hole_y -= rnd;
273 dy = 1; dir = DOWN; rnd -= hole_y;
275 dx = 0; h = size = rnd + 1; w = 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 DOWN: XFillRectangle (dpy, window, gc,
305 ix, y + grid_size * h, grid_size * w, iy - y);
307 case LEFT: XFillRectangle (dpy, window, gc, ix, iy, x - ix, grid_size * h);
309 case UP: XFillRectangle (dpy, window, gc, ix, iy, grid_size * w, y - iy);
311 case RIGHT: XFillRectangle (dpy, window, gc,
312 x + grid_size * w, iy, ix - x, grid_size * h);
317 if (delay) usleep (delay);
321 case DOWN: hole_y += size; break;
322 case LEFT: hole_x--; break;
323 case UP: hole_y--; break;
324 case RIGHT: 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);