diff options
Diffstat (limited to 'driver/xscreensaver-getimage.c')
-rw-r--r-- | driver/xscreensaver-getimage.c | 2000 |
1 files changed, 0 insertions, 2000 deletions
diff --git a/driver/xscreensaver-getimage.c b/driver/xscreensaver-getimage.c deleted file mode 100644 index 092540d..0000000 --- a/driver/xscreensaver-getimage.c +++ /dev/null @@ -1,2000 +0,0 @@ -/* xscreensaver, Copyright (c) 2001-2018 by 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 - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation. No representations are made about the suitability of this - * software for any purpose. It is provided "as is" without express or - * implied warranty. - */ - -/* xscreensaver-getimage -- helper program that puts a random image - onto the given window or pixmap. That image is either a screen-grab, - a file loaded from disk, or a frame grabbed from the system's video - input. - */ - -#include "utils.h" - -#include <X11/Intrinsic.h> -#include <ctype.h> -#include <errno.h> -#include <sys/stat.h> -#include <sys/time.h> - -#ifdef HAVE_SYS_WAIT_H -# include <sys/wait.h> /* for waitpid() and associated macros */ -#endif - -#ifdef HAVE_XMU -# ifndef VMS -# include <X11/Xmu/Error.h> -# else /* VMS */ -# include <Xmu/Error.h> -# endif -#else -# include "xmu.h" -#endif - -#include "yarandom.h" -#include "grabscreen.h" -#include "resources.h" -#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 -# include <gdk-pixbuf-xlib/gdk-pixbuf-xlib.h> -# else /* !HAVE_GTK2 */ -# include <gdk-pixbuf/gdk-pixbuf-xlib.h> -# endif /* !HAVE_GTK2 */ -#endif /* HAVE_GDK_PIXBUF */ - -#ifdef HAVE_JPEGLIB -# undef HAVE_GDK_PIXBUF -# include <jpeglib.h> -#endif - - -#ifdef __APPLE__ - /* On MacOS under X11, the usual X11 mechanism of getting a screen shot - doesn't work, and we need to use an external program. This is only - used when running under X11 on MacOS. If it's a Cocoa build, this - path is not taken, and OSX/grabclient-osx.m is used instead. - */ -# define USE_EXTERNAL_SCREEN_GRABBER -#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 -}; - - - -char *progname = 0; -char *progclass = "XScreenSaver"; -XrmDatabase db; -XtAppContext app; - -extern void grabscreen_verbose (void); - -typedef enum { - GRAB_DESK, GRAB_VIDEO, GRAB_FILE, GRAB_BARS -} grab_type; - - -#define GETIMAGE_VIDEO_PROGRAM "xscreensaver-getimage-video" -#define GETIMAGE_FILE_PROGRAM "xscreensaver-getimage-file" -#define GETIMAGE_SCREEN_PROGRAM "xscreensaver-getimage-desktop" - -extern const char *blurb (void); - -const char * -blurb (void) -{ - return progname; -} - - -static int -x_ehandler (Display *dpy, XErrorEvent *error) -{ - 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; -} - - -static Bool error_handler_hit_p = False; - -static int -ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error) -{ - error_handler_hit_p = True; - return 0; -} - -#ifndef USE_EXTERNAL_SCREEN_GRABBER -static int -ignore_badmatch_ehandler (Display *dpy, XErrorEvent *error) -{ - if (error->error_code == BadMatch) - return ignore_all_errors_ehandler (dpy, error); - else - return x_ehandler (dpy, error); -} -#endif /* ! USE_EXTERNAL_SCREEN_GRABBER */ - - -/* Returns True if the given Drawable is a Window; False if it's a Pixmap. - */ -static Bool -drawable_window_p (Display *dpy, Drawable d) -{ - XErrorHandler old_handler; - XWindowAttributes xgwa; - - XSync (dpy, False); - old_handler = XSetErrorHandler (ignore_all_errors_ehandler); - error_handler_hit_p = False; - XGetWindowAttributes (dpy, d, &xgwa); - XSync (dpy, False); - XSetErrorHandler (old_handler); - XSync (dpy, False); - - if (!error_handler_hit_p) - return True; /* It's a Window. */ - else - return False; /* It's a Pixmap, or an invalid ID. */ -} - - -/* 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; - unsigned 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, - &version) - == Success - && type != None) - return False; - - return True; -} - - -/* Clear the window or pixmap to black, or its background color. - */ -static void -clear_drawable (Screen *screen, Drawable drawable) -{ - Display *dpy = DisplayOfScreen (screen); - XGCValues gcv; - GC gc; - Window root; - int x, y; - unsigned int w, h, bw, d; - XGetGeometry (dpy, drawable, &root, &x, &y, &w, &h, &bw, &d); - - /* The window might have no-op background of None, so to clear it, - draw a black rectangle first, then do XClearWindow (in case the - actual background color is non-black...) */ - - /* #### really we should allocate "black" instead, but I'm lazy... */ - gcv.foreground = BlackPixelOfScreen (screen); - gc = XCreateGC (dpy, drawable, GCForeground, &gcv); - XFillRectangle (dpy, drawable, gc, 0, 0, w, h); - XFreeGC (dpy, gc); - if (drawable_window_p (dpy, drawable)) - XClearWindow (dpy, (Window) drawable); - XFlush (dpy); -} - - -/* Figure out what kind of scaling/positioning we ought to do to display - a src-sized image in a dest-sized window/pixmap. Returns the width - and height to which the image should be scaled, and the position where - it should be displayed to center it. - */ -static void -compute_image_scaling (int src_w, int src_h, - int dest_w, int dest_h, - Bool verbose_p, - int *scaled_from_x_ret, int *scaled_from_y_ret, - int *scaled_to_x_ret, int *scaled_to_y_ret, - int *scaled_w_ret, int *scaled_h_ret) -{ - int srcx, srcy, destx, desty; - - Bool exact_fit_p = ((src_w == dest_w && src_h <= dest_h) || - (src_h == dest_h && src_w <= dest_w)); - - if (!exact_fit_p) /* scale the image up or down */ - { - float rw = (float) dest_w / src_w; - float rh = (float) dest_h / src_h; - float r = (rw < rh ? rw : rh); - int tw, th, pct; - - /* If the window is a goofy aspect ratio, take a middle slice of - the image instead. */ - if (dest_w > dest_h * 5 || dest_h > dest_w * 5) - { - double r2 = (dest_w > dest_h - ? dest_w / (double) dest_h - : dest_h / (double) dest_w); - r *= r2; - if (verbose_p) - fprintf (stderr, "%s: weird aspect: scaling by %.1f\n", - progname, r2); - } - - tw = src_w * r; - th = src_h * r; - 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", - progname, pct, src_w, src_h, tw, th); - src_w = tw; - src_h = th; - } - } - - /* Center the image on the window/pixmap. */ - srcx = 0; - srcy = 0; - destx = (dest_w - src_w) / 2; - desty = (dest_h - src_h) / 2; - if (destx < 0) srcx = -destx, destx = 0; - if (desty < 0) srcy = -desty, desty = 0; - - /* if (dest_w < src_w) src_w = dest_w; - if (dest_h < src_h) src_h = dest_h; */ - - *scaled_w_ret = src_w; - *scaled_h_ret = src_h; - *scaled_from_x_ret = srcx; - *scaled_from_y_ret = srcy; - *scaled_to_x_ret = destx; - *scaled_to_y_ret = desty; - - if (verbose_p) - fprintf (stderr, "%s: displaying %dx%d+%d+%d image at %d,%d in %dx%d.\n", - progname, src_w, src_h, srcx, srcy, destx, desty, dest_w, dest_h); -} - - -static void -colorbars (Screen *screen, Visual *visual, Drawable drawable, Colormap cmap) -{ - Pixmap mask = 0; - unsigned long *pixels; /* ignored - unfreed */ - int npixels; - Pixmap logo = xscreensaver_logo (screen, visual, drawable, cmap, - BlackPixelOfScreen (screen), - &pixels, &npixels, &mask, True); - draw_colorbars (screen, visual, drawable, cmap, 0, 0, 0, 0, logo, mask); - XFreePixmap (DisplayOfScreen (screen), logo); - XFreePixmap (DisplayOfScreen (screen), mask); -} - - -/* Scales an XImage, modifying it in place. - This doesn't do dithering or smoothing, so it might have artifacts. - If out of memory, returns False, and the XImage will have been - destroyed and freed. - */ -#if !defined(USE_EXTERNAL_SCREEN_GRABBER) || defined(HAVE_JPEGLIB) -static Bool -scale_ximage (Screen *screen, Visual *visual, - XImage *ximage, int new_width, int new_height) -{ - Display *dpy = DisplayOfScreen (screen); - int depth = visual_depth (screen, visual); - int x, y; - double xscale, yscale; - - XImage *ximage2 = XCreateImage (dpy, visual, depth, - ZPixmap, 0, 0, - new_width, new_height, 8, 0); - ximage2->data = (char *) calloc (ximage2->height, ximage2->bytes_per_line); - - if (!ximage2->data) - { - fprintf (stderr, "%s: out of memory scaling %dx%d image to %dx%d\n", - progname, - ximage->width, ximage->height, - ximage2->width, ximage2->height); - if (ximage->data) free (ximage->data); - if (ximage2->data) free (ximage2->data); - ximage->data = 0; - ximage2->data = 0; - XDestroyImage (ximage); - XDestroyImage (ximage2); - return False; - } - - /* Brute force scaling... */ - xscale = (double) ximage->width / ximage2->width; - yscale = (double) ximage->height / ximage2->height; - for (y = 0; y < ximage2->height; y++) - for (x = 0; x < ximage2->width; x++) - XPutPixel (ximage2, x, y, - XGetPixel (ximage, x * xscale, y * yscale)); - - free (ximage->data); - ximage->data = 0; - - (*ximage) = (*ximage2); - - ximage2->data = 0; - XDestroyImage (ximage2); - - return True; -} -#endif /* !USE_EXTERNAL_SCREEN_GRABBER || HAVE_JPEGLIB */ - - -#ifdef HAVE_GDK_PIXBUF - -/* Reads the given image file and renders it on the Drawable, using GDK. - Returns False if it fails. - */ -static Bool -read_file_gdk (Screen *screen, Window window, Drawable drawable, - const char *filename, Bool verbose_p, - XRectangle *geom_ret) -{ - GdkPixbuf *pb; - Display *dpy = DisplayOfScreen (screen); - 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; - XGetGeometry (dpy, drawable, - &root, &x, &y, &win_width, &win_height, &bw, &win_depth); - } - - gdk_pixbuf_xlib_init_with_depth (dpy, screen_number (screen), win_depth); -# ifdef HAVE_GTK2 -# if !GLIB_CHECK_VERSION(2, 36 ,0) - g_type_init(); -# endif -# else /* !HAVE_GTK2 */ - xlib_rgb_init (dpy, screen); -# endif /* !HAVE_GTK2 */ - - pb = gdk_pixbuf_new_from_file (filename -# ifdef HAVE_GTK2 - , &gerr -# endif /* HAVE_GTK2 */ - ); - - if (!pb) - { - fprintf (stderr, "%s: unable to load \"%s\"\n", progname, filename); -# ifdef HAVE_GTK2 - if (gerr && gerr->message && *gerr->message) - fprintf (stderr, "%s: reason: %s\n", progname, gerr->message); -# endif /* HAVE_GTK2 */ - return False; - } - else - { - 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; - -# ifdef HAVE_GDK_PIXBUF_APPLY_EMBEDDED_ORIENTATION - { - int ow = w, oh = h; - GdkPixbuf *opb = pb; - pb = gdk_pixbuf_apply_embedded_orientation (opb); - g_object_unref (opb); - w = gdk_pixbuf_get_width (pb); - h = gdk_pixbuf_get_height (pb); - if (verbose_p && (w != ow || h != oh)) - fprintf (stderr, "%s: rotated %dx%d to %dx%d\n", - progname, ow, oh, w, h); - } -# endif - - compute_image_scaling (w, h, win_width, win_height, verbose_p, - &srcx, &srcy, &destx, &desty, &w2, &h2); - if (w != w2 || h != h2) - { - GdkPixbuf *pb2 = gdk_pixbuf_scale_simple (pb, w2, h2, - GDK_INTERP_BILINEAR); - if (pb2) - { - g_object_unref (pb); - pb = pb2; - w = w2; - h = h2; - } - else - fprintf (stderr, "%s: out of memory when scaling?\n", progname); - } - - /* 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 - gdk_pixbuf_render_pixmap_and_mask_for_colormap() instead. - But I haven't tried. - */ - if (srcx > 0) w -= srcx; - if (srcy > 0) h -= srcy; - gdk_pixbuf_xlib_render_to_drawable_alpha (pb, drawable, - srcx, srcy, destx, desty, - w, h, - GDK_PIXBUF_ALPHA_FULL, 127, - XLIB_RGB_DITHER_NORMAL, - 0, 0); - if (bg_p) - { - XSetWindowBackgroundPixmap (dpy, window, drawable); - XClearWindow (dpy, window); - } - - if (geom_ret) - { - geom_ret->x = destx; - geom_ret->y = desty; - geom_ret->width = w; - geom_ret->height = h; - } - } - - XSync (dpy, False); - return True; -} - -#endif /* HAVE_GDK_PIXBUF */ - - - -#ifdef HAVE_JPEGLIB - -/* Allocates a colormap that makes a PseudoColor or DirectColor - visual behave like a TrueColor visual of the same depth. - - #### Duplicated in utils/grabscreen.c - */ -static void -allocate_cubic_colormap (Screen *screen, Visual *visual, Colormap cmap, - Bool verbose_p) -{ - Display *dpy = DisplayOfScreen (screen); - int nr, ng, nb, cells; - int r, g, b; - int depth; - XColor colors[4097]; - int i; - - depth = visual_depth (screen, visual); - - switch (depth) - { - case 8: nr = 3; ng = 3; nb = 2; cells = 256; break; - case 12: nr = 4; ng = 4; nb = 4; cells = 4096; break; - default: abort(); break; - } - - memset(colors, 0, sizeof(colors)); - for (r = 0; r < (1 << nr); r++) - for (g = 0; g < (1 << ng); g++) - for (b = 0; b < (1 << nb); b++) - { - i = (r | (g << nr) | (b << (nr + ng))); - colors[i].pixel = i; - colors[i].flags = DoRed|DoGreen|DoBlue; - if (depth == 8) - { - colors[i].red = ((r << 13) | (r << 10) | (r << 7) | - (r << 4) | (r << 1)); - colors[i].green = ((g << 13) | (g << 10) | (g << 7) | - (g << 4) | (g << 1)); - colors[i].blue = ((b << 14) | (b << 12) | (b << 10) | - (b << 8) | (b << 6) | (b << 4) | - (b << 2) | b); - } - else - { - colors[i].red = (r << 12) | (r << 8) | (r << 4) | r; - colors[i].green = (g << 12) | (g << 8) | (g << 4) | g; - colors[i].blue = (b << 12) | (b << 8) | (b << 4) | b; - } - } - - { - int j; - int allocated = 0; - int interleave = cells / 8; /* skip around, rather than allocating in - order, so that we get better coverage if - we can't allocated all of them. */ - for (j = 0; j < interleave; j++) - for (i = 0; i < cells; i += interleave) - if (XAllocColor (dpy, cmap, &colors[i + j])) - allocated++; - - if (verbose_p) - fprintf (stderr, "%s: allocated %d of %d colors for cubic map\n", - progname, allocated, cells); - } -} - -/* Find the pixel index that is closest to the given color - (using linear distance in RGB space -- which is far from the best way.) - - #### Duplicated in utils/grabscreen.c - */ -static unsigned long -find_closest_pixel (XColor *colors, int ncolors, - unsigned long r, unsigned long g, unsigned long b) -{ - unsigned long distance = ~0; - int i, found = 0; - - if (ncolors == 0) - abort(); - for (i = 0; i < ncolors; i++) - { - unsigned long d; - int rd, gd, bd; - - rd = r - colors[i].red; - gd = g - colors[i].green; - bd = b - colors[i].blue; - if (rd < 0) rd = -rd; - if (gd < 0) gd = -gd; - if (bd < 0) bd = -bd; - d = (rd << 1) + (gd << 2) + bd; - - if (d < distance) - { - distance = d; - found = i; - if (distance == 0) - break; - } - } - - return found; -} - - -/* Given an XImage with 8-bit or 12-bit RGB data, convert it to be - displayable with the given X colormap. The farther from a perfect - color cube the contents of the colormap are, the lossier the - transformation will be. No dithering is done. - - #### Duplicated in utils/grabscreen.c - */ -static void -remap_image (Screen *screen, Colormap cmap, XImage *image, Bool verbose_p) -{ - Display *dpy = DisplayOfScreen (screen); - unsigned long map[4097]; - int x, y, i; - int cells; - XColor colors[4097]; - - if (image->depth == 8) - cells = 256; - else if (image->depth == 12) - cells = 4096; - else - abort(); - - memset(map, -1, sizeof(*map)); - memset(colors, -1, sizeof(*colors)); - - for (i = 0; i < cells; i++) - colors[i].pixel = i; - XQueryColors (dpy, cmap, colors, cells); - - if (verbose_p) - fprintf(stderr, "%s: building color cube for %d bit image\n", - progname, image->depth); - - for (i = 0; i < cells; i++) - { - unsigned short r, g, b; - - if (cells == 256) - { - /* "RRR GGG BB" In an 8 bit map. Convert that to - "RRR RRR RR" "GGG GGG GG" "BB BB BB BB" to give - an even spread. */ - r = (i & 0x07); - g = (i & 0x38) >> 3; - b = (i & 0xC0) >> 6; - - r = ((r << 13) | (r << 10) | (r << 7) | (r << 4) | (r << 1)); - g = ((g << 13) | (g << 10) | (g << 7) | (g << 4) | (g << 1)); - b = ((b << 14) | (b << 12) | (b << 10) | (b << 8) | - (b << 6) | (b << 4) | (b << 2) | b); - } - else - { - /* "RRRR GGGG BBBB" In a 12 bit map. Convert that to - "RRRR RRRR" "GGGG GGGG" "BBBB BBBB" to give an even - spread. */ - r = (i & 0x00F); - g = (i & 0x0F0) >> 4; - b = (i & 0xF00) >> 8; - - r = (r << 12) | (r << 8) | (r << 4) | r; - g = (g << 12) | (g << 8) | (g << 4) | g; - b = (b << 12) | (b << 8) | (b << 4) | b; - } - - map[i] = find_closest_pixel (colors, cells, r, g, b); - } - - if (verbose_p) - fprintf(stderr, "%s: remapping colors in %d bit image\n", - progname, image->depth); - - for (y = 0; y < image->height; y++) - for (x = 0; x < image->width; x++) - { - unsigned long pixel = XGetPixel(image, x, y); - if (pixel >= cells) abort(); - XPutPixel(image, x, y, map[pixel]); - } -} - - -/* If the file has a PPM (P6) on it, read it and return an XImage. - Otherwise, rewind the fd back to the beginning, and return 0. - */ -static XImage * -maybe_read_ppm (Screen *screen, Visual *visual, - const char *filename, FILE *in, Bool verbose_p) -{ - Display *dpy = DisplayOfScreen (screen); - int depth = visual_depth (screen, visual); - struct stat st; - char *buf = 0; - int bufsiz = 0; - char *s, dummy; - int i, j; - int x, y, w, h, maxval; - XImage *ximage = 0; - - if (fstat (fileno (in), &st)) - goto FAIL; - - bufsiz = st.st_size; - buf = (char *) malloc (bufsiz + 1); - if (!buf) - { - fprintf (stderr, "%s: out of memory loading %d byte PPM file %s\n", - progname, bufsiz, filename); - goto FAIL; - } - - if (! (s = fgets (buf, bufsiz, in))) /* line 1 */ - goto FAIL; - - if (!strncmp (buf, "\107\111", 2)) - { - fprintf (stderr, "%s: %s: sorry, GIF files not supported" - " when compiled with JPEGlib instead of GDK_Pixbuf.\n", - progname, filename); - goto FAIL; - } - else if (!strncmp (buf, "\211\120", 2)) - { - fprintf (stderr, "%s: %s: sorry, PNG files not supported" - " when compiled with JPEGlib instead of GDK_Pixbuf.\n", - progname, filename); - goto FAIL; - } - - if (strncmp (s, "P6", 2)) - goto FAIL; - - if (! (s = fgets (buf, bufsiz, in))) /* line 2 */ - goto FAIL; - if (2 != sscanf (s, " %d %d %c", &w, &h, &dummy)) - { - fprintf (stderr, "%s: %s: invalid PPM (line 2)\n", progname, filename); - goto FAIL; - } - - if (! (s = fgets (buf, bufsiz, in))) /* line 3 */ - goto FAIL; - if (1 != sscanf (s, " %d %c", &maxval, &dummy)) - { - fprintf (stderr, "%s: %s: invalid PPM (line 3)\n", progname, filename); - goto FAIL; - } - if (maxval != 255) - { - fprintf (stderr, "%s: %s: unparsable PPM: maxval is %d\n", - progname, filename, maxval); - goto FAIL; - } - - ximage = XCreateImage (dpy, visual, depth, ZPixmap, 0, 0, - w, h, 8, 0); - if (ximage) - 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", - progname, ximage->width, ximage->height, filename); - goto FAIL; - } - - s = buf; - j = bufsiz; - while ((i = fread (s, 1, j, in)) > 0) - s += i, j -= i; - - i = 0; - for (y = 0; y < ximage->height; y++) - for (x = 0; x < ximage->width; x++) - { - unsigned char r = buf[i++]; - unsigned char g = buf[i++]; - unsigned char b = buf[i++]; - unsigned long pixel; - - if (depth > 16) - pixel = (r << 16) | (g << 8) | b; - else if (depth == 8) - pixel = ((r >> 5) | ((g >> 5) << 3) | ((b >> 6) << 6)); - else if (depth == 12) - pixel = ((r >> 4) | ((g >> 4) << 4) | ((b >> 4) << 8)); - else if (depth == 16 || depth == 15) - pixel = (((r >> 3) << 10) | ((g >> 3) << 5) | ((b >> 3))); - else - abort(); - - XPutPixel (ximage, x, y, pixel); - } - - free (buf); - return ximage; - - FAIL: - if (buf) free (buf); - if (ximage && ximage->data) - { - free (ximage->data); - ximage->data = 0; - } - if (ximage) XDestroyImage (ximage); - fseek (in, 0, SEEK_SET); - return 0; -} - - -typedef struct { - struct jpeg_error_mgr pub; /* this is what passes for subclassing in C */ - const char *filename; - Screen *screen; - Visual *visual; - Drawable drawable; - Colormap cmap; -} getimg_jpg_error_mgr; - - -static void -jpg_output_message (j_common_ptr cinfo) -{ - getimg_jpg_error_mgr *err = (getimg_jpg_error_mgr *) cinfo->err; - char buf[JMSG_LENGTH_MAX]; - cinfo->err->format_message (cinfo, buf); - fprintf (stderr, "%s: %s: %s\n", progname, err->filename, buf); -} - - -static void -jpg_error_exit (j_common_ptr cinfo) -{ - getimg_jpg_error_mgr *err = (getimg_jpg_error_mgr *) cinfo->err; - cinfo->err->output_message (cinfo); - colorbars (err->screen, err->visual, err->drawable, err->cmap); - XSync (DisplayOfScreen (err->screen), False); - exit (1); -} - - -/* Reads a JPEG file, returns an RGB XImage of it. - */ -static XImage * -read_jpeg_ximage (Screen *screen, Visual *visual, Drawable drawable, - Colormap cmap, const char *filename, Bool verbose_p) -{ - Display *dpy = DisplayOfScreen (screen); - int depth = visual_depth (screen, visual); - - FILE *in = 0; - XImage *ximage = 0; - struct jpeg_decompress_struct cinfo; - getimg_jpg_error_mgr jerr; - JSAMPARRAY scanbuf = 0; - int y; - - jerr.filename = filename; - jerr.screen = screen; - jerr.visual = visual; - jerr.drawable = drawable; - jerr.cmap = cmap; - - if (! (depth >= 15 || depth == 12 || depth == 8)) - { - fprintf (stderr, "%s: unsupported depth: %d\n", progname, depth); - goto FAIL; - } - - in = fopen (filename, "rb"); - if (!in) - { - fprintf (stderr, "%s: %s: unreadable\n", progname, filename); - goto FAIL; - } - - /* Check to see if it's a PPM, and if so, read that instead of using - the JPEG library. Yeah, this is all modular and stuff. - */ - if ((ximage = maybe_read_ppm (screen, visual, filename, in, verbose_p))) - { - fclose (in); - return ximage; - } - - cinfo.err = jpeg_std_error (&jerr.pub); - jerr.pub.output_message = jpg_output_message; - jerr.pub.error_exit = jpg_error_exit; - - jpeg_create_decompress (&cinfo); - jpeg_stdio_src (&cinfo, in); - jpeg_read_header (&cinfo, TRUE); - - /* set some decode parameters */ - cinfo.out_color_space = JCS_RGB; - cinfo.quantize_colors = FALSE; - - jpeg_start_decompress (&cinfo); - - ximage = XCreateImage (dpy, visual, depth, ZPixmap, 0, 0, - cinfo.output_width, cinfo.output_height, - 8, 0); - if (ximage) - 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, - cinfo.rec_outbuf_height * - cinfo.output_width * - cinfo.output_components, - 1); - if (!ximage || !ximage->data || !scanbuf) - { - fprintf (stderr, "%s: out of memory loading %dx%d file %s\n", - progname, ximage->width, ximage->height, filename); - goto FAIL; - } - - y = 0; - while (cinfo.output_scanline < cinfo.output_height) - { - int n = jpeg_read_scanlines (&cinfo, scanbuf, 1); - int i; - for (i = 0; i < n; i++) - { - int x; - for (x = 0; x < ximage->width; x++) - { - int j = x * cinfo.output_components; - unsigned char r = scanbuf[i][j]; - unsigned char g = scanbuf[i][j+1]; - unsigned char b = scanbuf[i][j+2]; - unsigned long pixel; - - if (depth > 16) - pixel = (r << 16) | (g << 8) | b; - else if (depth == 8) - pixel = ((r >> 5) | ((g >> 5) << 3) | ((b >> 6) << 6)); - else if (depth == 12) - pixel = ((r >> 4) | ((g >> 4) << 4) | ((b >> 4) << 8)); - else if (depth == 15) - /* Gah! I don't understand why these are in the other - order. */ - pixel = (((r >> 3) << 10) | ((g >> 3) << 5) | ((b >> 3))); - else if (depth == 16) - pixel = (((r >> 3) << 11) | ((g >> 2) << 5) | ((b >> 3))); - else - abort(); - - XPutPixel (ximage, x, y, pixel); - } - y++; - } - } - - if (cinfo.output_scanline < cinfo.output_height) - /* don't goto FAIL -- we might have viewable partial data. */ - jpeg_abort_decompress (&cinfo); - else - jpeg_finish_decompress (&cinfo); - - jpeg_destroy_decompress (&cinfo); - fclose (in); - in = 0; - - return ximage; - - FAIL: - if (in) fclose (in); - if (ximage && ximage->data) - { - free (ximage->data); - ximage->data = 0; - } - if (ximage) XDestroyImage (ximage); - if (scanbuf) free (scanbuf); - return 0; -} - - -/* Reads the given image file and renders it on the Drawable, using JPEG lib. - Returns False if it fails. - */ -static Bool -read_file_jpeglib (Screen *screen, Window window, Drawable drawable, - const char *filename, Bool verbose_p, - XRectangle *geom_ret) -{ - Display *dpy = DisplayOfScreen (screen); - XImage *ximage; - Visual *visual; - int class, depth; - Colormap cmap; - 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); - visual = xgwa.visual; - cmap = xgwa.colormap; - XGetGeometry (dpy, drawable, - &root, &x, &y, &win_width, &win_height, &bw, &win_depth); - } - - /* Make sure we're not on some weirdo visual... - */ - class = visual_class (screen, visual); - depth = visual_depth (screen, visual); - if ((class == PseudoColor || class == DirectColor) && - (depth != 8 && depth != 12)) - { - fprintf (stderr, "%s: Pseudo/DirectColor depth %d unsupported\n", - progname, depth); - return False; - } - - /* Read the file... - */ - ximage = read_jpeg_ximage (screen, visual, drawable, cmap, - filename, verbose_p); - if (!ximage) return False; - - /* Scale it, if necessary... - */ - compute_image_scaling (ximage->width, ximage->height, - win_width, win_height, verbose_p, - &srcx, &srcy, &destx, &desty, &w2, &h2); - if (ximage->width != w2 || ximage->height != h2) - if (! scale_ximage (screen, visual, ximage, w2, h2)) - return False; - - /* Allocate a colormap, if we need to... - */ - if (class == PseudoColor || class == DirectColor) - { - allocate_cubic_colormap (screen, visual, cmap, verbose_p); - remap_image (screen, cmap, ximage, verbose_p); - } - - /* Finally, put the resized image on the window. - */ - { - GC gc; - XGCValues gcv; - - /* 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); - } - - if (geom_ret) - { - geom_ret->x = destx; - geom_ret->y = desty; - geom_ret->width = ximage->width; - geom_ret->height = ximage->height; - } - - free (ximage->data); - ximage->data = 0; - XDestroyImage (ximage); - XSync (dpy, False); - return True; -} - -#endif /* HAVE_JPEGLIB */ - - -/* Reads the given image file and renders it on the Drawable. - Returns False if it fails. - */ -static Bool -display_file (Screen *screen, Window window, Drawable drawable, - const char *filename, Bool verbose_p, - XRectangle *geom_ret) -{ - if (verbose_p) - fprintf (stderr, "%s: loading \"%s\"\n", progname, filename); - -# if defined(HAVE_GDK_PIXBUF) - if (read_file_gdk (screen, window, drawable, filename, verbose_p, geom_ret)) - return True; -# elif defined(HAVE_JPEGLIB) - if (read_file_jpeglib (screen, window, drawable, filename, verbose_p, - geom_ret)) - return True; -# else /* !(HAVE_GDK_PIXBUF || HAVE_JPEGLIB) */ - /* shouldn't get here if we have no image-loading methods available. */ - abort(); -# endif /* !(HAVE_GDK_PIXBUF || HAVE_JPEGLIB) */ - - return False; -} - - -/* Invokes a sub-process and returns its output (presumably, a file to - load.) Free the string when done. 'grab_type' controls which program - to run. Returned pathname may be relative to 'directory', or absolute. - */ -static char * -get_filename_1 (Screen *screen, const char *directory, grab_type type, - Bool verbose_p) -{ - Display *dpy = DisplayOfScreen (screen); - pid_t forked; - int fds [2]; - int in, out; - char buf[10240]; - char *av[20]; - int ac = 0; - - switch (type) - { - case GRAB_FILE: - av[ac++] = GETIMAGE_FILE_PROGRAM; - if (verbose_p) - av[ac++] = "--verbose"; - av[ac++] = "--name"; - av[ac++] = (char *) directory; - break; - - case GRAB_VIDEO: - av[ac++] = GETIMAGE_VIDEO_PROGRAM; - if (verbose_p) - av[ac++] = "--verbose"; - av[ac++] = "--name"; - break; - -# ifdef USE_EXTERNAL_SCREEN_GRABBER - case GRAB_DESK: - av[ac++] = GETIMAGE_SCREEN_PROGRAM; - if (verbose_p) - av[ac++] = "--verbose"; - av[ac++] = "--name"; - break; -# endif - - default: - abort(); - } - av[ac] = 0; - - if (verbose_p) - { - int i; - fprintf (stderr, "%s: executing:", progname); - for (i = 0; i < ac; i++) - fprintf (stderr, " %s", av[i]); - fprintf (stderr, "\n"); - } - - if (pipe (fds)) - { - sprintf (buf, "%s: error creating pipe", progname); - perror (buf); - return 0; - } - - in = fds [0]; - out = fds [1]; - - switch ((int) (forked = fork ())) - { - case -1: - { - sprintf (buf, "%s: couldn't fork", progname); - perror (buf); - return 0; - } - case 0: - { - int stdout_fd = 1; - - close (in); /* don't need this one */ - close (ConnectionNumber (dpy)); /* close display fd */ - - if (dup2 (out, stdout_fd) < 0) /* pipe stdout */ - { - sprintf (buf, "%s: could not dup() a new stdout", progname); - exit (-1); /* exits fork */ - } - - execvp (av[0], av); /* shouldn't return. */ - exit (-1); /* exits fork */ - break; - } - default: - { - struct stat st; - int wait_status = 0; - FILE *f = fdopen (in, "r"); - int L; - char *ret = 0; - - close (out); /* don't need this one */ - *buf = 0; - if (! fgets (buf, sizeof(buf)-1, f)) - *buf = 0; - fclose (f); - - /* Wait for the child to die. */ - waitpid (-1, &wait_status, 0); - - L = strlen (buf); - while (L && buf[L-1] == '\n') - buf[--L] = 0; - - if (!*buf) - return 0; - - ret = strdup (buf); - - if (*ret != '/') - { - /* Program returned path relative to directory. Prepend dir - to buf so that we can properly stat it. */ - strcpy (buf, directory); - if (directory[strlen(directory)-1] != '/') - strcat (buf, "/"); - strcat (buf, ret); - } - - if (stat(buf, &st)) - { - fprintf (stderr, "%s: file does not exist: \"%s\"\n", - progname, buf); - free (ret); - return 0; - } - else - return ret; - } - } - - abort(); -} - - -/* Returns a pathname to an image file. Free the string when you're done. - */ -static char * -get_filename (Screen *screen, const char *directory, Bool verbose_p) -{ - return get_filename_1 (screen, directory, GRAB_FILE, verbose_p); -} - - -/* Grabs a video frame to a file, and returns a pathname to that file. - Delete that file when you are done with it (and free the string.) - */ -static char * -get_video_filename (Screen *screen, Bool verbose_p) -{ - return get_filename_1 (screen, 0, GRAB_VIDEO, verbose_p); -} - -/* Grabs a desktop image to a file, and returns a pathname to that file. - Delete that file when you are done with it (and free the string.) - */ -# ifdef USE_EXTERNAL_SCREEN_GRABBER -static char * -get_desktop_filename (Screen *screen, Bool verbose_p) -{ - return get_filename_1 (screen, 0, GRAB_DESK, verbose_p); -} -#endif /* USE_EXTERNAL_SCREEN_GRABBER */ - - -/* Grabs a video frame, and renders it on the Drawable. - Returns False if it fails; - */ -static Bool -display_video (Screen *screen, Window window, Drawable drawable, - Bool verbose_p, XRectangle *geom_ret) -{ - char *filename = get_video_filename (screen, verbose_p); - Bool status; - - if (!filename) - { - if (verbose_p) - fprintf (stderr, "%s: video grab failed.\n", progname); - return False; - } - - status = display_file (screen, window, drawable, filename, verbose_p, - geom_ret); - - if (unlink (filename)) - { - char buf[512]; - sprintf (buf, "%s: rm %.100s", progname, filename); - perror (buf); - } - else if (verbose_p) - fprintf (stderr, "%s: rm %s\n", progname, filename); - - if (filename) free (filename); - return status; -} - - -/* Grabs a desktop screen shot onto the window and the drawable. - If the window and drawable are not the same size, the image in - the drawable is scaled to fit. - Returns False if it fails. - */ -static Bool -display_desktop (Screen *screen, Window window, Drawable drawable, - Bool verbose_p, XRectangle *geom_ret) -{ -# ifdef USE_EXTERNAL_SCREEN_GRABBER - - Display *dpy = DisplayOfScreen (screen); - Bool top_p = top_level_window_p (screen, window); - char *filename; - Bool status; - - if (top_p) - { - if (verbose_p) - fprintf (stderr, "%s: unmapping 0x%lx.\n", progname, - (unsigned long) window); - XUnmapWindow (dpy, window); - XSync (dpy, False); - } - - filename = get_desktop_filename (screen, verbose_p); - - if (top_p) - { - if (verbose_p) - fprintf (stderr, "%s: mapping 0x%lx.\n", progname, - (unsigned long) window); - XMapRaised (dpy, window); - XSync (dpy, False); - } - - if (!filename) - { - if (verbose_p) - fprintf (stderr, "%s: desktop grab failed.\n", progname); - return False; - } - - status = display_file (screen, window, drawable, filename, verbose_p, - geom_ret); - - if (unlink (filename)) - { - char buf[512]; - sprintf (buf, "%s: rm %.100s", progname, filename); - perror (buf); - } - else if (verbose_p) - fprintf (stderr, "%s: rm %s\n", progname, filename); - - if (filename) free (filename); - return status; - -# else /* !USE_EXTERNAL_SCREEN_GRABBER */ - - Display *dpy = DisplayOfScreen (screen); - XGCValues gcv; - XWindowAttributes xgwa; - Window root; - int px, py; - unsigned int pw, ph, pbw, pd; - int srcx, srcy, destx, desty, w2, h2; - - if (verbose_p) - { - fprintf (stderr, "%s: grabbing desktop image\n", progname); - grabscreen_verbose(); - } - - XGetWindowAttributes (dpy, window, &xgwa); - XGetGeometry (dpy, drawable, &root, &px, &py, &pw, &ph, &pbw, &pd); - - grab_screen_image_internal (screen, window); - - compute_image_scaling (xgwa.width, xgwa.height, - pw, ph, verbose_p, - &srcx, &srcy, &destx, &desty, &w2, &h2); - - if (pw == w2 && ph == h2) /* it fits -- just copy server-side pixmaps */ - { - GC gc = XCreateGC (dpy, drawable, 0, &gcv); - XCopyArea (dpy, window, drawable, gc, - 0, 0, xgwa.width, xgwa.height, 0, 0); - XFreeGC (dpy, gc); - } - else /* size mismatch -- must scale client-side images to fit drawable */ - { - GC gc; - XImage *ximage = 0; - XErrorHandler old_handler; - - XSync (dpy, False); - old_handler = XSetErrorHandler (ignore_badmatch_ehandler); - error_handler_hit_p = False; - - /* This can return BadMatch if the window is not fully on screen. - Trap that error and return color bars in that case. - (Note that this only happens with XGetImage, not with XCopyArea: - yet another totally gratuitous inconsistency in X, thanks.) - */ - ximage = XGetImage (dpy, window, 0, 0, xgwa.width, xgwa.height, - ~0L, ZPixmap); - - XSync (dpy, False); - XSetErrorHandler (old_handler); - XSync (dpy, False); - - if (error_handler_hit_p) - { - ximage = 0; - if (verbose_p) - fprintf (stderr, "%s: BadMatch reading window 0x%x contents!\n", - progname, (unsigned int) window); - } - - if (!ximage || - !scale_ximage (xgwa.screen, xgwa.visual, ximage, w2, h2)) - return False; - - gc = XCreateGC (dpy, drawable, 0, &gcv); - clear_drawable (screen, drawable); - XPutImage (dpy, drawable, gc, ximage, - srcx, srcy, destx, desty, ximage->width, ximage->height); - XDestroyImage (ximage); - XFreeGC (dpy, gc); - } - - if (geom_ret) - { - geom_ret->x = destx; - geom_ret->y = desty; - geom_ret->width = w2; - geom_ret->height = h2; - } - - XSync (dpy, False); - return True; - -# endif /* !USE_EXTERNAL_SCREEN_GRABBER */ -} - - -/* Whether the given Drawable is unreasonably small. - */ -static Bool -drawable_miniscule_p (Display *dpy, Drawable drawable) -{ - Window root; - int xx, yy; - unsigned int bw, d, w = 0, h = 0; - XGetGeometry (dpy, drawable, &root, &xx, &yy, &w, &h, &bw, &d); - return (w < 32 || h < 30); -} - - -/* Grabs an image (from a file, video, or the desktop) and renders it on - the Drawable. If `file' is specified, always use that file. Otherwise, - select randomly, based on the other arguments. - */ -static void -get_image (Screen *screen, - Window window, Drawable drawable, - Bool verbose_p, - Bool desk_p, - Bool video_p, - Bool image_p, - const char *dir, - const char *file) -{ - Display *dpy = DisplayOfScreen (screen); - grab_type which = GRAB_BARS; - struct stat st; - const char *file_prop = 0; - char *absfile = 0; - XRectangle geom = { 0, 0, 0, 0 }; - - if (! drawable_window_p (dpy, window)) - { - fprintf (stderr, "%s: 0x%lx is a pixmap, not a window!\n", - progname, (unsigned long) window); - 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); - file = 0; - } - - if (verbose_p) - { - fprintf (stderr, "%s: grabDesktopImages: %s\n", - progname, desk_p ? "True" : "False"); - fprintf (stderr, "%s: grabVideoFrames: %s\n", - progname, video_p ? "True" : "False"); - fprintf (stderr, "%s: chooseRandomImages: %s\n", - progname, image_p ? "True" : "False"); - fprintf (stderr, "%s: imageDirectory: %s\n", - progname, (file ? file : dir ? dir : "")); - } - -# if !(defined(HAVE_GDK_PIXBUF) || defined(HAVE_JPEGLIB)) - image_p = False; /* can't load images from files... */ -# ifdef USE_EXTERNAL_SCREEN_GRABBER - desk_p = False; /* ...or from desktops grabbed to files. */ -# endif - - if (file) - { - fprintf (stderr, - "%s: image file loading not available at compile-time\n", - progname); - fprintf (stderr, "%s: can't load \"%s\"\n", progname, file); - file = 0; - } -# endif /* !(HAVE_GDK_PIXBUF || HAVE_JPEGLIB) */ - - if (file) - { - desk_p = False; - video_p = False; - image_p = True; - } - else if (!dir || !*dir) - { - if (verbose_p && image_p) - fprintf (stderr, - "%s: no imageDirectory: turning off chooseRandomImages.\n", - progname); - image_p = False; - } - - /* If the target drawable is really small, no good can come of that. - Always do colorbars in that case. - */ - if (drawable_miniscule_p (dpy, drawable)) - { - desk_p = False; - video_p = False; - image_p = False; - } - -# ifndef _VROOT_H_ -# error Error! This file definitely needs vroot.h! -# endif - - /* We can grab desktop images (using the normal X11 method) if: - - the window is the real root window; - - the window is a toplevel window. - We cannot grab desktop images that way if: - - the window is a non-top-level window. - - Under X11 on MacOS, desktops are just like loaded image files. - Under Cocoa on MacOS, this code is not used at all. - */ -# ifndef USE_EXTERNAL_SCREEN_GRABBER - if (desk_p) - { - if (!top_level_window_p (screen, window)) - { - desk_p = False; - if (verbose_p) - fprintf (stderr, - "%s: 0x%x not top-level: turning off grabDesktopImages.\n", - progname, (unsigned int) window); - } - } -# endif /* !USE_EXTERNAL_SCREEN_GRABBER */ - - if (! (desk_p || video_p || image_p)) - which = GRAB_BARS; - else - { - int i = 0; - int n; - /* Loop until we get one that's permitted. - If files or video are permitted, do them more often - than desktop. - - D+V+I: 10% + 45% + 45%. - V+I: 50% + 50% - D+V: 18% + 82% - D+I: 18% + 82% - */ - AGAIN: - n = (random() % 100); - if (++i > 300) abort(); - else if (desk_p && n < 10) which = GRAB_DESK; /* 10% */ - else if (video_p && n < 55) which = GRAB_VIDEO; /* 45% */ - else if (image_p) which = GRAB_FILE; /* 45% */ - else goto AGAIN; - } - - - /* If we're to search a directory to find an image file, do so now. - */ - if (which == GRAB_FILE && !file) - { - file = get_filename (screen, dir, verbose_p); - if (!file) - { - which = GRAB_BARS; - if (verbose_p) - fprintf (stderr, "%s: no image files found.\n", progname); - } - } - - /* Now actually render something. - */ - switch (which) - { - case GRAB_BARS: - { - XWindowAttributes xgwa; - COLORBARS: - if (verbose_p) - fprintf (stderr, "%s: drawing colorbars.\n", progname); - XGetWindowAttributes (dpy, window, &xgwa); - colorbars (screen, xgwa.visual, drawable, xgwa.colormap); - XSync (dpy, False); - if (! file_prop) file_prop = ""; - - } - break; - - case GRAB_DESK: - if (! display_desktop (screen, window, drawable, verbose_p, &geom)) - goto COLORBARS; - file_prop = "desktop"; - break; - - case GRAB_FILE: - if (*file && *file != '/') /* pathname is relative to dir. */ - { - if (absfile) free (absfile); - absfile = malloc (strlen(dir) + strlen(file) + 10); - strcpy (absfile, dir); - if (dir[strlen(dir)-1] != '/') - strcat (absfile, "/"); - strcat (absfile, file); - } - if (! display_file (screen, window, drawable, - (absfile ? absfile : file), - verbose_p, &geom)) - goto COLORBARS; - file_prop = file; - break; - - case GRAB_VIDEO: - if (! display_video (screen, window, drawable, verbose_p, &geom)) - goto COLORBARS; - file_prop = "video"; - break; - - default: - abort(); - break; - } - - { - Atom a = XInternAtom (dpy, XA_XSCREENSAVER_IMAGE_FILENAME, False); - if (file_prop && *file_prop) - { - char *f2 = strdup (file_prop); - - /* Take the extension off of the file name. */ - /* Duplicated in utils/grabclient.c. */ - char *slash = strrchr (f2, '/'); - char *dot = strrchr ((slash ? slash : f2), '.'); - if (dot) *dot = 0; - /* Replace slashes with newlines */ - /* while ((dot = strchr(f2, '/'))) *dot = '\n'; */ - /* Replace slashes with spaces */ - /* while ((dot = strchr(f2, '/'))) *dot = ' '; */ - - XChangeProperty (dpy, window, a, XA_STRING, 8, PropModeReplace, - (unsigned char *) f2, strlen(f2)); - free (f2); - } - else - XDeleteProperty (dpy, window, a); - - a = XInternAtom (dpy, XA_XSCREENSAVER_IMAGE_GEOMETRY, False); - if (geom.width > 0) - { - char gstr[30]; - sprintf (gstr, "%dx%d+%d+%d", geom.width, geom.height, geom.x, geom.y); - XChangeProperty (dpy, window, a, XA_STRING, 8, PropModeReplace, - (unsigned char *) gstr, strlen (gstr)); - } - else - XDeleteProperty (dpy, window, a); - } - - if (absfile) free (absfile); - XSync (dpy, False); -} - - -#ifdef DEBUG -static Bool -mapper (XrmDatabase *db, XrmBindingList bindings, XrmQuarkList quarks, - XrmRepresentation *type, XrmValue *value, XPointer closure) -{ - int i; - for (i = 0; quarks[i]; i++) - { - if (bindings[i] == XrmBindTightly) - fprintf (stderr, (i == 0 ? "" : ".")); - else if (bindings[i] == XrmBindLoosely) - fprintf (stderr, "*"); - else - fprintf (stderr, " ??? "); - fprintf(stderr, "%s", XrmQuarkToString (quarks[i])); - } - - fprintf (stderr, ": %s\n", (char *) value->addr); - - return False; -} -#endif /* DEBUG */ - - -#define USAGE "usage: %s [ -options... ] window-id [pixmap-id]\n" \ - "\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" \ - " the system's video camera, or a screenshot of the desktop,\n" \ - " depending on command-line options or the ~/.xscreensaver file.\n" \ - "\n" \ - " Options include:\n" \ - "\n" \ - " -display host:dpy.screen which display to use\n" \ - " -root draw to the root window\n" \ - " -verbose print diagnostics\n" \ - " -images / -no-images whether to allow image file loading\n" \ - " -video / -no-video whether to allow video grabs\n" \ - " -desktop / -no-desktop whether to allow desktop screen grabs\n"\ - " -directory <path> where to find image files to load\n" \ - " -file <filename> load this image file\n" \ - "\n" \ - " The XScreenSaver Control Panel (xscreensaver-demo) lets you set the\n"\ - " defaults for these options in your ~/.xscreensaver file.\n" \ - "\n" - -int -main (int argc, char **argv) -{ - saver_preferences P; - Widget toplevel; - Display *dpy; - Screen *screen; - char *oprogname = progname; - char *file = 0; - char version[255]; - - Window window = (Window) 0; - Drawable drawable = (Drawable) 0; - const char *window_str = 0; - const char *drawable_str = 0; - char *s; - int i; - - progname = argv[0]; - s = strrchr (progname, '/'); - if (s) progname = s+1; - oprogname = progname; - - /* half-assed way of avoiding buffer-overrun attacks. */ - if (strlen (progname) >= 100) progname[100] = 0; - -# ifndef _VROOT_H_ -# 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, - put "xscreensaver" in argv[0] while initializing Xt. - */ - progname = argv[0] = "xscreensaver"; - - /* allow one dash or two. */ - for (i = 1; i < argc; i++) - if (argv[i][0] == '-' && argv[i][1] == '-') argv[i]++; - - toplevel = XtAppInitialize (&app, progclass, 0, 0, &argc, argv, - defaults, 0, 0); - dpy = XtDisplay (toplevel); - screen = XtScreen (toplevel); - db = XtDatabase (dpy); - XtGetApplicationNameAndClass (dpy, &s, &progclass); - XSetErrorHandler (x_ehandler); - XSync (dpy, False); - - /* Randomize -- only need to do this here because this program - doesn't use the `screenhack.h' or `lockmore.h' APIs. */ -# undef ya_rand_init - ya_rand_init (0); - - memset (&P, 0, sizeof(P)); - P.db = db; - load_init_file (dpy, &P); - - progname = argv[0] = oprogname; - - for (i = 1; i < argc; i++) - { - unsigned long w; - char dummy; - - /* Have to re-process these, or else the .xscreensaver file - has priority over the command line... - */ - if (!strcmp (argv[i], "-v") || !strcmp (argv[i], "-verbose")) - P.verbose_p = True; - else if (!strcmp (argv[i], "-desktop")) P.grab_desktop_p = True; - else if (!strcmp (argv[i], "-no-desktop")) P.grab_desktop_p = False; - else if (!strcmp (argv[i], "-video")) P.grab_video_p = True; - else if (!strcmp (argv[i], "-no-video")) P.grab_video_p = False; - else if (!strcmp (argv[i], "-images")) P.random_image_p = True; - else if (!strcmp (argv[i], "-no-images")) P.random_image_p = False; - else if (!strcmp (argv[i], "-file")) file = argv[++i]; - else if (!strcmp (argv[i], "-directory") || !strcmp (argv[i], "-dir")) - P.image_directory = argv[++i]; - else if (!strcmp (argv[i], "-root") || !strcmp (argv[i], "root")) - { - if (window) - { - fprintf (stderr, "%s: both %s and %s specified?\n", - progname, argv[i], window_str); - goto LOSE; - } - window_str = argv[i]; - window = VirtualRootWindowOfScreen (screen); - } - else if ((1 == sscanf (argv[i], " 0x%lx %c", &w, &dummy) || - 1 == sscanf (argv[i], " %lu %c", &w, &dummy)) && - w != 0) - { - if (drawable) - { - fprintf (stderr, "%s: both %s and %s specified?\n", - progname, drawable_str, argv[i]); - goto LOSE; - } - else if (window) - { - drawable_str = argv[i]; - drawable = (Drawable) w; - } - else - { - window_str = argv[i]; - window = (Window) w; - } - } - else - { - if (argv[i][0] == '-') - fprintf (stderr, "\n%s: unknown option \"%s\"\n", - progname, argv[i]); - else - fprintf (stderr, "\n%s: unparsable window/pixmap ID: \"%s\"\n", - progname, argv[i]); - LOSE: -# 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); - } - } - - if (window == 0) - { - fprintf (stderr, "\n%s: no window ID specified!\n", progname); - goto LOSE; - } - - -#ifdef DEBUG - if (P.verbose_p) /* Print out all the resources we can see. */ - { - XrmName name = { 0 }; - XrmClass class = { 0 }; - int count = 0; - XrmEnumerateDatabase (db, &name, &class, XrmEnumAllLevels, mapper, - (XtPointer) &count); - } -#endif /* DEBUG */ - - if (!window) abort(); - if (!drawable) drawable = window; - - get_image (screen, window, drawable, P.verbose_p, - P.grab_desktop_p, P.grab_video_p, P.random_image_p, - P.image_directory, file); - exit (0); -} |