http://packetstormsecurity.org/UNIX/admin/xscreensaver-4.14.tar.gz
[xscreensaver] / hacks / slidescreen.c
1 /* xscreensaver, Copyright (c) 1992, 1993, 1994, 1996, 1997, 1998, 2001, 2003 
2  * Jamie Zawinski <jwz@jwz.org>
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 static 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   long gcflags;
32   int border;
33   unsigned long fg, bg;
34   Drawable d;
35   Colormap cmap;
36   Visual *visual;
37
38   XGetWindowAttributes (dpy, window, &xgwa);
39   load_random_image (xgwa.screen, window, window, NULL);
40   cmap = xgwa.colormap;
41   visual = xgwa.visual;
42   max_width = xgwa.width;
43   max_height = xgwa.height;
44
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");
50
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;
56
57   {
58     XColor fgc, bgc;
59     char *fgs = get_string_resource("background", "Background");
60     char *bgs = get_string_resource("foreground", "Foreground");
61     Bool fg_ok, bg_ok;
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);
66
67     fg_ok = XAllocColor (dpy, cmap, &fgc);
68     bg_ok = XAllocColor (dpy, cmap, &bgc);
69
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.
75      */
76     if (fg_ok)
77       fg = fgc.pixel;
78     else
79       fg = 0;
80
81     if (bg_ok)
82       bg = bgc.pixel;
83     else
84       bg = 1;
85
86     if (!fg_ok || bg_ok)
87       {
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++)
93           {
94             all[i].flags = DoRed|DoGreen|DoBlue;
95             all[i].pixel = i;
96           }
97         XQueryColors (dpy, cmap, all, max);
98         for(i = 0; i < max; i++)
99           {
100             long rd, gd, bd;
101             unsigned long dd;
102             if (!fg_ok)
103               {
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;
111                 if (dd < fgd)
112                   {
113                     fgd = dd;
114                     fg = all[i].pixel;
115                     if (dd == 0)
116                       fg_ok = True;
117                   }
118               }
119
120             if (!bg_ok)
121               {
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;
129                 if (dd < bgd)
130                   {
131                     bgd = dd;
132                     bg = all[i].pixel;
133                     if (dd == 0)
134                       bg_ok = True;
135                   }
136               }
137
138             if (fg_ok && bg_ok)
139               break;
140           }
141         XFree(all);
142       }
143   }
144
145
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;
150
151   gcv.foreground = fg;
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);
158
159   XGetWindowAttributes (dpy, window, &xgwa);
160   bitmap_w = xgwa.width;
161   bitmap_h = xgwa.height;
162
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;
169
170   d = window;
171
172   if (border)
173     {
174       int half = border/2;
175       int half2 = (border & 1 ? half+1 : half);
176       XSetForeground(dpy, gc, bg);
177       for (i = 0; i < bitmap_w; i += grid_size)
178         {
179           int j;
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);
184         }
185
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);
191     }
192
193   if (xoff)
194     {
195       XFillRectangle (dpy, d, gc, 0, 0, xoff, bitmap_h);
196       XFillRectangle (dpy, d, gc, bitmap_w - xoff, 0, xoff, bitmap_h);
197     }
198   if (yoff)
199     {
200       XFillRectangle (dpy, d, gc, 0, 0, bitmap_w, yoff);
201       XFillRectangle (dpy, d, gc, 0, bitmap_h - yoff, bitmap_w, yoff);
202     }
203
204   XSync (dpy, False);
205   if (delay2) usleep (delay2 * 2);
206  for (i = 0; i < grid_size; i += pix_inc)
207    {
208      XPoint points [3];
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);
216
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);
222
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);
228
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);
234
235      XSync (dpy, False);
236      if (delay) usleep (delay);
237    }
238
239   XFillRectangle (dpy, window, gc,
240                   xoff + grid_size * hole_x,
241                   yoff + grid_size * hole_y,
242                   grid_size, grid_size);
243 }
244
245 static void
246 slide1 (Display *dpy, Window window)
247 {
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;
251  do {
252    dir = random () % 4;
253    switch (dir)
254      {
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;
259      default: abort ();
260      }
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);
266
267  switch (dir)
268    {
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;
273    default: abort ();
274    }
275
276  if (dx == -1) hole_x -= (size - 1);
277  else if (dy == -1) hole_y -= (size - 1);
278
279  ix = x = xoff + (hole_x + dx) * grid_size;
280  iy = y = yoff + (hole_y + dy) * grid_size;
281  inc = pix_inc;
282  for (i = 0; i < grid_size; i += inc)
283    {
284      int fx, fy, tox, toy;
285      if (inc + i > grid_size)
286        inc = grid_size - i;
287      tox = x - dx * inc;
288      toy = y - dy * inc;
289
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);
294
295      XCopyArea (dpy, window, window, gc,
296                 fx, fy,
297                 grid_size * w, grid_size * h,
298                 tox, toy);
299
300      x -= dx * inc;
301      y -= dy * inc;
302      switch (dir)
303        {
304        case 0: XFillRectangle (dpy, window, gc,
305                                ix, y + grid_size * h, grid_size * w, iy - y);
306          break;
307        case 1: XFillRectangle (dpy, window, gc, ix, iy, x - ix, grid_size * h);
308          break;
309        case 2: XFillRectangle (dpy, window, gc, ix, iy, grid_size * w, y - iy);
310          break;
311        case 3: XFillRectangle (dpy, window, gc,
312                                x + grid_size * w, iy, ix - x, grid_size * h);
313          break;
314        }
315
316      XSync (dpy, False);
317      if (delay) usleep (delay);
318    }
319  switch (dir)
320    {
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;
325    }
326 }
327
328 \f
329 char *progclass = "SlidePuzzle";
330
331 char *defaults [] = {
332   "*dontClearRoot:              True",
333
334 #ifdef __sgi    /* really, HAVE_READ_DISPLAY_EXTENSION */
335   "*visualID:                   Best",
336 #endif
337
338   ".background:                 Black",
339   ".foreground:                 Gray",
340   "*gridSize:                   70",
341   "*pixelIncrement:             10",
342   "*internalBorderWidth:        4",
343   "*delay:                      50000",
344   "*delay2:                     1000000",
345   0
346 };
347
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 },
354   { 0, 0, 0, 0 }
355 };
356
357 void
358 screenhack (Display *dpy, Window window)
359 {
360   init_slide (dpy, window);
361   while (1)
362     {
363       slide1 (dpy, window);
364       screenhack_handle_events (dpy);
365       if (delay2) usleep (delay2);
366     }
367 }