ftp://ftp.krokus.ru/pub/OpenBSD/distfiles/xscreensaver-4.22.tar.gz
[xscreensaver] / hacks / slidescreen.c
index a3792cd08f9ecfe214bbc600727217fbf287b5ba..22c7fe28cc7982368ca3f7128006516cce4deef3 100644 (file)
@@ -1,5 +1,4 @@
-/* xscreensaver, Copyright (c) 1992, 1993, 1994, 1996, 1997 
- * Jamie Zawinski <jwz@netscape.com>
+/* xscreensaver, Copyright (c) 1992-2005 Jamie Zawinski <jwz@jwz.org>
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
@@ -12,6 +11,9 @@
 
 #include "screenhack.h"
 
+enum { DOWN = 0, LEFT, UP, RIGHT };
+enum { VERTICAL, HORIZONTAL };
+
 static int grid_size;
 static int pix_inc;
 static int hole_x, hole_y;
@@ -20,7 +22,7 @@ static int xoff, yoff;
 static int grid_w, grid_h;
 static int delay, delay2;
 static GC gc;
-int max_width, max_height;
+static int max_width, max_height;
 
 static void
 init_slide (Display *dpy, Window window)
@@ -28,13 +30,15 @@ init_slide (Display *dpy, Window window)
   int i;
   XGCValues gcv;
   XWindowAttributes xgwa;
+  long gcflags;
   int border;
-  unsigned long fg;
+  unsigned long fg, bg;
   Drawable d;
   Colormap cmap;
   Visual *visual;
 
   XGetWindowAttributes (dpy, window, &xgwa);
+  load_random_image (xgwa.screen, window, window, NULL, NULL);
   cmap = xgwa.colormap;
   visual = xgwa.visual;
   max_width = xgwa.width;
@@ -45,17 +49,100 @@ init_slide (Display *dpy, Window window)
   grid_size = get_integer_resource ("gridSize", "Integer");
   pix_inc = get_integer_resource ("pixelIncrement", "Integer");
   border = get_integer_resource ("internalBorderWidth", "InternalBorderWidth");
-  fg = get_pixel_resource ("background", "Background", dpy, cmap);
-
-  grab_screen_image (xgwa.screen, window);
-
 
-  /* Total kludge -- if grab_screen_image() installed a new colormap, assume
-     that pixel 0 is the one we should use.  This further assumes that the
-     pixel is black, which overrides the user's -background setting, alas.
-   */
-  XGetWindowAttributes (dpy, window, &xgwa);
-  if (cmap != xgwa.colormap) fg = 0;
+  /* Don't let the grid be smaller than 3x3 */
+  if (grid_size > xgwa.width / 3)
+    grid_size = xgwa.width / 3;
+  if (grid_size > xgwa.height / 3)
+    grid_size = xgwa.height / 3;
+
+  {
+    XColor fgc, bgc;
+    char *fgs = get_string_resource("background", "Background");
+    char *bgs = get_string_resource("foreground", "Foreground");
+    Bool fg_ok, bg_ok;
+    if (!XParseColor (dpy, cmap, fgs, &fgc))
+      XParseColor (dpy, cmap, "black", &bgc);
+    if (!XParseColor (dpy, cmap, bgs, &bgc))
+      XParseColor (dpy, cmap, "gray", &fgc);
+
+    fg_ok = XAllocColor (dpy, cmap, &fgc);
+    bg_ok = XAllocColor (dpy, cmap, &bgc);
+
+    /* If we weren't able to allocate the two colors we want from the
+       colormap (which is likely if the screen has been grabbed on an
+       8-bit SGI visual -- don't ask) then just go through the map
+       and find the closest color to the ones we wanted, and use those
+       pixels without actually allocating them.
+     */
+    if (fg_ok)
+      fg = fgc.pixel;
+    else
+      fg = 0;
+
+    if (bg_ok)
+      bg = bgc.pixel;
+    else
+      bg = 1;
+
+    if (!fg_ok || bg_ok)
+      {
+       unsigned long fgd = ~0;
+       unsigned long bgd = ~0;
+       int max = visual_cells (xgwa.screen, visual);
+       XColor *all = (XColor *) calloc(sizeof (*all), max);
+       for (i = 0; i < max; i++)
+         {
+           all[i].flags = DoRed|DoGreen|DoBlue;
+           all[i].pixel = i;
+         }
+       XQueryColors (dpy, cmap, all, max);
+       for(i = 0; i < max; i++)
+         {
+           long rd, gd, bd;
+           unsigned long dd;
+           if (!fg_ok)
+             {
+               rd = (all[i].red   >> 8) - (fgc.red   >> 8);
+               gd = (all[i].green >> 8) - (fgc.green >> 8);
+               bd = (all[i].blue  >> 8) - (fgc.blue  >> 8);
+               if (rd < 0) rd = -rd;
+               if (gd < 0) gd = -gd;
+               if (bd < 0) bd = -bd;
+               dd = (rd << 1) + (gd << 2) + bd;
+               if (dd < fgd)
+                 {
+                   fgd = dd;
+                   fg = all[i].pixel;
+                   if (dd == 0)
+                     fg_ok = True;
+                 }
+             }
+
+           if (!bg_ok)
+             {
+               rd = (all[i].red   >> 8) - (bgc.red   >> 8);
+               gd = (all[i].green >> 8) - (bgc.green >> 8);
+               bd = (all[i].blue  >> 8) - (bgc.blue  >> 8);
+               if (rd < 0) rd = -rd;
+               if (gd < 0) gd = -gd;
+               if (bd < 0) bd = -bd;
+               dd = (rd << 1) + (gd << 2) + bd;
+               if (dd < bgd)
+                 {
+                   bgd = dd;
+                   bg = all[i].pixel;
+                   if (dd == 0)
+                     bg_ok = True;
+                 }
+             }
+
+           if (fg_ok && bg_ok)
+             break;
+         }
+       XFree(all);
+      }
+  }
 
 
   if (delay < 0) delay = 0;
@@ -66,8 +153,10 @@ init_slide (Display *dpy, Window window)
   gcv.foreground = fg;
   gcv.function = GXcopy;
   gcv.subwindow_mode = IncludeInferiors;
-  gc = XCreateGC (dpy, window, GCForeground |GCFunction | GCSubwindowMode,
-                 &gcv);
+  gcflags = GCForeground |GCFunction;
+  if (use_subwindow_mode_p(xgwa.screen, window)) /* see grabscreen.c */
+    gcflags |= GCSubwindowMode;
+  gc = XCreateGC (dpy, window, gcflags, &gcv);
 
   XGetWindowAttributes (dpy, window, &xgwa);
   bitmap_w = xgwa.width;
@@ -84,10 +173,23 @@ init_slide (Display *dpy, Window window)
 
   if (border)
     {
+      int half = border/2;
+      int half2 = (border & 1 ? half+1 : half);
+      XSetForeground(dpy, gc, bg);
+      for (i = 0; i < bitmap_w; i += grid_size)
+       {
+         int j;
+         for (j = 0; j < bitmap_h; j += grid_size)
+           XDrawRectangle (dpy, d, gc,
+                           xoff+i+half2, yoff+j+half2,
+                           grid_size-border-1, grid_size-border-1);
+       }
+
+      XSetForeground(dpy, gc, fg);
       for (i = 0; i <= bitmap_w; i += grid_size)
-       XFillRectangle (dpy, d, gc, xoff+i-border/2, yoff, border, bitmap_h);
+       XFillRectangle (dpy, d, gc, xoff+i-half, yoff, border, bitmap_h);
       for (i = 0; i <= bitmap_h; i += grid_size)
-       XFillRectangle (dpy, d, gc, xoff, yoff+i-border/2, bitmap_w, border);
+       XFillRectangle (dpy, d, gc, xoff, yoff+i-half, bitmap_w, border);
     }
 
   if (xoff)
@@ -101,8 +203,8 @@ init_slide (Display *dpy, Window window)
       XFillRectangle (dpy, d, gc, 0, bitmap_h - yoff, bitmap_w, yoff);
     }
 
-  XSync (dpy, True);
-  if (delay2) usleep (delay2 * 2);
+  XSync (dpy, False);
+  if (delay2) usleep (delay2);
  for (i = 0; i < grid_size; i += pix_inc)
    {
      XPoint points [3];
@@ -132,7 +234,7 @@ init_slide (Display *dpy, Window window)
      points[2].y = points[1].y;
      XFillPolygon (dpy, window, gc, points, 3, Convex, CoordModeOrigin);
 
-     XSync (dpy, True);
+     XSync (dpy, False);
      if (delay) usleep (delay);
    }
 
@@ -140,42 +242,40 @@ init_slide (Display *dpy, Window window)
                  xoff + grid_size * hole_x,
                  yoff + grid_size * hole_y,
                  grid_size, grid_size);
+
+  XSync (dpy, False);
+  if (delay2) usleep (delay2);
 }
 
 static void
 slide1 (Display *dpy, Window window)
 {
   /* this code is a total kludge, but who cares, it works... */
- int i, x, y, ix, iy, dx, dy, dir, w, h, size, inc;
+ int rnd, i, x, y, ix, iy, dx, dy, dir, w, h, size, inc;
  static int last = -1;
- do {
-   dir = random () % 4;
-   switch (dir)
-     {
-     case 0: dx = 0,  dy = 1;  break;
-     case 1: dx = -1, dy = 0;  break;
-     case 2: dx = 0,  dy = -1; break;
-     case 3: dx = 1,  dy = 0;  break;
-     default: abort ();
-     }
- } while (dir == last ||
-         hole_x + dx < 0 || hole_x + dx >= grid_w ||
-         hole_y + dy < 0 || hole_y + dy >= grid_h);
- if (grid_w > 1 && grid_h > 1)
-   last = (dir == 0 ? 2 : dir == 2 ? 0 : dir == 1 ? 3 : 1);
 
- switch (dir)
-   {
-   case 0: size = 1 + (random()%(grid_h - hole_y - 1)); h = size; w = 1; break;
-   case 1: size = 1 + (random()%hole_x);               w = size; h = 1; break;
-   case 2: size = 1 + (random()%hole_y);               h = size; w = 1; break;
-   case 3: size = 1 + (random()%(grid_w - hole_x - 1)); w = size; h = 1; break;
-   default: abort ();
-   }
-
- if (dx == -1) hole_x -= (size - 1);
- else if (dy == -1) hole_y -= (size - 1);
+ if (last == -1) last = random () % 2;
 
+/* alternate between horizontal and vertical slides */
+/* note that dir specifies the direction the _hole_ moves, not the tiles */
+ if (last == VERTICAL) {
+   if ((rnd = random () % (grid_w - 1)) < hole_x) {
+     dx = -1; dir = LEFT;  hole_x -= rnd;
+   } else {
+     dx =  1; dir = RIGHT; rnd -= hole_x;
+   }
+   dy = 0; w = size = rnd + 1; h = 1;
+   last = HORIZONTAL;
+ } else {
+   if ((rnd = random () % (grid_h - 1)) < hole_y) {
+     dy = -1; dir = UP;    hole_y -= rnd;
+   } else {
+     dy =  1; dir = DOWN;  rnd -= hole_y;
+   }
+   dx = 0; h = size = rnd + 1; w = 1;
+   last = VERTICAL;
+ }
  ix = x = xoff + (hole_x + dx) * grid_size;
  iy = y = yoff + (hole_y + dy) * grid_size;
  inc = pix_inc;
@@ -201,27 +301,27 @@ slide1 (Display *dpy, Window window)
      y -= dy * inc;
      switch (dir)
        {
-       case 0: XFillRectangle (dpy, window, gc,
+       case DOWN: XFillRectangle (dpy, window, gc,
                               ix, y + grid_size * h, grid_size * w, iy - y);
         break;
-       case 1: XFillRectangle (dpy, window, gc, ix, iy, x - ix, grid_size * h);
+       case LEFT: XFillRectangle (dpy, window, gc, ix, iy, x - ix, grid_size * h);
         break;
-       case 2: XFillRectangle (dpy, window, gc, ix, iy, grid_size * w, y - iy);
+       case UP: XFillRectangle (dpy, window, gc, ix, iy, grid_size * w, y - iy);
         break;
-       case 3: XFillRectangle (dpy, window, gc,
+       case RIGHT: XFillRectangle (dpy, window, gc,
                               x + grid_size * w, iy, ix - x, grid_size * h);
         break;
        }
 
-     XSync (dpy, True);
+     XSync (dpy, False);
      if (delay) usleep (delay);
    }
  switch (dir)
    {
-   case 0: hole_y += size; break;
-   case 1: hole_x--; break;
-   case 2: hole_y--; break;
-   case 3: hole_x += size; break;
+   case DOWN: hole_y += size; break;
+   case LEFT: hole_x--; break;
+   case UP: hole_y--; break;
+   case RIGHT: hole_x += size; break;
    }
 }
 
@@ -235,10 +335,11 @@ char *defaults [] = {
   "*visualID:                  Best",
 #endif
 
-  "*background:                        Black",
+  ".background:                        Black",
+  ".foreground:                        Gray",
   "*gridSize:                  70",
   "*pixelIncrement:            10",
-  "*internalBorderWidth:       1",
+  "*internalBorderWidth:       4",
   "*delay:                     50000",
   "*delay2:                    1000000",
   0
@@ -260,6 +361,7 @@ screenhack (Display *dpy, Window window)
   while (1)
     {
       slide1 (dpy, window);
+      screenhack_handle_events (dpy);
       if (delay2) usleep (delay2);
     }
 }