ftp://ftp.swin.edu.au/slackware/slackware-9.1/source/xap/xscreensaver/xscreensaver...
[xscreensaver] / driver / xscreensaver-getimage.c
index 599c50cd4d10e5cab70dd98ca47c21ddeb4e1011..b0ce3fa20ce7933eeec677160c949e61828bcff5 100644 (file)
 #include "colorbars.h"
 #include "visual.h"
 #include "prefs.h"
+#include "version.h"
 #include "vroot.h"
 
+#ifndef _XSCREENSAVER_VROOT_H_
+# error Error!  You have an old version of vroot.h!  Check -I args.
+#endif /* _XSCREENSAVER_VROOT_H_ */
+
 #ifdef HAVE_GDK_PIXBUF
 # undef HAVE_JPEGLIB
 # ifdef HAVE_GTK2
 #endif
 
 
+#ifdef __GNUC__
+ __extension__     /* shut up about "string length is greater than the length
+                      ISO C89 compilers are required to support" when including
+                      the .ad file... */
+#endif
+
 static char *defaults[] = {
 #include "../driver/XScreenSaver_ad.h"
  0
@@ -88,8 +99,17 @@ blurb (void)
 static int
 x_ehandler (Display *dpy, XErrorEvent *error)
 {
-  fprintf (stderr, "\nX error in %s:\n", progname);
-  XmuPrintDefaultErrorMessage (dpy, error, stderr);
+  if (error->error_code == BadWindow || error->error_code == BadDrawable)
+    {
+      fprintf (stderr, "%s: target %s 0x%lx unexpectedly deleted\n", progname,
+               (error->error_code == BadWindow ? "window" : "pixmap"),
+               (unsigned long) error->resourceid);
+    }
+  else
+    {
+      fprintf (stderr, "\nX error in %s:\n", progname);
+      XmuPrintDefaultErrorMessage (dpy, error, stderr);
+    }
   exit (-1);
   return 0;
 }
@@ -128,6 +148,35 @@ drawable_window_p (Display *dpy, Drawable d)
 }
 
 
+/* Returns true if the window is the root window, or a virtual root window,
+   but *not* the xscreensaver window.  That is, if it's a "real" desktop
+   root window of some kind.
+ */
+static Bool
+root_window_p (Screen *screen, Window window)
+{
+  Display *dpy = DisplayOfScreen (screen);
+  Atom type;
+  int format;
+  unsigned long nitems, bytesafter;
+  char *version;
+
+  if (window != RootWindowOfScreen (screen))
+    return False;
+
+  if (XGetWindowProperty (dpy, window,
+                         XInternAtom (dpy, "_SCREENSAVER_VERSION", False),
+                         0, 1, False, XA_STRING,
+                         &type, &format, &nitems, &bytesafter,
+                         (unsigned char **) &version)
+      == Success
+      && type != None)
+    return False;
+
+  return True;
+}
+
+
 /* Clear the window or pixmap to black, or its background color.
  */
 static void
@@ -183,7 +232,10 @@ compute_image_scaling (int src_w, int src_h,
       int th = src_h * r;
       int pct = (r * 100);
 
+#if 0
+      /* this optimization breaks things */
       if (pct < 95 || pct > 105)  /* don't scale if it's close */
+#endif
         {
           if (verbose_p)
             fprintf (stderr, "%s: scaling image by %d%% (%dx%d -> %dx%d)\n",
@@ -228,20 +280,18 @@ read_file_gdk (Screen *screen, Window window, Drawable drawable,
 {
   GdkPixbuf *pb;
   Display *dpy = DisplayOfScreen (screen);
-  unsigned int win_width, win_height;
+  unsigned int win_width, win_height, win_depth;
 # ifdef HAVE_GTK2
   GError *gerr = 0;
 # endif /* HAVE_GTK2 */
 
+  /* Find the size of the Drawable. */
   {
     Window root;
     int x, y;
-    unsigned int bw, d;
-    XWindowAttributes xgwa;
-    XGetWindowAttributes (dpy, window, &xgwa);
-    screen = xgwa.screen;
+    unsigned int bw;
     XGetGeometry (dpy, drawable,
-                  &root, &x, &y, &win_width, &win_height, &bw, &d);
+                  &root, &x, &y, &win_width, &win_height, &bw, &win_depth);
   }
 
   gdk_pixbuf_xlib_init (dpy, screen_number (screen));
@@ -271,6 +321,7 @@ read_file_gdk (Screen *screen, Window window, Drawable drawable,
       int w = gdk_pixbuf_get_width (pb);
       int h = gdk_pixbuf_get_height (pb);
       int srcx, srcy, destx, desty, w2, h2;
+      Bool bg_p = False;
 
       compute_image_scaling (w, h, win_width, win_height, verbose_p,
                              &srcx, &srcy, &destx, &desty, &w2, &h2);
@@ -289,7 +340,25 @@ read_file_gdk (Screen *screen, Window window, Drawable drawable,
             fprintf (stderr, "%s: out of memory when scaling?\n", progname);
         }
 
-      clear_drawable (screen, drawable);
+      /* If we're rendering onto the root window (and it's not the
+         xscreensaver pseudo-root) then put the image in the window's
+         background.  Otherwise, just paint the image onto the window.
+       */
+      bg_p = (window == drawable && root_window_p (screen, window));
+
+      if (bg_p)
+        {
+          XGCValues gcv;
+          GC gc;
+          drawable = XCreatePixmap (dpy, window,
+                                    win_width, win_height, win_depth);
+          gcv.foreground = BlackPixelOfScreen (screen);
+          gc = XCreateGC (dpy, drawable, GCForeground, &gcv);
+          XFillRectangle (dpy, drawable, gc, 0, 0, win_width, win_height);
+          XFreeGC (dpy, gc);
+        }
+      else
+        clear_drawable (screen, drawable);
 
       /* #### Note that this always uses the default colormap!  Morons!
          Owen says that in Gnome 2.0, I should try using
@@ -302,9 +371,14 @@ read_file_gdk (Screen *screen, Window window, Drawable drawable,
                                                 GDK_PIXBUF_ALPHA_FULL, 127,
                                                 XLIB_RGB_DITHER_NORMAL,
                                                 0, 0);
-      XSync (dpy, False);
+      if (bg_p)
+        {
+          XSetWindowBackgroundPixmap (dpy, window, drawable);
+          XClearWindow (dpy, window);
+        }
     }
 
+  XSync (dpy, False);
   return True;
 }
 
@@ -574,8 +648,7 @@ maybe_read_ppm (Screen *screen, Visual *visual,
   ximage = XCreateImage (dpy, visual, depth, ZPixmap, 0, 0,
                          w, h, 8, 0);
   if (ximage)
-    ximage->data = (unsigned char *)
-      calloc (ximage->height, ximage->bytes_per_line);
+    ximage->data = (char *) calloc (ximage->height, ximage->bytes_per_line);
   if (!ximage || !ximage->data)
     {
       fprintf (stderr, "%s: out of memory loading %dx%d PPM file %s\n",
@@ -721,8 +794,7 @@ read_jpeg_ximage (Screen *screen, Visual *visual, Drawable drawable,
                          cinfo.output_width, cinfo.output_height,
                          8, 0);
   if (ximage)
-    ximage->data = (unsigned char *)
-      calloc (ximage->height, ximage->bytes_per_line);
+    ximage->data = (char *) calloc (ximage->height, ximage->bytes_per_line);
 
   if (ximage && ximage->data)
     scanbuf = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE,
@@ -813,8 +885,7 @@ scale_ximage (Screen *screen, Visual *visual,
   XImage *ximage2 = XCreateImage (dpy, visual, depth,
                                   ZPixmap, 0, 0,
                                   new_width, new_height, 8, 0);
-  ximage2->data = (unsigned char *)
-    calloc (ximage2->height, ximage2->bytes_per_line);
+  ximage2->data = (char *) calloc (ximage2->height, ximage2->bytes_per_line);
 
   if (!ximage2->data)
     {
@@ -866,17 +937,15 @@ read_file_jpeglib (Screen *screen, Window window, Drawable drawable,
   unsigned int win_width, win_height, win_depth;
   int srcx, srcy, destx, desty, w2, h2;
 
+  /* Find the size of the Drawable, and the Visual/Colormap of the Window. */
   {
     Window root;
     int x, y;
     unsigned int bw;
     XWindowAttributes xgwa;
-
     XGetWindowAttributes (dpy, window, &xgwa);
-    screen = xgwa.screen;
     visual = xgwa.visual;
     cmap = xgwa.colormap;
-
     XGetGeometry (dpy, drawable,
                   &root, &x, &y, &win_width, &win_height, &bw, &win_depth);
   }
@@ -918,13 +987,34 @@ read_file_jpeglib (Screen *screen, Window window, Drawable drawable,
 
   /* Finally, put the resized image on the window.
    */
-  clear_drawable (screen, drawable);
   {
     GC gc;
     XGCValues gcv;
-    gc = XCreateGC (dpy, drawable, 0, &gcv);
-    XPutImage (dpy, drawable, gc, ximage,
-               srcx, srcy, destx, desty, ximage->width, ximage->height);
+
+    /* If we're rendering onto the root window (and it's not the xscreensaver
+       pseudo-root) then put the image in the window's background.  Otherwise,
+       just paint the image onto the window.
+     */
+    if (window == drawable && root_window_p (screen, window))
+      {
+        Pixmap bg = XCreatePixmap (dpy, window,
+                                   win_width, win_height, win_depth);
+        gcv.foreground = BlackPixelOfScreen (screen);
+        gc = XCreateGC (dpy, drawable, GCForeground, &gcv);
+        XFillRectangle (dpy, bg, gc, 0, 0, win_width, win_height);
+        XPutImage (dpy, bg, gc, ximage,
+                   srcx, srcy, destx, desty, ximage->width, ximage->height);
+        XSetWindowBackgroundPixmap (dpy, window, bg);
+        XClearWindow (dpy, window);
+      }
+    else
+      {
+        gc = XCreateGC (dpy, drawable, 0, &gcv);
+        clear_drawable (screen, drawable);
+        XPutImage (dpy, drawable, gc, ximage,
+                   srcx, srcy, destx, desty, ximage->width, ximage->height);
+      }
+
     XFreeGC (dpy, gc);
   }
 
@@ -1154,6 +1244,13 @@ get_image (Screen *screen,
       exit (1);
     }
 
+  /* Make sure the Screen and the Window correspond. */
+  {
+    XWindowAttributes xgwa;
+    XGetWindowAttributes (dpy, window, &xgwa);
+    screen = xgwa.screen;
+  }
+
   if (file && stat (file, &st))
     {
       fprintf (stderr, "%s: file \"%s\" does not exist\n", progname, file);
@@ -1207,7 +1304,6 @@ get_image (Screen *screen,
 
   /* We can grab desktop images if:
        - the window is the real root window;
-       - the window is the virtal root window;
        - the window is a toplevel window.
      We cannot grab desktop images if:
        - the window is a non-top-level window.
@@ -1331,7 +1427,9 @@ mapper (XrmDatabase *db, XrmBindingList bindings, XrmQuarkList quarks,
 
 #define USAGE "usage: %s [ -options... ] window-id [pixmap-id]\n"            \
    "\n"                                                                              \
-   "    This program puts an image on the given window or pixmap.\n"         \
+   "    %s\n"                                                                \
+   "\n"                                                                              \
+   "    %s puts an image on the given window or pixmap.\n"                   \
    "\n"                                                                              \
    "    It is used by those xscreensaver demos that operate on images.\n"     \
    "    The image may be a file loaded from disk, a frame grabbed from\n"     \
@@ -1362,6 +1460,7 @@ main (int argc, char **argv)
   Screen *screen;
   char *oprogname = progname;
   char *file = 0;
+  char version[255];
 
   Window window = (Window) 0;
   Drawable drawable = (Drawable) 0;
@@ -1382,6 +1481,20 @@ main (int argc, char **argv)
 #  error Error!  This file definitely needs vroot.h!
 # endif
 
+  /* Get the version number, for error messages. */
+  {
+    char *v = (char *) strdup(strchr(screensaver_id, ' '));
+    char *s1, *s2, *s3, *s4;
+    s1 = (char *) strchr(v,  ' '); s1++;
+    s2 = (char *) strchr(s1, ' ');
+    s3 = (char *) strchr(v,  '('); s3++;
+    s4 = (char *) strchr(s3, ')');
+    *s2 = 0;
+    *s4 = 0;
+    sprintf (version, "Part of XScreenSaver %s -- %s.", s1, s3);
+    free(v);
+  }
+
   /* We must read exactly the same resources as xscreensaver.
      That means we must have both the same progclass *and* progname,
      at least as far as the resource database is concerned.  So,
@@ -1441,10 +1554,10 @@ main (int argc, char **argv)
               goto LOSE;
             }
           window_str = argv[i];
-          window = (Window) RootWindowOfScreen (screen);
+          window = VirtualRootWindowOfScreen (screen);
         }
       else if ((1 == sscanf (argv[i], " 0x%lx %c", &w, &dummy) ||
-                1 == sscanf (argv[i], " %ld %c",   &w, &dummy)) &&
+                1 == sscanf (argv[i], " %lu %c",   &w, &dummy)) &&
                w != 0)
         {
           if (drawable)
@@ -1473,7 +1586,12 @@ main (int argc, char **argv)
             fprintf (stderr, "\n%s: unparsable window/pixmap ID: \"%s\"\n",
                      progname, argv[i]);
         LOSE:
-          fprintf (stderr, USAGE, progname);
+# ifdef __GNUC__
+          __extension__   /* don't warn about "string length is greater than
+                             the length ISO C89 compilers are required to
+                             support" in the usage string... */
+# endif
+          fprintf (stderr, USAGE, progname, version, progname);
           exit (1);
         }
     }