http://ftp.x.org/contrib/applications/xscreensaver-2.24.tar.gz
[xscreensaver] / utils / grabscreen.c
index 1dba4328d509e4b7a4539d8b037381028b480ae2..6bf8cc8b848bdd8e6edd5ce57025a8642a6b44bb 100644 (file)
@@ -1,4 +1,4 @@
-/* xscreensaver, Copyright (c) 1992, 1993, 1994, 1997
+/* xscreensaver, Copyright (c) 1992, 1993, 1994, 1997, 1998
  *  Jamie Zawinski <jwz@netscape.com>
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
@@ -18,6 +18,7 @@
  */
 
 #include "utils.h"
+#include "yarandom.h"
 
 #include <X11/Xatom.h>
 #include <X11/Xutil.h>
@@ -33,6 +34,9 @@
 #include "usleep.h"
 #include "colors.h"
 #include "grabscreen.h"
+#include "sgivideo.h"
+#include "visual.h"
+#include "resources.h"
 
 #include "vroot.h"
 #undef RootWindowOfScreen
@@ -41,7 +45,6 @@
 
 
 #ifdef HAVE_READ_DISPLAY_EXTENSION
-# include "visual.h"
 # include <X11/extensions/readdisplay.h>
   static Bool read_display (Screen *, Window, Pixmap, Bool);
 #endif /* HAVE_READ_DISPLAY_EXTENSION */
 
 static void copy_default_colormap_contents (Screen *, Colormap, Visual *);
 
+#if defined(HAVE_READ_DISPLAY_EXTENSION) || defined(HAVE_SGI_VIDEO)
+static void make_cubic_colormap (Screen *, Window, Visual *);
+#endif
+
 
 static Bool
 MapNotify_event_p (Display *dpy, XEvent *event, XPointer window)
@@ -131,6 +138,25 @@ BadWindow_ehandler (Display *dpy, XErrorEvent *error)
 }
 
 
+/* XCopyArea seems not to work right on SGI O2s if you draw in SubwindowMode
+   on a window whose depth is not the maximal depth of the screen?  Or
+   something.  Anyway, things don't work unless we: use SubwindowMode for
+   the real root window (or a legitimate virtual root window); but do not
+   use SubwindowMode for the xscreensaver window.  I make no attempt to
+   explain.
+ */
+Bool
+use_subwindow_mode_p(Screen *screen, Window window)
+{
+  if (window != VirtualRootWindowOfScreen(screen))
+    return False;
+  else if (xscreensaver_window_p(DisplayOfScreen(screen), window))
+    return False;
+  else
+    return True;
+}
+
+
 /* Install the colormaps of all visible windows, deepest first.
    This should leave the colormaps of the topmost windows installed
    (if only N colormaps can be installed at a time, then only the
@@ -174,8 +200,8 @@ install_screen_colormaps (Screen *screen)
 }
 
 
-void
-grab_screen_image (Screen *screen, Window window)
+static void
+grab_screen_image_1 (Screen *screen, Window window)
 {
   Display *dpy = DisplayOfScreen (screen);
   XWindowAttributes xgwa;
@@ -196,10 +222,18 @@ grab_screen_image (Screen *screen, Window window)
 
   if (!root_p)
     {
+      double unmap = 0;
       if (saver_p)
-       unmap_time = 2500000;  /* 2 1/2 seconds */
+       {
+         unmap = get_float_resource("grabRootDelay", "Seconds");
+         if (unmap <= 0.00001 || unmap > 20) unmap = 2.5;
+       }
       else
-       unmap_time =  660000;  /* 2/3rd second */
+       {
+         unmap = get_float_resource("grabWindowDelay", "Seconds");
+         if (unmap <= 0.00001 || unmap > 20) unmap = 0.66;
+       }
+      unmap_time = unmap * 100000;
     }
 
 #ifdef DEBUG
@@ -211,7 +245,8 @@ grab_screen_image (Screen *screen, Window window)
     XWindowAttributes xgwa2;
     XGetWindowAttributes (dpy, window, &xgwa2);
     fprintf(stderr, "%s: ", progname);
-    describe_visual(stderr, screen, xgwa2.visual);
+    describe_visual(stderr, screen, xgwa2.visual, ####);
+    fprintf (stderr, "\n");
   }
 #endif /* DEBUG */
 
@@ -293,6 +328,42 @@ grab_screen_image (Screen *screen, Window window)
   XSync (dpy, True);
 }
 
+void
+grab_screen_image (Screen *screen, Window window)
+{
+#ifdef HAVE_SGI_VIDEO
+  char c, *s = get_string_resource("grabVideoProbability", "Float");
+  double prob = -1;
+  if (!s ||
+      (1 != sscanf (s, " %lf %c", &prob, &c)) ||
+      prob < 0 ||
+      prob > 1)
+    prob = 0.5;
+
+  if ((random() % 100) < ((int) (100 * prob)))
+    {
+      XWindowAttributes xgwa;
+      Display *dpy = DisplayOfScreen (screen);
+      XGetWindowAttributes (dpy, window, &xgwa);
+# ifdef DEBUG
+      fprintf(stderr, "%s: trying to grab from video...\n", progname);
+# endif /* DEBUG */
+      if (grab_video_frame (screen, xgwa.visual, window))
+       {
+         if (xgwa.depth < 24)
+           {
+             int class = visual_class (screen, xgwa.visual);
+             if (class == PseudoColor || class == DirectColor)
+               make_cubic_colormap (screen, window, xgwa.visual);
+           }
+         return;
+       }
+    }
+#endif /* HAVE_SGI_VIDEO */
+
+  grab_screen_image_1 (screen, window);
+}
+
 
 /* When we are grabbing and manipulating a screen image, it's important that
    we use the same colormap it originally had.  So, if the screensaver was
@@ -345,7 +416,35 @@ copy_default_colormap_contents (Screen *screen,
 
   got_cells = max_cells;
   allocate_writable_colors (dpy, to_cmap, pixels, &got_cells);
-  XStoreColors (dpy, to_cmap, old_colors, got_cells);
+
+#ifdef DEBUG
+  if (got_cells != max_cells)
+    fprintf(stderr, "%s: got only %d of %d cells\n", progname,
+           got_cells, max_cells);
+#endif /* DEBUG */
+
+  if (got_cells <= 0)                                   /* we're screwed */
+    ;
+  else if (got_cells == max_cells &&                    /* we're golden */
+          from_cells == to_cells)
+    XStoreColors (dpy, to_cmap, old_colors, got_cells);
+  else                                                  /* try to cope... */
+    {
+      for (i = 0; i < got_cells; i++)
+       {
+         XColor *c = old_colors + i;
+         int j;
+         for (j = 0; j < got_cells; j++)
+           if (pixels[j] == c->pixel)
+             {
+               /* only store this color value if this is one of the pixels
+                  we were able to allocate. */
+               XStoreColors (dpy, to_cmap, c, 1);
+               break;
+             }
+       }
+    }
+
 
 #ifdef DEBUG
   fprintf(stderr, "%s: installing copy of default colormap\n", progname);
@@ -368,8 +467,6 @@ copy_default_colormap_contents (Screen *screen,
 
 #ifdef HAVE_READ_DISPLAY_EXTENSION
 
-static void make_cubic_colormap (Screen *, Window, Visual *);
-
 static Bool
 read_display (Screen *screen, Window window, Pixmap into_pixmap,
              Bool dont_wait)
@@ -426,13 +523,23 @@ read_display (Screen *screen, Window window, Pixmap into_pixmap,
       return False;
     }
 
-  /* Uh, this can't be right, can it?  But it's necessary.  X sucks.
-     If the visual is of depth 24, but the image came back as depth 32,
-     hack it to be 24 lest we get a BadMatch from XPutImage.  (I presume
-     I'm expected to look at the server's pixmap formats or some such
-     nonsense... but fuck it.
+  /* XReadDisplay tends to LIE about the depth of the image it read.
+     It is returning an XImage which has `depth' and `bits_per_pixel'
+     confused!
+
+     That is, on a 24-bit display, where all visuals claim depth 24, and
+     where XGetImage would return an XImage with depth 24, and where
+     XPutImage will get a BadMatch with images that are not depth 24,
+     XReadDisplay is returning images with depth 32!  Fuckwits!
+
+     So if the visual is of depth 24, but the image came back as depth 32,
+     hack it to be 24 lest we get a BadMatch from XPutImage.
+
+     I wonder what happens on an 8-bit SGI...  Probably it still returns
+     an image claiming depth 32?  Certainly it can't be 8.  So, let's just
+     smash it to 32...
    */
-  if (xgwa.depth == 24 && image->depth == 32)
+  if (image->depth == 32 /* && xgwa.depth == 24 */ )
     image->depth = 24;
 
   /* If the visual of the window/pixmap into which we're going to draw is
@@ -532,7 +639,14 @@ read_display (Screen *screen, Window window, Pixmap into_pixmap,
 
   return True;
 }
+#endif /* HAVE_READ_DISPLAY_EXTENSION */
+
+
+#if defined(HAVE_READ_DISPLAY_EXTENSION) || defined(HAVE_SGI_VIDEO)
 
+/* Makes and installs a colormap that makes a PseudoColor or DirectColor
+   visual behave like a TrueColor visual of the same depth.
+ */
 static void
 make_cubic_colormap (Screen *screen, Window window, Visual *visual)
 {
@@ -606,5 +720,4 @@ make_cubic_colormap (Screen *screen, Window window, Visual *visual)
   XInstallColormap (dpy, cmap);
 }
 
-
-#endif /* HAVE_READ_DISPLAY_EXTENSION */
+#endif /* HAVE_READ_DISPLAY_EXTENSION || HAVE_SGI_VIDEO */