source: trunk/third/xscreensaver/hacks/slidescreen.c @ 20148

Revision 20148, 9.9 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20147, which included commits to RCS files with non-trunk default branches.
Line 
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
15static int grid_size;
16static int pix_inc;
17static int hole_x, hole_y;
18static int bitmap_w, bitmap_h;
19static int xoff, yoff;
20static int grid_w, grid_h;
21static int delay, delay2;
22static GC gc;
23static int max_width, max_height;
24
25static void
26init_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
245static void
246slide1 (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
329char *progclass = "SlidePuzzle";
330
331char *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
348XrmOptionDescRec 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
357void
358screenhack (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}
Note: See TracBrowser for help on using the repository browser.