http://packetstormsecurity.org/UNIX/admin/xscreensaver-3.32.tar.gz
[xscreensaver] / hacks / slidescreen.c
1 /* xscreensaver, Copyright (c) 1992, 1993, 1994, 1996, 1997, 1998 
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   grab_screen_image (xgwa.screen, window);
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   {
52     XColor fgc, bgc;
53     char *fgs = get_string_resource("background", "Background");
54     char *bgs = get_string_resource("foreground", "Foreground");
55     Bool fg_ok, bg_ok;
56     if (!XParseColor (dpy, cmap, fgs, &fgc))
57       XParseColor (dpy, cmap, "black", &bgc);
58     if (!XParseColor (dpy, cmap, bgs, &bgc))
59       XParseColor (dpy, cmap, "gray", &fgc);
60
61     fg_ok = XAllocColor (dpy, cmap, &fgc);
62     bg_ok = XAllocColor (dpy, cmap, &bgc);
63
64     /* If we weren't able to allocate the two colors we want from the
65        colormap (which is likely if the screen has been grabbed on an
66        8-bit SGI visual -- don't ask) then just go through the map
67        and find the closest color to the ones we wanted, and use those
68        pixels without actually allocating them.
69      */
70     if (fg_ok)
71       fg = fgc.pixel;
72     else
73       fg = 0;
74
75     if (bg_ok)
76       bg = bgc.pixel;
77     else
78       bg = 1;
79
80     if (!fg_ok || bg_ok)
81       {
82         unsigned long fgd = ~0;
83         unsigned long bgd = ~0;
84         int max = visual_cells (xgwa.screen, visual);
85         XColor *all = (XColor *) calloc(sizeof (*all), max);
86         for (i = 0; i < max; i++)
87           {
88             all[i].flags = DoRed|DoGreen|DoBlue;
89             all[i].pixel = i;
90           }
91         XQueryColors (dpy, cmap, all, max);
92         for(i = 0; i < max; i++)
93           {
94             long rd, gd, bd;
95             unsigned long d;
96             if (!fg_ok)
97               {
98                 rd = (all[i].red   >> 8) - (fgc.red   >> 8);
99                 gd = (all[i].green >> 8) - (fgc.green >> 8);
100                 bd = (all[i].blue  >> 8) - (fgc.blue  >> 8);
101                 if (rd < 0) rd = -rd;
102                 if (gd < 0) gd = -gd;
103                 if (bd < 0) bd = -bd;
104                 d = (rd << 1) + (gd << 2) + bd;
105                 if (d < fgd)
106                   {
107                     fgd = d;
108                     fg = all[i].pixel;
109                     if (d == 0)
110                       fg_ok = True;
111                   }
112               }
113
114             if (!bg_ok)
115               {
116                 rd = (all[i].red   >> 8) - (bgc.red   >> 8);
117                 gd = (all[i].green >> 8) - (bgc.green >> 8);
118                 bd = (all[i].blue  >> 8) - (bgc.blue  >> 8);
119                 if (rd < 0) rd = -rd;
120                 if (gd < 0) gd = -gd;
121                 if (bd < 0) bd = -bd;
122                 d = (rd << 1) + (gd << 2) + bd;
123                 if (d < bgd)
124                   {
125                     bgd = d;
126                     bg = all[i].pixel;
127                     if (d == 0)
128                       bg_ok = True;
129                   }
130               }
131
132             if (fg_ok && bg_ok)
133               break;
134           }
135         XFree(all);
136       }
137   }
138
139
140   if (delay < 0) delay = 0;
141   if (delay2 < 0) delay2 = 0;
142   if (pix_inc < 1) pix_inc = 1;
143   if (grid_size < 1) grid_size = 1;
144
145   gcv.foreground = fg;
146   gcv.function = GXcopy;
147   gcv.subwindow_mode = IncludeInferiors;
148   gcflags = GCForeground |GCFunction;
149   if (use_subwindow_mode_p(xgwa.screen, window)) /* see grabscreen.c */
150     gcflags |= GCSubwindowMode;
151   gc = XCreateGC (dpy, window, gcflags, &gcv);
152
153   XGetWindowAttributes (dpy, window, &xgwa);
154   bitmap_w = xgwa.width;
155   bitmap_h = xgwa.height;
156
157   grid_w = bitmap_w / grid_size;
158   grid_h = bitmap_h / grid_size;
159   hole_x = random () % grid_w;
160   hole_y = random () % grid_h;
161   xoff = (bitmap_w - (grid_w * grid_size)) / 2;
162   yoff = (bitmap_h - (grid_h * grid_size)) / 2;
163
164   d = window;
165
166   if (border)
167     {
168       int half = border/2;
169       int half2 = (border & 1 ? half+1 : half);
170       XSetForeground(dpy, gc, bg);
171       for (i = 0; i < bitmap_w; i += grid_size)
172         {
173           int j;
174           for (j = 0; j < bitmap_h; j += grid_size)
175             XDrawRectangle (dpy, d, gc,
176                             xoff+i+half2, yoff+j+half2,
177                             grid_size-border-1, grid_size-border-1);
178         }
179
180       XSetForeground(dpy, gc, fg);
181       for (i = 0; i <= bitmap_w; i += grid_size)
182         XFillRectangle (dpy, d, gc, xoff+i-half, yoff, border, bitmap_h);
183       for (i = 0; i <= bitmap_h; i += grid_size)
184         XFillRectangle (dpy, d, gc, xoff, yoff+i-half, bitmap_w, border);
185     }
186
187   if (xoff)
188     {
189       XFillRectangle (dpy, d, gc, 0, 0, xoff, bitmap_h);
190       XFillRectangle (dpy, d, gc, bitmap_w - xoff, 0, xoff, bitmap_h);
191     }
192   if (yoff)
193     {
194       XFillRectangle (dpy, d, gc, 0, 0, bitmap_w, yoff);
195       XFillRectangle (dpy, d, gc, 0, bitmap_h - yoff, bitmap_w, yoff);
196     }
197
198   XSync (dpy, False);
199   if (delay2) usleep (delay2 * 2);
200  for (i = 0; i < grid_size; i += pix_inc)
201    {
202      XPoint points [3];
203      points[0].x = xoff + grid_size * hole_x;
204      points[0].y = yoff + grid_size * hole_y;
205      points[1].x = points[0].x + grid_size;
206      points[1].y = points[0].y;
207      points[2].x = points[0].x;
208      points[2].y = points[0].y + i;
209      XFillPolygon (dpy, window, gc, points, 3, Convex, CoordModeOrigin);
210
211      points[1].x = points[0].x;
212      points[1].y = points[0].y + grid_size;
213      points[2].x = points[0].x + i;
214      points[2].y = points[0].y + grid_size;
215      XFillPolygon (dpy, window, gc, points, 3, Convex, CoordModeOrigin);
216
217      points[0].x = points[1].x + grid_size;
218      points[0].y = points[1].y;
219      points[2].x = points[0].x;
220      points[2].y = points[0].y - i;
221      XFillPolygon (dpy, window, gc, points, 3, Convex, CoordModeOrigin);
222
223      points[1].x = points[0].x;
224      points[1].y = points[0].y - grid_size;
225      points[2].x = points[1].x - i;
226      points[2].y = points[1].y;
227      XFillPolygon (dpy, window, gc, points, 3, Convex, CoordModeOrigin);
228
229      XSync (dpy, False);
230      if (delay) usleep (delay);
231    }
232
233   XFillRectangle (dpy, window, gc,
234                   xoff + grid_size * hole_x,
235                   yoff + grid_size * hole_y,
236                   grid_size, grid_size);
237 }
238
239 static void
240 slide1 (Display *dpy, Window window)
241 {
242   /* this code is a total kludge, but who cares, it works... */
243  int i, x, y, ix, iy, dx, dy, dir, w, h, size, inc;
244  static int last = -1;
245  do {
246    dir = random () % 4;
247    switch (dir)
248      {
249      case 0: dx = 0,  dy = 1;  break;
250      case 1: dx = -1, dy = 0;  break;
251      case 2: dx = 0,  dy = -1; break;
252      case 3: dx = 1,  dy = 0;  break;
253      default: abort ();
254      }
255  } while (dir == last ||
256           hole_x + dx < 0 || hole_x + dx >= grid_w ||
257           hole_y + dy < 0 || hole_y + dy >= grid_h);
258  if (grid_w > 1 && grid_h > 1)
259    last = (dir == 0 ? 2 : dir == 2 ? 0 : dir == 1 ? 3 : 1);
260
261  switch (dir)
262    {
263    case 0: size = 1 + (random()%(grid_h - hole_y - 1)); h = size; w = 1; break;
264    case 1: size = 1 + (random()%hole_x);                w = size; h = 1; break;
265    case 2: size = 1 + (random()%hole_y);                h = size; w = 1; break;
266    case 3: size = 1 + (random()%(grid_w - hole_x - 1)); w = size; h = 1; break;
267    default: abort ();
268    }
269
270  if (dx == -1) hole_x -= (size - 1);
271  else if (dy == -1) hole_y -= (size - 1);
272
273  ix = x = xoff + (hole_x + dx) * grid_size;
274  iy = y = yoff + (hole_y + dy) * grid_size;
275  inc = pix_inc;
276  for (i = 0; i < grid_size; i += inc)
277    {
278      int fx, fy, tox, toy;
279      if (inc + i > grid_size)
280        inc = grid_size - i;
281      tox = x - dx * inc;
282      toy = y - dy * inc;
283
284      fx = (x < 0 ? 0 : x > max_width  ? max_width  : x);
285      fy = (y < 0 ? 0 : y > max_height ? max_height : y);
286      tox = (tox < 0 ? 0 : tox > max_width  ? max_width  : tox);
287      toy = (toy < 0 ? 0 : toy > max_height ? max_height : toy);
288
289      XCopyArea (dpy, window, window, gc,
290                 fx, fy,
291                 grid_size * w, grid_size * h,
292                 tox, toy);
293
294      x -= dx * inc;
295      y -= dy * inc;
296      switch (dir)
297        {
298        case 0: XFillRectangle (dpy, window, gc,
299                                ix, y + grid_size * h, grid_size * w, iy - y);
300          break;
301        case 1: XFillRectangle (dpy, window, gc, ix, iy, x - ix, grid_size * h);
302          break;
303        case 2: XFillRectangle (dpy, window, gc, ix, iy, grid_size * w, y - iy);
304          break;
305        case 3: XFillRectangle (dpy, window, gc,
306                                x + grid_size * w, iy, ix - x, grid_size * h);
307          break;
308        }
309
310      XSync (dpy, False);
311      if (delay) usleep (delay);
312    }
313  switch (dir)
314    {
315    case 0: hole_y += size; break;
316    case 1: hole_x--; break;
317    case 2: hole_y--; break;
318    case 3: hole_x += size; break;
319    }
320 }
321
322 \f
323 char *progclass = "SlidePuzzle";
324
325 char *defaults [] = {
326   "*dontClearRoot:              True",
327
328 #ifdef __sgi    /* really, HAVE_READ_DISPLAY_EXTENSION */
329   "*visualID:                   Best",
330 #endif
331
332   ".background:                 Black",
333   ".foreground:                 Gray",
334   "*gridSize:                   70",
335   "*pixelIncrement:             10",
336   "*internalBorderWidth:        4",
337   "*delay:                      50000",
338   "*delay2:                     1000000",
339   0
340 };
341
342 XrmOptionDescRec options [] = {
343   { "-grid-size",       ".gridSize",            XrmoptionSepArg, 0 },
344   { "-ibw",             ".internalBorderWidth", XrmoptionSepArg, 0 },
345   { "-increment",       ".pixelIncrement",      XrmoptionSepArg, 0 },
346   { "-delay",           ".delay",               XrmoptionSepArg, 0 },
347   { "-delay2",          ".delay2",              XrmoptionSepArg, 0 },
348   { 0, 0, 0, 0 }
349 };
350
351 void
352 screenhack (Display *dpy, Window window)
353 {
354   init_slide (dpy, window);
355   while (1)
356     {
357       slide1 (dpy, window);
358       screenhack_handle_events (dpy);
359       if (delay2) usleep (delay2);
360     }
361 }